Projects
-
Site Updates for September
Frequent visitors to the site may have noticed some minor layout changes around here.
I’ve moved my list of projects to the top of the main page. Crucially, it is now mobile friendly as well.
Projects also have tags on them now to distinguish between
apps
(something that may be useful),games
(a full-fledged, playable game) andtoys
(things I made to mess around with). I may add more categories later.On the backend, projects are now a Jekyll
Collection
which in theory gives me more control over how to render them. And, if you reshare any of my posts, they now have improved open graph metadata. -
In Which I Go Down a Complete Rabbithole About Bash Completion
Ever wonder what is actually going on in your shell when you type, for example,
cd ~/myp
, hit<TAB>
, and the shell completes~/myproject
?Neither had I, until recently.
This was supposed to be a post about the next chapter of Efficient Linux at the Command Line, which is about navigating the file system. However, the author dropped in the idea of the bash builtin
complete
in a sidebar, and I might have gone a little off the deep end.In the source code given for writing a custom bash function, the last line added to the user’s config file is:
complete -W "work recipes video beatles" qcd
which would mean if someone typedqcd
followed by two tabs, the terminal would print all the available keys: in this casework
recipes
video
andbeatles
.What is this? What’s going on here?
If you type
complete
by itself, you get a very long list of what looks like nonsense:complete -F _longopt mv complete -F _root_command gksudo complete -F _command nice complete -F _longopt tr complete -F _longopt head ...and so on
This is, it turns out, a list of what completion command is run when you run one of the bash commands at the end of each line. In other words,
complete -F _longopt mv
means, if you typemv <tab><tab>
complete will run the function (-F
)_longopt
._longopt
and the other built in completions are very long bash functions that mostly call other functions, and if you want to spend a lot of your next three-day weekend retracing my steps, you are welcome to it. For the purposes of this post, however, I’ll talk about an overly simplified completion, because I already spent more time on this Labor Day weekend reading about this than I ever imagined I would. -
Leveling Up on the Command Line
I am lucky in that my first exposure to computers was through the command line. I wasn’t a wizard by any sense when I realized that I could type “echo hi” and the computer would ‘talk’ back to me*, but it means that I feel more comfortable in a non-GUI environment than many of my colleagues.
There’s always room for improvement, though. And when I’m not at work, I’m working on a new-to-me Linux laptop. Even with Pop OS installed, let’s be real: There are some things that any Linux GUI just doesn’t do that well, so the command line is still essential.
In that spirit, I bought Efficient Linux at the Command Line.
I’m only on Chapter 3 but am already learning a lot of commands that I hope to burn into muscle memory. Here are a few that I am working on now:
-
Building a Queens clone in React
I have nearly a 50-day streak on Queens, a daily game from the worst social network. The fact that LinkedIn has managed to trick me into visiting daily is not lost on me, but man, it’s a fun game.
I decided that one Queens per day is not enough, and so I’ve built Infinite Queens. The original Queens puzzle, which Infinite Queens is based on, is fairly simple: place eight queens on the chessboard such that no two queens could capture each other. That means no queens in the same horizontal, vertical or diagonal line. LinkedIn’s Queens actually is more complex and, I think, more interesting, but I started with the easier problem: How can I make a puzzle that replicates the O.G. Queens, but is different every time you refresh the page?
Because there are only 96 solutions to Queens, and the majority of them are created by transforming other solutions, I decided that the solutions can be hardcoded. Basically, create hardcoded 2D arrays with the solutions, and at game time, we can choose one at random, then flip or rotate the array to create an alternate game board, then remove all but 2-3 of the starting pieces to give the player something to start with.
At that point, I’m honestly not sure whether the puzzle is “well-formed” – meaning, whether there is only one solution to the given configuration. I suspect there is more than one solution, so the game only checks whether the board is valid, not whether it matches the original configuration.
I started with one board:
-
Learnin' Kubernetes
At work, all teams are being asked to adopt Karpenter, which, as you can tell from the name, is related to Kubernetes.
The adoption is a relatively simple process, thanks to pre-work other teams have done to automate most of the hard stuff. Realistically, I should just have to change a few values in a couple YAML files and be done with it. However, when you’re talking about modifying deployed services, it always pays to be careful.
I felt like what I was being asked to do would be relatively simple if I only understood some of the terminology being used. I mean:
Identify taints to add to provisioned nodes. If a pod doesn’t have a matching toleration for the taint, the effect set by the taint occurs (NoSchedule, PreferNoSchedule, or NoExecute).
Yikes?
So some basic terminology larnin’ is in order. I’m not really a devops girl so I am starting with the true basics. Here are some of my notes. Any mistakes here, however, are fully my own.
Note: I dithered for four days about whether to post this, but then I read Comfortable with the struggle and was reminded that not understanding things is the default mode for software developers. It’s okay that I couldn’t tell you the difference between a Kubernetes pod and a node until this week, although I feel better now that I have learned to tell them apart.
Kubernetes
As explained by its docs, Kubernetes is an “open source system for automating deployment, scaling, and management of containerized applications.” In other words, it manages your apps running in containers: with Kubernetes, you can easily scale an app up or down (increase or decrease the number of pods running your app), handle load balancing, and (for example) automatically reboot a pod if it is failing.
Fun fact because I am a language nerd: Kubernetes comes from kybernetes, the Greek word for “helmsman” (the idea being that if a Docker container is like a shipping container, then the helmsman is the person who steers all those containers around). Know what else can claim kybernetes as a root word? If you guessed cybernetics, you’d be correct: Norbert Wiener claimed he coined the term because he was interested in systems of feedback, and said that ships’ steering engines were “one of the earliest and best-developed forms of feedback mechanisms.” (“Governor” is also derived from kybernetes via Latin. Now that’s cool.)
Karpenter
An add-on for Kubernetes. Its value proposition is “just-in-time nodes.” It is aimed at helping users reduce costs by auto-scaling-down nodes if they are underutilized, or switching to “spot instances” (an AWS product that basically runs your app on ‘spare’ computers), among other things.
Pods / nodes / clusters
A pod is the smallest possible “unit” in Kubernetes - one container, for example. (However, a pod can hold more than one container (: ) A node is the thing that the pods run on, typically a physical server or a virtual machine. All pods need a node to run on, but not all nodes have pods scheduled to them. A cluster is a group of nodes. Typically a service would have a cluster per deploy environment, so one for dev, one for staging, etc. The Kubernetes control plane lives at the cluster level.
Control plane
Just a fancy name for the software that actually orchestrates the containers. The scheduler is an important part of the control plane as it is the software that assigns pods to nodes. It can do this automatically, applying some sensible defaults, but if you work on a big production app you probably want more granular control, hence the next set of terms.
Node affinity
Pods have what’s called
node affinities
which means that they either want to run on a certain node (or a type of a node or a node location), or don’t want to run on a certain node. For example, you might want two services that communicate with each other to be in the same geographic region, to reduce latency. It’s all still electrons, after all. Or, you might want certain pods to only run on nodes with some minimum CPU power, or you might just want to make sure that your app is evenly spread across regions to better protect it from downtime.Taint
Taint
is like the opposite of a node affinity, it says “don’t put this pod on this node.” Unless the node can tolerate the taint…Toleration
A pod that has a toleration matching a node’s taint can still be scheduled on that node.
The syntax for taints and tolerations (in addition to all the new terminology) confused me.
This is the command to apply a taint to a node:
kubectl taint nodes node1 key1=value1:NoSchedule
This means that no pods can be scheduled on (assigned to) a node unless they have a toleration matching
key1=value1
. (I had assumed that this means no pods can be scheduled on that node if their key/value matches, but it is the opposite.)So now that we know (or at least have familiarized ourselves) with this terminology, we can go back to the Karpenter documentation from before:
Identify taints to add to provisioned nodes. If a pod doesn’t have a matching toleration for the taint, the effect set by the taint occurs (NoSchedule, PreferNoSchedule, or NoExecute).
This just means Karpenter can control how nodes are tainted, rather than controlling it through K8s.
In the end, to adopt Karpenter on my service at work, it truly was a pretty easy lift; as I said, other teams did most of the hard work so I just had to update some YAML to tell Karpenter my service’s tolerations and taints. For now, the taint is essentially, “don’t run any pods on this node that don’t belong to my team” and the toleration is “I belong to Rachel’s team,” so it’s not too complicated. But now that it’s set up we can (possibly) come up with some more interesting customizations in the future.
Resources