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.


Revision History Limit


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.


Example


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.


Commands


// 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}