Kubernetes rolling updates

Note: this tutorial is done with Kubernetes v1.17.2, Docker 19.03.5 on MacOS 0.15.2.

Kubernetes

Kubernetes cluster

Kubernetes core concepts

A very simple server

For demonstration purpose, we write a server which listens at the port 8080 and responses a string “Hello World!” to every request from clients.

// server.js
var http = require('http');

var handleRequest = function(request, response) {
  console.log('Received request for URL: ' + request.url);
  response.writeHead(200);
  response.end('Hello World!');
};
var www = http.createServer(handleRequest);
www.listen(8080);

Then we write a Dockerfile for our containerized application

FROM node:6.14.2
EXPOSE 8080
COPY server.js .
CMD [ "node", "server.js" ]

Requirements

We install minikube and Docker in order to manage Kubernetes clusters. A Kubernetes cluster could be started with the following command minikube start. To ensure that our cluster is operating normally, we should see the following output from minikube status command.

host: Running
kubelet: Running
apiserver: Running
kubeconfig: Configured

Deploy our app

The recommended workflow is uploading a Docker image to a registry, creating a Kubernetes pod, and granting the pod the access to the image. In order to simply the setup of this tutorial, we could apply this solution to let the pod have direct access to the Docker images stored inside a Kubernetes node.

eval $(minikube docker-env)

To deploy our app, we firstly need to build a Docker image

docker build -t myimage:v1 .

We create a Kubernetes Deployment by executing kubectl create deployment myapp --image=myimage:v1

By default, the containerized application only exposes itself to other apps in the same cluster. We create a Kubernetes Service to expose our web app so external users could interact with it.

kubectl expose deployments/myservice --type="NodePort" --port 8080 --name myservice

The following scripts help us to verify whether our app is functioning normally.

export NODE_PORT=$(kubectl get services/myservice -o \
    go-template='{{(index .spec.ports 0).nodePort}}')
export POD_NAME=$(kubectl get pods -o \
    go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}')
# Make a request to the web app
curl $(minikube ip):$NODE_PORT

We should see the response text “Hello World”.

Rolling updates

In order to prepare for our rolling update, we need to scale our app by adding some replicas kubectl scale deployments/myapp --replicas=3. To simply put, these 3 replicas are 3 exact copies of our app. For demonstrating the new update of the app, we simply modify server.js to make the server return a string “Hello World v2!” to every client’s request.

response.end('Hello World v2!');
A new Docker image is built by running

docker build -t myimage:v2 .

After setting the desired image (myimage:v2) kubectl set image deployments/myapp myimage=myimage:v2, we perform the rolling update with the following command

kubectl rollout status deployments/myapp

The expected output of curl $(minikube ip):$NODE_PORT should be “Hello World v2!” by now.

Kubernetes also make it very simple to rollback to the previous version of the app

kubectl rollout undo deployments/myapp

Cleaning up

Finally, we clean up our tutorial by deleting resources (e.g., services, deployments) and stopping minikube.

kubectl delete service myservice
kubectl delete deployment myapp
minikube stop

We should also removing the Docker images if we don’t plan to work with them later on.

References

Comments

comments powered by Disqus