21/11/2020 - KUBERNETES
In this example we are going to deploy our application to Kubernetes and rollback to any given revision if something goes wrong with the most recent deployment.
Important: When rolling back to a specific revision, the docker image gets pulled so make sure every image has a unique tag attached to it and referenced in deployment.yaml
for each deployment. Every time you deploy a code, its image tag should be a new one. If you use latest
, you will also have to manually revert the code first, push the image which is not a good practise and beats the purpose of rollback. In short, uniquely tag (e.g. git hash
) the docker image, push it and use same tag in deployment.yaml
file.
A Deployment's revision history is stored in its ReplicaSets.
The optional .spec.revisionHistoryLimit
key controls how many ReplicaSets should be retained for rollback. The more ReplicaSets retained, the more resources in etcd
is consumed so don't keep the numbers too high. By default, 10 old ReplicaSets will be kept.
We have set our revisionHistoryLimit
to 5 so we will never have more than 5 revisions. Let's see what we currently have in the cluster.
$ kubectl get deployments,replicasets,pods
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/address-finder-deployment 1/1 1 1 9m20s
NAME DESIRED CURRENT READY AGE
replicaset.apps/address-finder-deployment-68dd5b79b8 0 0 0 9m
replicaset.apps/address-finder-deployment-56847c949b 0 0 0 3m
replicaset.apps/address-finder-deployment-7f9fdc5f48 1 1 1 17s
NAME READY STATUS RESTARTS AGE
pod/address-finder-deployment-7f9fdc5f48-wr94x 2/2 Running 0 17s
As you can see above we have 3 ReplicaSets. Given that the deployment/release revisions are controlled by ReplicaSets, we should also have 3 revision history. Let's check.
$ kubectl rollout history deployment address-finder-deployment
REVISION CHANGE-CAUSE
1
2
3
Our Pod is a web server so it would print a dummy string such as v1, v2, v3 so on. Currently it prints v3 but we want to go back to v2 message instead. You can assume that the revision belongs to the latest ReplicaSet which is 3 because it is the latest one at the bottom. However, it is not always the case so let's make sure first.
$ kubectl describe replicaset address-finder-deployment-7f9fdc5f48 | grep revision
deployment.kubernetes.io/revision: 3
Now we are sure what revision we are on. Let's go back to previous revision which is 2.
$ kubectl rollout undo deployment address-finder-deployment --to-revision=2
deployment.apps/address-finder-deployment rolled back
Let's see what we currently have in the cluster again.
$ kubectl get deployments,replicasets,pods
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/address-finder-deployment 1/1 1 1 22m
NAME DESIRED CURRENT READY AGE
replicaset.apps/address-finder-deployment-68dd5b79b8 0 0 0 22m
replicaset.apps/address-finder-deployment-56847c949b 1 1 1 15m
replicaset.apps/address-finder-deployment-7f9fdc5f48 0 0 0 13m
NAME READY STATUS RESTARTS AGE
pod/address-finder-deployment-56847c949b-vr99p 2/2 Running 0 14s
As you can see above, current ReplicaSet has changed and Pod is restarted. Let's also check what revision history looks like.
$ kubectl rollout history deployment address-finder-deployment
REVISION CHANGE-CAUSE
1
3
4
Revision 2 is now promoted to 4 which should be the active one. Let's confirm with the current ReplicaSet.
$ kubectl describe replicaset address-finder-deployment-56847c949b | grep revision
deployment.kubernetes.io/revision: 4
deployment.kubernetes.io/revision-history: 2
There it is. It tells us what the current revision is and its rollback history. Our web server should now print v2 message instead of v3.
// Run/restart rollout/deployment
$ kubectl rollout restart deployment address-finder-deployment
// List rollout/deployment history/revisions
$ kubectl rollout history deployment address-finder-deployment
// Rollback to revision
$ kubectl rollout undo deployment address-finder-deployment --to-revision={revision-no}