Docker and Kubernetes | Strategies for Running Kubernetes Components with Up-to-Date Docker Images
Problem:
We want to use always latest image from docker hub but since we have the same tag for our deployment description, kubernetes won’t pull newest image from docker hub
TLDR Solution;
Use two tags when you are generating a new image;
- :latest
- :SHA, comes from latest github commit’s unique id
SHA=$(git rev-parse HEAD)docker build -t USERNAME/IMAGE_NAME:latest -t USERNAME/IMAGE_NAME:SHA ./client/Dockerfile ./client
Let’s say we have a kubernetes deployment which was declared like this:
Take a closer look at line 18. This is the place where we’re telling our deployment to use multi-client image. If we don’t specify any specific tag, k8s will automatically use the latest image from the docker hub. Also, if we specify an image tag like “orhanors/multi-client:v2”, k8s won’t use this image if it doesn’t change and without re-generating the deployment file.
How can we solve this issue? If we want to create a CI/CD pipeline for our application, changes should be applied automatically without doing the same steps every time.
Let’s think about how can we solve this issue.
Solution 1:
Delete the pod that runs into deployment. K8s will be aware of the absence of pod and it will try to re-create it. This is a silly solution
Solution 2:
Change the image tag when you’re pushing the new version. After that re-run the command;
kubectl apply -f <config_file>
Solution 3 (Best one):
We can use an imperative command to set the new image to a specific deployment;
kubectl set image <object_type>/<object_name> <container_name> = <new image to use>
But how should we apply this solution exactly?
Let’s think about a basic CI/CD flow. We want to deploy our application on Google Cloud using Travis-CI. And the flow will look like;
I’m not going to explain all steps of this flow. We can focus on the last 4 steps.
In your travis file, create an environment variable called “SHA”. This will be a unique variable that comes from the latest github commit. So it will look like;
env:global:
-SHA=$(git rev-parse HEAD)
After keeping each commit’s unique variable inside of the “SHA” environment variable, you’ll be able to use it when you’re generating your docker images.
docker build -t USERNAME/IMAGE_NAME:latest -t USERNAME/IMAGE_NAME:$SHA ./client/Dockerfile ./client
When you run the below command, it’ll generate two images.
- image tagged as “latest”
2. image tagged with unique github commit SHA
After generating and pushing these two images to your docker hub, you can add this line to your deployment flow (command should be just one line);
kubectl set image deployments/client-deployment client=USERNAME/IMAGE_NAME:$SHA
With this approach, you’ll have your unique images that are ready to use for your k8s deployments.
As a plus, you’ll also have an image for each master commit. If something went wrong with your deployment, you can easily check the committed image and solve the issues.
Conclusion
In this article, I tried to explain one of the best strategies to keep sync with your docker images and kubernetes components. I choose some specific technologies like Travis-CI to make it easy to explain but you can use the same approach on any platform that you want.
Thanks for reading 🤓