The Verdict
For a small stateless application where the cluster supports Kubernetes rolling updates, sync waves alone are insufficient to guarantee zero downtime if you are managing the cutover between two distinct resource sets. You should rely on the Kubernetes Deployment rollingUpdate strategy for the actual pod transition and use a Pre-Sync Hook if you need to gate the overall synchronization process based on external readiness checks.
Why Sync Waves Are Not a Readiness Gate
A common misconception is that Argo CD waits for a resource to be "Healthy" before moving to the next sync wave. In reality, Argo CD proceeds to the next wave as soon as the Kubernetes API server accepts the manifest. It does not natively pause for the Ready condition of pods within a Deployment before triggering the next wave.
If you use waves to sequence a "New Version" deployment and an "Old Version" deletion, the deletion wave may trigger while the new pods are still in ContainerCreating or Pending, leading to a service outage.
Implementation Strategy
To achieve zero downtime for a stateless app, follow these configurations:
- Primary Mechanism: Use a single Kubernetes Deployment with a
strategy: type: RollingUpdate. Set maxUnavailable: 0 and maxSurge: 1 (or higher). This ensures Kubernetes keeps the old pods running until the new ones pass their readiness probes.
- Gating with Pre-Sync Hooks: If you must perform a task (like a database migration) before the rollout starts, use a Pre-Sync hook. Set the
HookFailurePolicy to Fail. This ensures that if the pre-requisite fails, Argo CD aborts the sync entirely, leaving the existing stable version untouched.
Addressing Constraints
| Constraint |
Effect / Recommendation |
HookFailurePolicy |
Set to Fail. If set to Continue, a failed readiness check will not stop the sync, potentially triggering the removal of old resources while the new version is broken. |
| Disabling Prune |
Not recommended. While it prevents the accidental deletion of the old version, it leads to "resource leak" where old ReplicaSets and ConfigMaps accumulate, eventually hitting cluster quotas. |
Verification Steps
To verify the behavior in a staging environment:
- Apply a Deployment with
maxUnavailable: 0.
- Trigger a sync and run
kubectl get pods -w. Confirm that the new pod reaches Ready before the old pod is terminated.
- If using a Pre-Sync hook, intentionally cause the hook to fail (e.g., a script that exits 1) and verify that the main Deployment is not updated.
Missing Detail: Are you deploying a single Deployment manifest with a version change, or are you managing two separate Deployment objects (Blue/Green) via Argo CD?