What is Rollout & Rollback?
A rollout is the process of deploying or distributing a new version of an application.
A rollback is the act of returning to a prior, stable version of the application or deployment. In K8s, this is used to undo a rollout that caused issues, ensuring the application runs a known good version.
When is K8s rollback used?
For following situations, rollback may save to go back to the previous stable state:
- Buggy Release: A new deployment introduces a critical bug causing application crashes.
- Failed Health Checks: The new version fails Kubernetes liveness or readiness probes.
- Increased Latency: Users report slow response times after deployment.
- Database Migration Issues: The new release depends on a database schema change that was not applied.
- Memory/CPU Spikes: The updated application consumes excessive resources, affecting performance.
- Configuration Errors: A misconfigured environment variable in the new version causes failures.
- Unexpected Dependency Conflicts: A library upgrade in the new release breaks compatibility.
- Security Vulnerability: The deployed version introduces a critical security risk that needs immediate rollback.
- Rollback for Canary Deployment: A percentage of users report issues during phased rollout, requiring a revert.
- Auto Scaling Failures: The new version does not handle traffic spikes properly, leading to outages.
Two Hands-on samples for different update strategies:
- Hands-on Sample#1: Rollout with Recreate Strategy
- Hands-on Sample#2: Rollout with RollingUpdate Strategy
Hands-on Sample#1: Rollout with Recreate Strategy
This scenario shows how to roll out deployments with recreate
strategy.
Steps
- Run minikube (in this scenario, K8s runs on WSL2-Ubuntu 20.04) ("minikube start")
user@k8s:$ minikube start
π minikube v1.35.0 on Ubuntu 20.04
β¨ Automatically selected the docker driver
π Using Docker driver with root privileges
π Starting "minikube" primary control-plane node in "minikube" cluster
π Pulling base image v0.0.46 ...
π₯ Creating docker container (CPUs=2, Memory=3100MB) ...
β Failing to connect to https://registry.k8s.io/ from inside the minikube container
π‘ To pull new external images, you may need to configure a proxy: https://minikube.sigs.k8s.io/docs/reference/networking/proxy/
π³ Preparing Kubernetes v1.32.0 on Docker 27.4.1 ...
βͺ Generating certificates and keys ...
βͺ Booting up control plane ...
βͺ Configuring RBAC rules ...
π Configuring bridge CNI (Container Networking Interface) ...
π Verifying Kubernetes components...
βͺ Using image gcr.io/k8s-minikube/storage-provisioner:v5
π Enabled addons: storage-provisioner, default-storageclass
π Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default
- Create Yaml file (
recreate-deployment.yaml
) in your directory and copy the below definition into the file. - File: https://github.com/omerbsezer/Fast-Kubernetes/blob/main/labs/deployment/recreate-deployment.yaml
YAML File Explanation:
-
replicas: 5
=> create 5 replicas -
matchLabels: app: recreate
=> labelselector of deployment: selects pods which have "app:recreate" labels -
strategy: type: Recreate
=> deployment roll up strategy: recreate => Delete all pods firstly and create Pods from scratch. -
labels: app: recreate
=> labels the pod with "app:recreate" -
recreate-deployment.yaml
:
apiVersion: apps/v1
kind: Deployment
metadata:
name: rcdeployment
labels:
team: development
spec:
replicas: 5
selector:
matchLabels:
app: recreate
strategy:
type: Recreate
template:
metadata:
labels:
app: recreate
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
- Run deployment:
kubectl apply -f recreate-deployment.yaml
deployment.apps/rcdeployment created
- Watching pods' status (
kubectl get pods
, orkubectl get pods -o wide
)
user@k8s:$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
rcdeployment-687df9bcb7-gt96n 0/1 ContainerCreating 0 12s <none> minikube <none> <none>
rcdeployment-687df9bcb7-jn4xb 0/1 ContainerCreating 0 12s <none> minikube <none> <none>
rcdeployment-687df9bcb7-pmxfp 0/1 ContainerCreating 0 12s <none> minikube <none> <none>
rcdeployment-687df9bcb7-w9n88 0/1 ContainerCreating 0 12s <none> minikube <none> <none>
rcdeployment-687df9bcb7-z97qn 0/1 ContainerCreating 0 12s <none> minikube <none> <none>
user@k8s:$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
rcdeployment-687df9bcb7-gt96n 1/1 Running 0 76s 10.244.0.3 minikube <none> <none>
rcdeployment-687df9bcb7-jn4xb 1/1 Running 0 76s 10.244.0.6 minikube <none> <none>
rcdeployment-687df9bcb7-pmxfp 1/1 Running 0 76s 10.244.0.5 minikube <none> <none>
rcdeployment-687df9bcb7-w9n88 1/1 Running 0 76s 10.244.0.4 minikube <none> <none>
rcdeployment-687df9bcb7-z97qn 1/1 Running 0 76s 10.244.0.7 minikube <none> <none>
- Watching replica set's status:
user@k8s:$ kubectl get rs
NAME DESIRED CURRENT READY AGE
rcdeployment-687df9bcb7 5 5 0 23s
user@k8s:$ kubectl get rs
NAME DESIRED CURRENT READY AGE
rcdeployment-687df9bcb7 5 5 5 2m41s
- Update image version, after new replicaset and pods are created, old ones are deleted.
user@k8s:$ kubectl set image deployment rcdeployment nginx=httpd
deployment.apps/rcdeployment image updated
- With "recreate" strategy, pods are terminated:
user@k8s:$ kubectl get rs
NAME DESIRED CURRENT READY AGE
rcdeployment-588d5d854c 5 5 0 0s
rcdeployment-687df9bcb7 0 0 0 4m2s
- New pods are creating:
user@k8s:$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
rcdeployment-588d5d854c-42vjj 0/1 ContainerCreating 0 9s <none> minikube <none> <none>
rcdeployment-588d5d854c-8llhg 0/1 ContainerCreating 0 9s <none> minikube <none> <none>
rcdeployment-588d5d854c-dhpzz 0/1 ContainerCreating 0 9s <none> minikube <none> <none>
rcdeployment-588d5d854c-fgvgr 0/1 ContainerCreating 0 9s <none> minikube <none> <none>
rcdeployment-588d5d854c-j4qhv 0/1 ContainerCreating 0 9s <none> minikube <none> <none>
- New replicaset created:
user@k8s:$ kubectl get rs
NAME DESIRED CURRENT READY AGE
rcdeployment-588d5d854c 5 5 5 21s
rcdeployment-687df9bcb7 0 0 0 4m23s
user@k8s:$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
rcdeployment-588d5d854c-42vjj 1/1 Running 0 24s 10.244.0.11 minikube <none> <none>
rcdeployment-588d5d854c-8llhg 1/1 Running 0 24s 10.244.0.10 minikube <none> <none>
rcdeployment-588d5d854c-dhpzz 1/1 Running 0 24s 10.244.0.8 minikube <none> <none>
rcdeployment-588d5d854c-fgvgr 1/1 Running 0 24s 10.244.0.12 minikube <none> <none>
rcdeployment-588d5d854c-j4qhv 1/1 Running 0 24s 10.244.0.9 minikube <none> <none>
- Delete this deployment:
user@k8s:$ kubectl delete -f recreate-deployment.yaml
deployment.apps "rcdeployment" deleted
user@k8s:$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
rcdeployment-588d5d854c-42vjj 0/1 Completed 0 4m53s 10.244.0.11 minikube <none> <none>
rcdeployment-588d5d854c-8llhg 0/1 Completed 0 4m53s 10.244.0.10 minikube <none> <none>
rcdeployment-588d5d854c-dhpzz 0/1 Completed 0 4m53s 10.244.0.8 minikube <none> <none>
rcdeployment-588d5d854c-fgvgr 0/1 Completed 0 4m53s 10.244.0.12 minikube <none> <none>
user@k8s:$ kubectl get pods -o wide
No resources found in default namespace.
Hands-on Sample#2: Rollout with RollingUpdate Strategy
This scenario shows how to roll out deployments with rollingUpdate
strategy.
- Create Yaml file (
rolling-deployment.yaml
) in your directory and copy the below definition into the file. - File: https://github.com/omerbsezer/Fast-Kubernetes/blob/main/labs/deployment/rolling-deployment.yaml
YAML File Explanation:
-
matchLabels: app: rolling
=> labelselector of deployment: selects pods which have "app:rolling" labels -
type: RollingUpdate
=> deployment roll up strategy: rollingUpdate, Pods are updated step by step, all pods are not deleted at the same time. -
maxUnavailable: 2
=> shows the max number of deleted containers. Total:10 container; if maxUnava:2, min:8 containers run in that time period -
maxSurge: 2
=> shows that the max number of containers. Total:10 container; if maxSurge:2, max:12 containers run in a time -
labels: app: rolling
=> labels the pod with "app:rolling" -
rolling-deployment.yaml
:
apiVersion: apps/v1
kind: Deployment
metadata:
name: rolldeployment
labels:
team: development
spec:
replicas: 10
selector:
matchLabels:
app: rolling
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 2
maxSurge: 2
template:
metadata:
labels:
app: rolling
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
- Run deployment:
user@k8s:$ kubectl apply -f rolling-deployment.yaml
deployment.apps/rolldeployment created
- Watching pods' status:
user@k8s:$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
rolldeployment-6b947d555-4bx8h 0/1 ContainerCreating 0 11s <none> minikube <none> <none>
rolldeployment-6b947d555-58xjd 1/1 Running 0 11s 10.244.0.14 minikube <none> <none>
rolldeployment-6b947d555-99rxm 0/1 ContainerCreating 0 11s <none> minikube <none> <none>
rolldeployment-6b947d555-d2sff 0/1 ContainerCreating 0 11s <none> minikube <none> <none>
rolldeployment-6b947d555-f6jx4 1/1 Running 0 11s 10.244.0.13 minikube <none> <none>
rolldeployment-6b947d555-g2ldl 0/1 ContainerCreating 0 11s <none> minikube <none> <none>
rolldeployment-6b947d555-mkzlm 0/1 ContainerCreating 0 11s <none> minikube <none> <none>
rolldeployment-6b947d555-qpt7g 0/1 ContainerCreating 0 11s <none> minikube <none> <none>
rolldeployment-6b947d555-s8cct 0/1 ContainerCreating 0 11s <none> minikube <none> <none>
rolldeployment-6b947d555-zfl8l 1/1 Running 0 11s 10.244.0.15 minikube <none> <none>
- Watching replica set's status:
user@k8s:$ kubectl get rs
NAME DESIRED CURRENT READY AGE
rolldeployment-6b947d555 10 10 10 82s
- Run edit command, it opens vim editor to edit:
user@k8s:$ kubectl edit deployment rolldeployment --record
- Find image definition, press
i
for insert mode, change tohttpd
instead ofnginx
, pressESC
, press:wq
to save and exit (by default opening withvi
text editor app)
strategy:
rollingUpdate:
maxSurge: 2
maxUnavailable: 2
type: RollingUpdate
template:
metadata:
creationTimestamp: null
labels:
app: rolling
spec:
containers:
- image: nginx # <= update with different image with httpd
imagePullPolicy: Always
name: nginx
ports:
- containerPort: 80
protocol: TCP
- New pods are creating with new version:
user@k8s:$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
rolldeployment-6b947d555-4bx8h 1/1 Running 0 4m42s 10.244.0.22 minikube <none> <none>
rolldeployment-6b947d555-58xjd 1/1 Running 0 4m42s 10.244.0.14 minikube <none> <none>
rolldeployment-6b947d555-99rxm 1/1 Running 0 4m42s 10.244.0.18 minikube <none> <none>
rolldeployment-6b947d555-d2sff 1/1 Running 0 4m42s 10.244.0.19 minikube <none> <none>
rolldeployment-6b947d555-f6jx4 1/1 Running 0 4m42s 10.244.0.13 minikube <none> <none>
rolldeployment-6b947d555-g2ldl 1/1 Running 0 4m42s 10.244.0.16 minikube <none> <none>
rolldeployment-6b947d555-qpt7g 1/1 Running 0 4m42s 10.244.0.20 minikube <none> <none>
rolldeployment-6b947d555-s8cct 0/1 Completed 0 4m42s 10.244.0.17 minikube <none> <none>
rolldeployment-9b659bdf9-f78w2 0/1 ContainerCreating 0 9s <none> minikube <none> <none>
rolldeployment-9b659bdf9-gtdv5 0/1 ContainerCreating 0 8s <none> minikube <none> <none>
rolldeployment-9b659bdf9-jbbss 0/1 ContainerCreating 0 8s <none> minikube <none> <none>
rolldeployment-9b659bdf9-kssgd 0/1 ContainerCreating 0 1s <none> minikube <none> <none>
rolldeployment-9b659bdf9-wrxpk 1/1 Running 0 9s 10.244.0.23 minikube <none> <none>
- New replicaset created:
user@k8s:$ kubectl get rs
NAME DESIRED CURRENT READY AGE
rolldeployment-6b947d555 0 0 0 4m58s
rolldeployment-9b659bdf9 10 10 10 25s
- Run new deployment version:
user@k8s:$ kubectl set image deployment rolldeployment nginx=httpd:alpine --record=true
Flag --record has been deprecated, --record will be removed in the future
deployment.apps/rolldeployment image updated
- New pods are creating with new version:
user@k8s:$ kubectl get pods
NAME READY STATUS RESTARTS AGE
rolldeployment-7bd8467cd-8nrzd 1/1 Running 0 6s
rolldeployment-7bd8467cd-f6jrf 0/1 ContainerCreating 0 3s
rolldeployment-7bd8467cd-n7594 1/1 Running 0 8s
rolldeployment-7bd8467cd-p2n7b 1/1 Running 0 9s
rolldeployment-7bd8467cd-p9bnx 1/1 Running 0 18s
rolldeployment-7bd8467cd-q89x5 1/1 Running 0 5s
rolldeployment-7bd8467cd-qb5lb 1/1 Running 0 18s
rolldeployment-7bd8467cd-qx9gj 1/1 Running 0 18s
rolldeployment-7bd8467cd-skv5l 1/1 Running 0 18s
rolldeployment-7bd8467cd-smcvv 0/1 ContainerCreating 0 4s
rolldeployment-9b659bdf9-jbbss 1/1 Terminating 0 4m56s
rolldeployment-9b659bdf9-kssgd 1/1 Terminating 0 4m49s
- New replicaset created:
user@k8s:$ kubectl get rs
NAME DESIRED CURRENT READY AGE
rolldeployment-6b947d555 0 0 0 9m39s
rolldeployment-7bd8467cd 10 10 10 27s
rolldeployment-9b659bdf9 0 0 0 5m6s
- To show history of the deployments (important: --record should be used to add old deployment versions in the history list):
user@k8s:$ kubectl rollout history deployment rolldeployment
deployment.apps/rolldeployment
REVISION CHANGE-CAUSE
1 <none>
2 kubectl edit deployment rolldeployment --record=true
3 kubectl set image deployment rolldeployment nginx=httpd:alpine --record=true
- Rollback to previous version (with undo: "kubectl rollout undo deployment/rolldeployment"):
user@k8s:$ kubectl rollout undo deployment/rolldeployment
deployment.apps/rolldeployment rolled back
- Pod status:
user@k8s:$ kubectl get pods
NAME READY STATUS RESTARTS AGE
rolldeployment-7bd8467cd-8nrzd 1/1 Running 0 6m57s
rolldeployment-7bd8467cd-f6jrf 1/1 Running 0 6m54s
rolldeployment-7bd8467cd-n7594 1/1 Running 0 6m59s
rolldeployment-7bd8467cd-p2n7b 1/1 Running 0 7m
rolldeployment-7bd8467cd-p9bnx 1/1 Running 0 7m9s
rolldeployment-7bd8467cd-q89x5 1/1 Running 0 6m56s
rolldeployment-7bd8467cd-qx9gj 1/1 Running 0 7m9s
rolldeployment-7bd8467cd-smcvv 1/1 Running 0 6m55s
rolldeployment-9b659bdf9-5klq5 0/1 ContainerCreating 0 2s
rolldeployment-9b659bdf9-8rdgm 0/1 ContainerCreating 0 2s
rolldeployment-9b659bdf9-drb54 0/1 ContainerCreating 0 2s
rolldeployment-9b659bdf9-gv8m8 0/1 ContainerCreating 0 2s
- It is also to pause rollout:
user@k8s:$ kubectl rollout undo deployment/rolldeployment
deployment.apps/rolldeployment rolled back
user@k8s:$ kubectl rollout pause deployment/rolldeployment
deployment.apps/rolldeployment paused
user@k8s:$ kubectl get rs
NAME DESIRED CURRENT READY AGE
rolldeployment-6b947d555 0 0 0 19m
rolldeployment-7bd8467cd 6 6 2 10m
rolldeployment-9b659bdf9 6 6 6 14m
- There are 12 pods instead of 10 pods, because of the rolling update:
user@k8s:$ kubectl get pods
NAME READY STATUS RESTARTS AGE
rolldeployment-7bd8467cd-78sjw 1/1 Running 0 18s
rolldeployment-7bd8467cd-cvjx6 1/1 Running 0 18s
rolldeployment-7bd8467cd-cvxqt 1/1 Running 0 18s
rolldeployment-7bd8467cd-krwpf 1/1 Running 0 18s
rolldeployment-7bd8467cd-ks8z4 1/1 Running 0 14s
rolldeployment-7bd8467cd-xc52z 1/1 Running 0 13s
rolldeployment-9b659bdf9-4tt79 1/1 Running 0 2m57s
rolldeployment-9b659bdf9-8rdgm 1/1 Running 0 3m3s
rolldeployment-9b659bdf9-drb54 1/1 Running 0 3m3s
rolldeployment-9b659bdf9-h6jzq 1/1 Running 0 2m54s
rolldeployment-9b659bdf9-jtch2 1/1 Running 0 2m55s
rolldeployment-9b659bdf9-tnthr 1/1 Running 0 2m56s
- While rollback undo, it was paused:
user@k8s:$ kubectl get rs
NAME DESIRED CURRENT READY AGE
rolldeployment-6b947d555 0 0 0 19m
rolldeployment-7bd8467cd 6 6 6 10m
rolldeployment-9b659bdf9 6 6 6 14m
- Resume the pause of rollout of deployment:
user@k8s:$ kubectl rollout resume deployment/rolldeployment
deployment.apps/rolldeployment resumed
user@k8s:$ kubectl get rs
NAME DESIRED CURRENT READY AGE
rolldeployment-6b947d555 0 0 0 23m
rolldeployment-7bd8467cd 10 10 6 14m
rolldeployment-9b659bdf9 2 2 2 19m
user@k8s:$ kubectl get rs
NAME DESIRED CURRENT READY AGE
rolldeployment-6b947d555 0 0 0 23m
rolldeployment-7bd8467cd 10 10 8 14m
rolldeployment-9b659bdf9 0 0 0 19m
user@k8s:$ kubectl get rs
NAME DESIRED CURRENT READY AGE
rolldeployment-6b947d555 0 0 0 23m
rolldeployment-7bd8467cd 10 10 9 14m
rolldeployment-9b659bdf9 0 0 0 19m
user@k8s:$ kubectl get rs
NAME DESIRED CURRENT READY AGE
rolldeployment-6b947d555 0 0 0 23m
rolldeployment-7bd8467cd 10 10 10 14m
rolldeployment-9b659bdf9 0 0 0 19m
- Delete deployment:
user@k8s:$ kubectl delete -f rolling-deployment.yaml
deployment.apps "rolldeployment" deleted
user@k8s:$ kubectl get rs
No resources found in default namespace.
user@k8s:$ kubectl get pods
No resources found in default namespace.
- Delete minikube:
minikube delete
π₯ Deleting "minikube" in docker ...
π₯ Deleting container "minikube" ...
π₯ Removing /home/omer/.minikube/machines/minikube ...
π Removed all traces of the "minikube" cluster.
Conclusion
This post showed the mechanism of the rollout, rollback between versions. K8s rollout
ensures smooth deployment of new application versions with minimal downtime using rolling updates.
If an issue arises, rollback
allows quick restoration to a stable previous version, reducing service disruption. These features enhance application availability, reliability, and DevOps efficiency.
If you found the tutorial interesting, Iβd love to hear your thoughts in the blog post comments. Feel free to share your reactions or leave a comment. I truly value your input and engagement π
For other posts π https://dev.to/omerberatsezer π§
Multi-Container Sidecar Pattern on Kubernetes with Hands-on Sample
Γmer Berat Sezer γ» Jan 24
Follow for Tips, Tutorials, Hands-On Labs for AWS, Kubernetes, Docker, Linux, DevOps, Ansible, Machine Learning, Generative AI.
Top comments (0)