Having fun with Kubernetes deployment

Install deployment

Install nginx 1.12.2 with 2 pods

If you need to have 2 pods from the start then it could be done in three easy steps:

  • Create deployment template with nginx version 1.12.2
  • Edit nginx.yaml to update replicas count.
  • Apply deployment template to Kubernetes cluster
# step 1
kubectl create  deployment nginx --save-config=true --image=nginx:1.12.2 --dry-run=client -o yaml > nginx.yaml
# step 2
edit nginx.yaml
# step 3
kubectl apply --record=true -f nginx.yaml

Notice use of --record=true to save the state of what caused the deployment change

Auto-scaling deployment

Deployments can be scaled manually or automatically. Let’s see how it could be done in few simple commands.

Scaling manually up to 4 pods

kubectl scale deployment nginx --replicas=4 --record=true

Scaling manually down to 2 pods

kubectl scale deployment nginx --replicas=2 --record=true

Automatically scale up and down

Automatically scale up to 4 pods and down to 2 pods based on cpu usage

kubectl autoscale deployment nginx --min=2 --max 4

You can adjust when to scale up/down using --cpu-percent(e.g. --cpu-percent=80) flag

Upgrade deployment

There are several options to perform an upgrade:

  • Update deployment image using kubectl set image command
  • Patch deployment manifest using kubectl patch command
  • Re-apply deployment file using kubectl apply

Advantage of first two options that they perform rollout on the “fly”. As soon as you have new container image ready you can perform upgrade.

Advantage of 3rd command kubectl apply is that it relies on the file on disk. So, new image name have to be updated in the file first. This way you can implement GitOps approach to apply your templates anytime you made a change to git repo.

Upgrade nginx using set image

Update deployment container image with `kubectl set image`

kubectl set image --record=true deployment/nginx nginx=nginx:1.13.8
deployment.apps/nginx image updated
kubectl get pods
NAME                     READY   STATUS              RESTARTS   AGE
nginx-76d56bc6fb-cdrdl   0/1     ContainerCreating   0          3s
nginx-8f4745b9c-4lbwn    1/1     Running             0          5m51s
nginx-8f4745b9c-8rflb    1/1     Running             0          5m51s

Upgrade nginx using patch

Lets patch nginx deployment to the latest version

kubectl patch deployment nginx --type json -p='[{"op":"replace","path":"/spec/template/spec/containers/0/image","value":"nginx:latest"}]'
deployment.apps/nginx patched

Lets check that patch was successful

kubectl get deployments.apps nginx -o json | jq ".spec.template.spec.containers[0].image"
"nginx:latest"

Notice how patch recorded in deployment history

kubectl rollout history deployment nginx
deployment.apps/nginx
REVISION  CHANGE-CAUSE
1         <none>
3         kubectl set image deployment/nginx nginx=nginx:1.14.8 --record=true
4         kubectl set image deployment/nginx nginx=nginx:1.13.8 --record=true
5         kubectl set image deployment/nginx nginx=nginx:1.13.8 --record=true
6         kubectl set image deployment/nginx nginx=nginx:1.13.8 --record=true

Notice that CHANGE-CAUSE field didn’t change to kubectl patch command, because we omit --record=true option during patch, but instead it show previous cause change command. So, keep in mind to always set –record=true to have up-to date “change cause” record.

Lets patch again with record true and see how it will reflect in deployment history

kubectl patch --record=true deployment nginx --type json -p='[{"op":"replace","path":"/spec/template/spec/containers/0/image","value":"nginx:latest"}]

kubectl rollout history deployment nginx 
deployment.apps/nginx 
REVISION  CHANGE-CAUSE
1         <none>
4         kubectl set image deployment/nginx nginx=nginx:1.13.8 --record=true
7         kubectl set image deployment/nginx nginx=nginx:1.14.8 --record=true
10        kubectl patch deployment nginx --record=true --type=json --patch=[{"op":"replace","path":"/spec/template/spec/containers/0/image","value":"nginx:latest"}]

Upgrade nginx using kubectl apply

The most used and straight forward way to upgrade deployment is to use kubectl apply -f filename.yaml command

kubectl apply --record=true -f nginx.yaml

Rollback

Lets make faulty deployment

Set nginx image to 1.14.8 which doesn’t exist in docker repository.

kubectl set image deployment/nginx nginx=nginx:1.14.8 --record

Check upgrade status

kubectl rollout status deployment nginxWaiting for deployment "nginx" rollout to finish: 1 out of 2 new replicas have been updated...

kubectl will wait for deployment to finish before it release the console. Because this nginx image are not exist deployment rollout will never finish and we need to rollback. Press Ctrl+C to stop watching for `kubectl rollout status`

Rollback latest deployment

kubectl rollout undo deployment nginx
deployment.apps/nginx rolled back

Check deployment history again

kubectl rollout history deployment nginx
deployment.apps/nginx 
REVISION  CHANGE-CAUSE
1         <none>
4         kubectl set image deployment/nginx nginx=nginx:1.13.8 --record=true
9         kubectl patch deployment nginx --record=true --type=json --patch=[{"op":"replace","path":"/spec/template/spec/containers/0/image","value":"nginx:1.19.1"}]
11        kubectl set image deployment/nginx nginx=nginx:1.14.8 --record=true
12        kubectl patch deployment nginx --record=true --type=json --patch=[{"op":"replace","path":"/spec/template/spec/containers/0/image","value":"nginx:latest"}]

Notice how revision 10 with patch become revision 12. In that way operator can see that rollback was performed.

References