An essential step of any CI/CD pipeline is deployment. If the pipeline operates with Docker containers and deploys to K8s clusters then the goal of the deployment step is to deploy a specific Docker image (stored on some container registry) to a specific K8s cluster. Let’s say there is a VM where this deployment step is being performed. There are a couple of things to be done with that VM before it can be used as a deploying-to-kuberenetes machine:
- install kubectl (K8s CLI)
- configure access to K8s clusters where we are going to deploy
Having the VM configured, the deployment step does the following:
# kubeconfig file contains access configuration to all K8s clusters we need # each configuration is called "context" export KUBECONFIG=kubeconfig # switch to "google-cloud-k8s-dev" context (K8s cluster on Google Cloud for Dev) # so all subsequent kubectl commands are applied to that K8s cluster kubectl config use-context google-cloud-k8s-dev # actually deploy by applying k8s-deployment.yaml file # containing instructions on what image should be deployed and how kubectl apply -f k8s-deployment.yaml
In this post I am going to show how we can create a preconfigured Docker container capable of deploying a Docker image to a K8s cluster. So, basically, it is going to work as a function with two parameters: docker image, K8s context. Therefore we are going to create a function in Fn Project basing on this “deployer” container and deploy to K8s just by invoking the function over http.
The deployer container is going to be built from a Dockerfile with the following content:
FROM ubuntu # install kubectl ADD https://storage.googleapis.com/kubernetes-release/release/v1.6.4/bin/linux/amd64/kubectl /usr/local/bin/kubectl ENV HOME=/config RUN chmod +x /usr/local/bin/kubectl RUN export PATH=$PATH:/usr/local/bin # install rpl RUN apt-get update RUN apt-get install rpl -y # copy into container k8s configuration file with access to all K8s clusters COPY kubeconfig kubeconfig # copy into container yaml file template with IMAGE_NAME placeholder # and an instruction on how to deploy the container to K8s cluster COPY k8s-deployment.yaml k8s-deployment.yaml # copy into container a shell script performing the deployment COPY deploy.sh /usr/local/bin/deploy.sh RUN chmod +x /usr/local/bin/deploy.sh ENTRYPOINT ["xargs","/usr/local/bin/deploy.sh"]
It is worth looking at the k8s-deployment.yaml file. It contains IMAGE_NAME placeholder which is going to be replaced with the exact Docker image name while deployment:
apiVersion: extensions/v1beta1 kind: Deployment ... spec: containers: - image: IMAGE_NAME imagePullPolicy: Always ...
The deploy.sh script which is being invoked once the container is started has the following content:
#!/bin/bash # replace IMAGE_NAME placeholder in yaml file with the first shell parameter
rpl IMAGE_NAME $1 k8s-deployment.yaml export KUBECONFIG=kubeconfig # switch to K8s context specified in the second shell parameter kubectl config use-context $2 # deploy to K8s cluster kubectl apply -f k8s-deployment.yaml
So, we are going to build a docker image from the Dockerfile by invoking this docker command:
docker build -t efedorenko/k8sdeployer:1.0 .
Assuming there is Fn Project up and running somewhere (e.g. on K8s cluster as it is described in this post) we can create an Fn application:
fn apps create k8sdeployerapp
Then create a route to the k8sdeployer container:
fn routes create k8sdeployerapp /deploy efedorenko/k8sdeployer:1.0
We have created a function deploying a Docker image to a K8s cluster. This function can be invoked over http like this:
curl http://22.214.171.124:80/r/k8sdeployer -d "google-cloud-k8s-dev efedorenko/happyeaster:latest"
This call will deploy efedorenko/happyeaster:latest Docker image to a K8s cluster on Google Cloud Platform.