Canary Rollout¶
Canary mode resizes a small percentage of pods first, watches them for safety violations, and only proceeds to the full fleet after the observation period passes without issues.
Configuring canary rollout¶
spec:
cpu:
maxChangePercent: 50 # max CPU change per resize cycle
memory:
maxChangePercent: 30 # max memory change per resize cycle
updateStrategy:
type: Canary
canary:
percentage: 10 # resize 10% of pods first
observationPeriod: 30m # watch canary pods for 30 minutes
autoPromote: true # promote to full fleet automatically
cooldown: 2h
autoRevert: true
| Field | Description |
|---|---|
canary.percentage |
Percentage of eligible pods to resize in the first wave |
canary.observationPeriod |
How long the operator monitors canary pods before proceeding |
canary.autoPromote |
Automatically promote to full fleet after observation passes without reverts (default: false) |
cpu.maxChangePercent |
Maximum CPU change per resize cycle (default 50%) |
memory.maxChangePercent |
Maximum memory change per resize cycle (default 30%) |
cooldown |
Minimum time between successive resizes of the same workload |
autoRevert |
Automatically restore original resources on safety violation |
Note
At least one pod is always selected, even if percentage would calculate
to zero. For a 3-replica Deployment with percentage: 10, one pod is
resized.
Step-by-step process¶
- Recommendations computed: the estimator chain produces per-container targets based on Prometheus data.
- Canary selection: the operator picks
ceil(percentage * eligible / 100)pods. Only running pods without an active resize or pending deletion qualify. - In-place resize: the operator calls
UpdateResizeon each selected pod. - Observation:
status.canary.startTimeis set only after a successful in-place canary resize. DuringobservationPeriodafter that resize, the safety monitor checks for OOMKill, restart spikes, pod NotReady, CPU throttle, and SLO guardrail breaches. Skipped cycles (budget, node pressure, already at target) do not start the clock. - Verdict: if that app's canary pods remain healthy, that app
is promoted (
status.canary.workloads[].phase=FullRollout). Other apps on the same policy keep watching. Policystatus.canary.phasebecomesFullRolloutonly when every listed app has been promoted. A revert on one app resets that app's clock only. - Isolation: while an app is still in canary, CREATE initial sizing,
startup boost, and HPA retune do not apply to the rest of that app
(or to other apps). New pods stay at their template size until that
app is promoted (or the assigned pod name is already in
status.canary.workloads[].pods). ReplicaSet CREATE often has an emptymetadata.name; that empty name is not treated as a slice identity. Selector-based policies are included: the CREATE webhook fetches the owning Deployment/StatefulSet/DaemonSet and matchestargetRef.selector. - Cooldown: the operator waits for that workload's
cooldownbefore resizing it again. Other apps on the policy are not locked.
Monitoring canary pods¶
The operator tracks which pods were selected for the canary subset in
status.canary.pods and per app in status.canary.workloads. The
kubectl attune status CANARY column shows CanaryInProgress (1/2 apps)
when some apps are promoted and others are still watching. List the
per-app rows:
kubectl get attunepolicy my-app -o jsonpath='{.status.canary.workloads}' | jq .
Watch resize events:
kubectl get events --field-selector reason=Resized -w
Check which pods have been resized:
kubectl get pods -l app=my-app -o custom-columns=\
NAME:.metadata.name,\
CPU_REQ:.spec.containers[0].resources.requests.cpu,\
MEM_REQ:.spec.containers[0].resources.requests.memory
Handling auto-revert¶
When the safety monitor detects a problem, it reverts the pod's resources
and records the event in .status.resizeHistory with result: Reverted.
kubectl get attunepolicy my-app -o jsonpath='{.status.resizeHistory}' | jq '.[] | select(.result=="Reverted")'
Warning
If you see repeated reverts, review the reason field (oomkill, restart, throttle, slo:<name>,
notready) and consider increasing the overhead or adjusting bounds
before retrying.
Promoting from canary to full fleet¶
Automatic promotion¶
When autoPromote: true, the operator handles promotion automatically:
- After the canary pods pass the observation period measured from the
successful in-place resize, with zero reverts, the operator sets
status.canary.phase: FullRollout. - On the next reconcile, all eligible pods are resized (same as Auto mode).
- If any revert occurs during observation, promotion is blocked, the observation clock is cleared, and a new watch starts after the next successful in-place resize. The operator continues resizing only the canary subset until that new watch passes.
Check the canary phase:
kubectl get attunepolicy my-app -o jsonpath='{.status.canary.phase}'
# CanaryInProgress -> FullRollout
Spec change resets the canary cycle. If you edit the policy spec
(e.g., change percentile or overhead) while a canary cycle is in
progress or in FullRollout, the operator resets the observation timer.
The new configuration is re-validated from scratch before promotion.
Manual promotion¶
When autoPromote is false (default), promote to Auto mode manually
after canary pods have run successfully through multiple cooldown cycles:
kubectl patch attunepolicy my-app --type merge \
-p '{"spec":{"updateStrategy":{"type":"Auto"}}}'
Or increase the canary percentage gradually:
kubectl patch attunepolicy my-app --type merge \
-p '{"spec":{"updateStrategy":{"canary":{"percentage":50}}}}'
Rollback¶
To stop all resizing immediately, switch back to Recommend mode:
kubectl patch attunepolicy my-app --type merge \
-p '{"spec":{"updateStrategy":{"type":"Recommend"}}}'
Tip
Existing pod resources are not reverted when you change modes. Pods keep their current allocations; only future resize operations are affected.