CI/CD for Kubernetes Applications (Part 1)
So you're ready to automate your application deployment to Kubernetes. You've made the right choice! Let's consider what a pipeline might look like if you are using Kubernetes manifests directly without the use of a tool such as Helm. In other words, you just have some YAML files sitting somewhere that you deploy with using a command like
kubectl apply -f my-deployment.yaml
First, here's an image that you can reference as you read through the following sections.
The Build Stage
For an application that you intend to run in Kubernetes, your build process will have at least two artifacts:
- A container image that you push to a container registry.
- A Kubernetes definition file that describes to Kubernetes what should be deployed. This is your YAML file.
The reason for saving the YAML file(s) to your artifacts is that you have now associated it with a specific build, and thus, a specific container image. This way you won't ever be guessing something like, "How did we deploy the last version and get it working? Was it before or after I made changes to those manifests?"
Before saving your YAML file to artifacts, you will want the pipeline to perform a string replacement. The particular part we are concerned with is the image tag that gets deployed to Kubernetes. The image tag should be set to whatever image gets built and pushed to the container registry.
The Deploy Stage
Now that you have your artifacts and they are associated using image tags, the deploy pipeline will need to be parameterized to know which version of the artifacts you would like to use. Naturally, the parameter will be the image tag that you want to deploy. One strategy I have used in the past for this is creating a
git tag for each build with something like
build/<image-tag>, then using my CI/CD tool of choice to read those git tags and return them in a list that I can select from when manually triggering a deployment.
At this point, the pipeline needs to retrieve the artifact associated with that tag and run
kubectl apply using that YAML resource definition. And you're done!
I have seen the case be made for managing YAML files and application code separately. Ultimately, this creates a huge mess when trying to figure out which versions of the resource definitions go with which versions of the container image. Let's just cut the middleman and be explicit and direct. This is an area where duplication can be extremely beneficial.
Deploying this way will get you started with automation for Kubernetes deployments. And it can be easily expanded in the future. In a later post, we will explore how using Helm can drastically improve the capabilities of this pipeline.