In-place Updates (Rolling Upgrade)
Goal: controlled, pod-by-pod upgrade of the base Deployment using native Kubernetes
rolling update semantics, cluster by cluster — no separate canary Deployment required.
How it works
Unlike Strategy 1, which deploys a separate canary Deployment alongside the base, the
rolling upgrade patches the base Deployment directly via an OverridePolicy. The local
Kubernetes controller inside each target cluster handles the rolling update, respecting the
maxSurge and maxUnavailable settings already configured on the Deployment. You can
upgrade one cluster first, observe, then extend to remaining clusters — or roll back at any
point before the change spreads further.
The OverridePolicy used for the rolling upgrade strategy is functionally identical to the
canary http-probe-promote-override OverridePolicy: both override the application
environment variable ROLLOUT_LABEL with the value v2. The only distinction lies in the
policy naming — we name it http-probe-rolling-upgrade merely for differentiation purposes.
The two policies are independent of each other. They can either be merged by combining their
overrideRules.targetCluster configurations, or coexist as-is: a rolling upgrade can run
on some clusters while a canary deployment runs on others simultaneously.
Controlling rollout speed: with this strategy the only way to influence how fast or slow the rolling update progresses within a cluster is by tuning three parameters on the
Deploymentspec:
spec.strategy.rollingUpdate.maxSurge— how many extra pods can exist above the desired count during the update. WithmaxSurge: 1only one new pod is created at a time.spec.strategy.rollingUpdate.maxUnavailable— how many pods can be unavailable during the update. WithmaxUnavailable: 0no pod is terminated until its replacement is ready.spec.template.spec.containers[].readinessProbe.initialDelaySeconds— how long Kubernetes waits before starting readiness checks on a new pod. Together withperiodSecondsthis determines the minimum time each pod takes to be declared ready, which gates when the next pod starts rolling.With
maxUnavailable: 0andmaxSurge: 1(the settings used in this tutorial), pods roll one at a time and each must pass its readiness probe before the next starts — giving you fine-grained control per pod but no way to express a target traffic percentage explicitly. If explicit percentage-based traffic control is a requirement, see Strategy 3 — Percentage-based Shifting (Wave Rollout) which achieves approximate traffic percentages by balancing replica counts across two Deployments.
Demo 1 — Rolling upgrade one cluster, extend to region
Upgrade member1 first and observe the in-place roll, then extend to the full region
cluster by cluster and finalize.
The steps we will execute are:
- Apply an
OverridePolicytargetingmember1— base rolls tov2in place - Extend the
OverridePolicytomember2— base rolls tov2in place - Extend the
OverridePolicyto all three clusters —member3rolls tov2 - Finalize — update the base manifest to
v2, delete theOverridePolicy(zero-churn)
The following diagram depicts the full sequence of operations:
Note: Before running Demo 1, ensure the cluster is on
v1:kubectl apply -f base/http-probe-app.yaml
Step 1: Upgrade the base on member1
Apply the rolling upgrade OverridePolicy targeting member1. Karmada patches the base
Deployment spec on member1 — the local Kubernetes controller triggers a standard rolling
update replacing pods one by one.
http-probe-rolling-upgrade-member1.yaml
apiVersion: policy.karmada.io/v1alpha1
kind: OverridePolicy
metadata:
name: http-probe-rolling-upgrade
spec:
resourceSelectors:
- apiVersion: apps/v1
kind: Deployment
name: http-probe-app
overrideRules:
- targetCluster:
clusterNames:
- member1
overriders:
plaintext:
- path: /spec/template/spec/containers/0/env/0/value
operator: replace
value: v2
kubectl apply -f rolling-upgrade/http-probe-rolling-upgrade-member1.yaml
Watch the base Deployment roll on member1:
kubectl --kubeconfig ~/.kube/members.config --context member1 \
rollout status deployment/http-probe-app
What to observe in the dashboard:
- Replica panel: the pods in
member1roll in place — there are no separate canary pods. During the transition a mix of yellow●(v2) and green○(v1) pods is visible in themember1column as Kubernetes replaces them one by one. Once complete, the entiremember1column shows yellow●. Themember2andmember3columns remain fully green throughout. - Traffic panel: the
member1column shows a growing proportion of yellow-highlighted responses as pods are replaced. Themember2andmember3columns remain fully white.
Step 2: Extend the upgrade to member2
Apply the same OverridePolicy with member1 and member2 in clusterNames. Karmada
patches the existing policy in place and triggers the rolling update on member2.
kubectl apply -f rolling-upgrade/http-probe-rolling-upgrade-member1-member2.yaml
Watch the base Deployment roll on member2:
kubectl --kubeconfig ~/.kube/members.config --context member2 \
rollout status deployment/http-probe-app
What to observe in the dashboard:
- Replica panel: the
member2column transitions through the same rolling pattern — a mix of yellow●and green○pods visible during the update. Themember1column is already fully yellow and unchanged. Themember3column remains fully green. - Traffic panel: yellow-highlighted responses spread to the
member2column as pods roll. Themember3column remains fully white.
Step 3: Extend the upgrade to member3
Apply the OverridePolicy with all three clusters in clusterNames.
kubectl apply -f rolling-upgrade/http-probe-rolling-upgrade-all.yaml
Watch the base Deployment roll on member3:
kubectl --kubeconfig ~/.kube/members.config --context member3 \
rollout status deployment/http-probe-app
What to observe in the dashboard:
- Replica panel: the
member3column transitions through the rolling pattern. Once complete, all three columns show only yellow●pods — all base pods across the region are onv2. - Traffic panel: all three columns are fully yellow — every response carries
v2.
Step 4: Finalize the upgrade
Update the base manifest to v2 and delete the OverridePolicy. Because all clusters are
already running v2 via the override, updating the base manifest is a no-op at the pod
level — no pods are restarted.
kubectl apply -f base/http-probe-app-v2.yaml
kubectl delete overridepolicy http-probe-rolling-upgrade
Verify all clusters are on v2:
kubectl get resourcebinding http-probe-app-deployment -o jsonpath=\
'{range .status.aggregatedStatus[*]}{.clusterName}: {.health} ready={.status.readyReplicas}/{.status.replicas}{"\n"}{end}'
Expected output:
member1: Healthy ready=2/2
member2: Healthy ready=2/2
member3: Healthy ready=2/2
What to observe in the dashboard:
- Replica panel: all pods remain yellow
●then settle back to green○— no pod churn occurs. TheOverridePolicyalready had all clusters onv2; updating the base manifest is purely a source-of-truth update. - Traffic panel: all three columns continue serving
v2without interruption. The bottom bar legend disappears — no two versions are present simultaneously.
Demo 2 — Rolling upgrade one cluster, rollback
Upgrade member1, observe a problem, and roll it back — demonstrating that a rolling
upgrade can be safely aborted on any cluster before it spreads to others.
The steps we will execute are:
- Apply an
OverridePolicytargetingmember1— base rolls tov2in place - Roll back by deleting the
OverridePolicy— base onmember1rolls back tov1
The following diagram depicts the full sequence of operations:
Note: Before running Demo 2, ensure the cluster is on
v1:kubectl apply -f base/http-probe-app.yaml
Step 1: Upgrade the base on member1
kubectl apply -f rolling-upgrade/http-probe-rolling-upgrade-member1.yaml
Watch the base Deployment roll on member1:
kubectl --kubeconfig ~/.kube/members.config --context member1 \
rollout status deployment/http-probe-app
What to observe in the dashboard:
- Replica panel: pods in
member1roll in place from green○to yellow●one by one. Themember2andmember3columns remain fully green throughout. - Traffic panel: the
member1column shows a growing proportion of yellow responses. Themember2andmember3columns remain fully white.
Step 2: Roll back the upgrade on member1
Delete the OverridePolicy. Karmada removes the patch and Kubernetes rolls the base
Deployment on member1 back to the version declared in the base manifest (v1).
member2 and member3 are untouched — they were never part of the OverridePolicy.
kubectl delete overridepolicy http-probe-rolling-upgrade
Watch the rollback on member1:
kubectl --kubeconfig ~/.kube/members.config --context member1 \
rollout status deployment/http-probe-app
What to observe in the dashboard:
- Replica panel: pods in
member1roll back tov1one by one — a brief mix of yellow●and green○is visible during the transition. Once complete, all three columns are fully green○— the region is back onv1with noOverridePolicyin place. - Traffic panel: the
member1column returns to fully white responses. All three columns are uniform white once the rollback completes.
Deleting the
OverridePolicyis the complete rollback operation — no additional cleanup is needed. The base manifest remains atv1and the region converges to it immediately.