CKAD — Kubernetes Application Developer
Rolling Updates, Rollbacks, Blue-Green and Canary
Goal
You tune a Deployment's rollout parameters, build up revisions and roll back to the point you want, and build blue-green and canary with nothing but labels, selectors, and replicas.
Why it matters
Once you understand that a Deployment manages several ReplicaSets, everything else follows. When you change the image, a new ReplicaSet is created and the old one remains with 0 replicas. rollout undo is instantaneous because it does not pull the image again; it scales up a ReplicaSet that already exists. If you set revisionHistoryLimit to 0, that safety net disappears.
maxSurge and maxUnavailable are a tradeoff between "how fast" and "how safe." maxUnavailable: 0 keeps the number of available Pods even during the rollout, but it is slow because it must wait for the new Pod to become Ready. And this safety net is meaningful only with a Readiness Probe — without a probe, a container is considered Ready as soon as it starts.
Blue-green and canary can be built with labels alone, without a separate CRD. The difference is how narrow the Service selector is. If you put the version label in the selector, only one side receives traffic (blue-green); if you put only the shared label, both sides come in and traffic is split by the ratio of counts (canary).
Steps
- Create the namespace
ckad-deployand create a Deploymentweb. Imagenginx:1.25, 4 replicas. (The container name becomesnginx.) - Set the strategy of
webtoRollingUpdatewithmaxSurge: 1andmaxUnavailable: 0. - Update the image of
webtonginx:1.26, and attach to the Deployment the annotationkubernetes.io/change-cause=nginx 1.26 으로 업데이트(the Korean text in the value means "updated to nginx 1.26"). - Update the image of
webonce more tonginx:1.27, and refresh the annotation tokubernetes.io/change-cause=nginx 1.27 으로 업데이트(the Korean text in the value means "updated to nginx 1.27"). At this point, at least 3 ReplicaSets must exist. - Roll
webback to revision 2. A rollback is also a change that moves forward, so a new revision 4 is created, and that revision's image must benginx:1.26. - Build blue-green. Create the Deployments
checkout-blue(2 replicas, labelsapp=checkoutandversion=blue, imagenginx:1.26) andcheckout-green(2 replicas, labelsapp=checkoutandversion=green, imagenginx:1.27), and give the Servicecheckout(port 80, targetPort 80) the selectorapp=checkout+version=green. - Build a canary. Create the Deployments
pay-stable(9 replicas, labelsapp=payandtrack=stable, imagenginx:1.26) andpay-canary(1 replica, labelsapp=payandtrack=canary, imagenginx:1.27), and give the Servicepay(port 80, targetPort 80) only the selectorapp=pay. - Run
kubectl rollout pauseonwebfirst, then change the image tonginx:1.28and setrevisionHistoryLimitto 3. Because it is paused, no new ReplicaSet should be created. (Do not resume. Leave the 4 replicas as they are.)
Notes
kubectl patch deployment web -n ckad-deploy -p '{"spec":{"strategy":{"rollingUpdate":{"maxSurge":1,"maxUnavailable":0}}}}'kubectl annotate deployment web -n ckad-deploy kubernetes.io/change-cause='...' --overwrite- View the contents of each revision with
kubectl rollout history deployment/web -n ckad-deployand--revision=2. - Common mistake 1: writing the Deployment name instead of the container name in
kubectl set image. It is컨테이너=이미지(the placeholders are the container name and the image), as indeployment/web nginx=nginx:1.26. - Common mistake 2: putting
trackin the Service selector for a canary. Then only one side receives traffic, so it becomes blue-green, not a canary. - Step 8 is meaningful only if you apply
pausefirst. If the order is reversed, the rollout has already started.
Creating the namespace and Deployment
Create the namespace ckad-deploy and create a Deployment web. Image nginx:1.25, 4 replicas. (The container name becomes nginx.)
Give kubectl create deployment the --image and --replicas flags. Check what labels and selector the created Deployment has — you will use them in later steps.
Tuning the rolling update parameters
Set the strategy of web to RollingUpdate with maxSurge: 1 and maxUnavailable: 0.
The two values are under spec.strategy.rollingUpdate. You can edit with kubectl edit or pass JSON to kubectl patch. maxUnavailable: 0 means you want to keep the original count even during the rollout.
Updating the image and recording the change-cause
Update the image of web to nginx:1.26, and attach to the Deployment the annotation kubernetes.io/change-cause=nginx 1.26 으로 업데이트 (the Korean text in the value means "updated to nginx 1.26").
The form is kubectl set image deployment/이름 컨테이너=이미지 (the placeholders are the Deployment name, the container name, and the image). You must write the container name exactly. Attach the CHANGE-CAUSE yourself as the kubernetes.io/change-cause annotation.
Pushing once more to build up revisions
Update the image of web once more to nginx:1.27, and refresh the annotation to kubernetes.io/change-cause=nginx 1.27 으로 업데이트 (the Korean text in the value means "updated to nginx 1.27"). At this point, at least 3 ReplicaSets must exist.
Revisions remain as ReplicaSets. Check how many have accumulated with kubectl get rs -n <ns> and how far the revision number has come with kubectl rollout history.
Rolling back to a specific revision
Roll web back to revision 2. A rollback is also a change that moves forward, so a new revision 4 is created, and that revision's image must be nginx:1.26.
Give kubectl rollout undo the flag --to-revision=번호 (the placeholder is the revision number). Even after a rollback, the revision number does not decrease; a new number is attached. To see which image each revision had, use kubectl rollout history --revision=N.
Blue-green — switching the Service selector
Build blue-green. Create the Deployments checkout-blue (2 replicas, labels app=checkout and version=blue, image nginx:1.26) and checkout-green (2 replicas, labels app=checkout and version=green, image nginx:1.27), and give the Service checkout (port 80, targetPort 80) the selector app=checkout + version=green.
The two Deployments share one common label and have different version labels. If you put the version label in the Service selector, only that side joins the endpoints. Creating the Service and then just changing the selector is the whole of this pattern.
Canary — splitting traffic by replica ratio
Build a canary. Create the Deployments pay-stable (9 replicas, labels app=pay and track=stable, image nginx:1.26) and pay-canary (1 replica, labels app=pay and track=canary, image nginx:1.27), and give the Service pay (port 80, targetPort 80) only the selector app=pay.
A canary is the opposite: keep the Service selector narrow so that the Pods of both Deployments come in. Then the traffic ratio becomes the ratio of replica counts. Give each Deployment its own distinguishing label.
Collecting changes in a paused state (comprehensive)
Run kubectl rollout pause on web first, then change the image to nginx:1.28 and set revisionHistoryLimit to 3. Because it is paused, no new ReplicaSet should be created. (Do not resume. Leave the 4 replicas as they are.)
If you apply kubectl rollout pause first, later template changes accumulate without immediately creating a new ReplicaSet. If the order is reversed, the rollout has already started. Also set the field that determines how many old ReplicaSets to keep.