Interactive · GitOps · Argo CD
Argo CD doesn't really "deploy" — it continuously reconciles, comparing the desired state in Git against the live state in the cluster and, when they differ, running a sync operation through ordered phases until the cluster matches Git and every resource is healthy. One architecture diagram stays fixed below while its state steps through a full sync: from steady state, through drift detection, into PreSync → Sync → PostSync, to Synced + Healthy — plus the failure branch. Thick grey lines are the fixed wiring; the thin blue overlay is the desired-state path (Git → repo-server → controller) and the thin teal overlay is the live-state path (controller ↔ cluster). A violet ring marks the component doing the work. Watch three things change: which component is active, the Sync status, and the Health status.
—
—
Operation phase
—
—
Sync phase / wave
—
—
What's happening
—
—
The three state machines Argo CD reports, using its exact names. App-level Health is the worst health of its immediate child resources, not an inherited value.
| Dimension | Values (verbatim) | Notes |
|---|---|---|
| Sync status (3) | Synced OutOfSync Unknown | Synced = live matches Git; OutOfSync = mismatch; Unknown = comparison not available. |
| Health status (6) | Healthy Progressing Degraded Suspended Missing Unknown | Priority (worst wins): Healthy < Suspended < Progressing < Missing < Degraded < Unknown. |
| Operation phase (5) | Running Succeeded Failed Error Terminating | Recorded in status.operationState on the Application. |
A sync runs in ordered phases. Apply order within a sync is: phase → sync-wave → kind → name. PostSync fires only after a successful apply and every resource is Healthy.
| Item | Value | Meaning |
|---|---|---|
| Phases | PreSync → Sync → PostSync (+ SyncFail) | PreSync runs before manifests; Sync applies them; PostSync runs after all resources are Healthy; SyncFail runs on failure. |
| Hook annotation | argocd.argoproj.io/hook | Values: PreSync Sync Skip PostSync SyncFail PostDelete. |
| Hook delete policy | argocd.argoproj.io/hook-delete-policy | HookSucceeded · HookFailed · BeforeHookCreation. |
| Sync wave | argocd.argoproj.io/sync-wave | Integer, default 0, negatives allowed; low → high, ~2s delay between waves; next wave waits for current to be Healthy. |
What wakes the controller, and how often it looks on its own.
| Trigger | Mechanism | Notes |
|---|---|---|
| Manual | argocd app sync, UI or API | Explicit; also the only mode that permits rollback. |
| Automated | spec.syncPolicy.automated | Options: prune, selfHeal, allowEmpty. Only syncs when OutOfSync; skips identical SHAs unless selfHeal. |
| Poll | timeout.reconciliation | ~3 min (120s + up to 60s jitter). Set 0 to disable polling entirely. |
| Webhook | Git provider push | Near-instant sync instead of waiting for the poll tick. |
argocd app sync flagsHow the apply behaves, set per-app via argocd.argoproj.io/sync-options or per-run via CLI flags. Retry uses exponential backoff.
| Sync options | CLI flags | Retry / backoff |
|---|---|---|
Prune=true · Replace=true · Force=true · ServerSideApply=true · ApplyOutOfSyncOnly=true · CreateNamespace=true · PrunePropagationPolicy=<p> · PruneLast=true |
--prune · --force · --replace · --server-side · --dry-run · --resource · --async |
spec.syncPolicy.retry.limit (e.g. 5; -1=unlimited)backoff.duration 5s · factor 2 · maxDuration 3m |
The ways a real sync goes wrong — stage F is the first of these.
| Mode | What happens | Symptom |
|---|---|---|
| Hook failure | A PreSync/Sync hook Job fails (classic: a DB-migration Job errors), so the Sync phase never applies; SyncFail hooks run. | OperationState = Failed, stays OutOfSync. |
| Stuck Progressing | A resource never reaches Healthy, so PostSync never fires and the operation hangs or times out. | Synced but Degraded / Progressing. |
| selfHeal vs human | Someone kubectl edits a live resource; with selfHeal: true the controller reverts it within ~5s, repeatedly. | Manual changes never stick. |