Set node affinity to all pods in a namespace
Tags: kubernetes, go, opensource
Published: 2021-04-12 21:12:39

Recently I had to install a fairly large system on an existing k8s cluster and make sure its pods run only on specific nodes. Initially I thought to myself, the PodNodeAffinity plugin will do that for me easy! The bad news is, that’s not available on GKE (or EKS for that matter) and that's what I was using. I started googling around as I was sure that there must be an alternative for this, but the only thing I managed to find were a few very old, unanswered questions on stack overflow :(
As I have not worked on any open-source projects outside of work in quite a while and really wanted to publish something, that stuck out as a good problem to solve! That's how I ended up creating the [Namespace Node Affinity mutating webhook](https://github.com/idgenchev/namespace-node-affinity).

# Implementation

Using a mutating webhook sounded like a good solution to that problem - just inject the nodeAffinity as pods are created. I wanted to create the easiest possible to use, plug-and-play solution, so I decided to include an init container with the webhook that can create the mutating webhook configuration, the certificate authority and the self-signed certificates. I have not dealt with creating CAs and signing certificates in golang before, but there were some excellent guides around the web such as [this one from Shane Utt](https://shaneutt.com/blog/golang-ca-and-signed-cert-go/) which made it fairly easy to learn and implement :)

Most of the interesting things happen in the `affinityinjector` package, which deals with the `AdmissionReview`s. The `AffinityInjector` reads the k8s object from the admission review request, then reads the configuration for the object's namespace and constructs the admission review response with the patched object.

# Build

I always wanted to try the GitHub actions, but never had the chance before as they never seemed like a good fit for the projects I've been working on recently or I had to stick to some existing build system. Using them for my personal open source project seemed like the perfect chance to try them! Overall I really enjoyed using them and it seems like the marketplace is full of useful tools! The only thing that I found annoying was that there are still some bugs for scenarios that in my opinion come up quite often. For example `workflow_run` is not working at all for tags. Initially I wanted to set up two separate workflows, one to run the tests and another for building the docker images and pushing them to Docker Hub. At the end I ended up combining them and the docker job is just skipped for pull requests now with `if: ${{ github.event_name != 'pull_request' }}`. That worked out great as it seems enough to run the CI/CD only on master, tags and PRs anyway and it seems like a good idea to build and push images to Docker Hub on changes to master and when tags are created. I will definitely continue exploring GitHub actions more and will write up another post to share my findings :)
 
I hope you found that post and the [Namespace Node Affinity tool](https://github.com/idgenchev/namespace-node-affinity) useful!