Sync Phases, Waves, and Hooks¶
- ArgoCD sync operations proceed through three phases: PreSync, Sync, and PostSync.
- Within each phase, resources are ordered by their
argocd.argoproj.io/sync-waveannotation. - Hooks are resources (Jobs, Pods, etc.) that run only during sync operations, not as permanent workloads.
What will we learn?¶
- The three sync phases and when each runs
- How sync waves order resource application within a phase
- How to create PreSync, Sync, and PostSync hooks
- How to use sync-wave annotations to control ordering
Prerequisites¶
- Complete Lab 002
01. Sync Phases¶
ArgoCD Sync Timeline:
┌─────────────────────────────────────────────────────┐
│ 1. PreSync Phase │
│ - Run PreSync hooks (e.g., database migrations) │
│ - Wait for all PreSync hooks to complete │
├─────────────────────────────────────────────────────┤
│ 2. Sync Phase │
│ - Apply all non-hook resources │
│ - Resources with lower wave number go first │
├─────────────────────────────────────────────────────┤
│ 3. PostSync Phase │
│ - Run PostSync hooks (e.g., smoke tests) │
│ - SyncFail hooks run if sync fails │
└─────────────────────────────────────────────────────┘
02. Hook Annotations¶
metadata:
annotations:
argocd.argoproj.io/hook: PreSync # Phase
argocd.argoproj.io/hook-delete-policy: HookSucceeded # Cleanup
Hook types:
PreSync- runs before the sync beginsSync- runs during the sync phase (alongside normal resources)PostSync- runs after all resources are synced and healthySyncFail- runs only if the sync fails
Hook delete policies:
HookSucceeded- delete the hook after it succeedsHookFailed- delete the hook after it failsBeforeHookCreation- delete the previous hook before creating a new one
03. PreSync Hook Example: Database Migration¶
cat <<'EOF' | kubectl apply -f -
apiVersion: batch/v1
kind: Job
metadata:
name: db-migration
namespace: guestbook
annotations:
argocd.argoproj.io/hook: PreSync
argocd.argoproj.io/hook-delete-policy: HookSucceeded
spec:
template:
spec:
containers:
- name: migrate
image: alpine:3.18
command: ["/bin/sh", "-c"]
args:
- |
echo "Running database migration..."
sleep 5
echo "Migration complete!"
restartPolicy: Never
backoffLimit: 2
EOF
04. PostSync Hook Example: Smoke Test¶
cat <<'EOF' | kubectl apply -f -
apiVersion: batch/v1
kind: Job
metadata:
name: smoke-test
namespace: guestbook
annotations:
argocd.argoproj.io/hook: PostSync
argocd.argoproj.io/hook-delete-policy: HookSucceeded
spec:
template:
spec:
containers:
- name: test
image: curlimages/curl:8.0.0
command: ["/bin/sh", "-c"]
args:
- |
echo "Running smoke test..."
# curl -f http://guestbook-ui.guestbook.svc.cluster.local
echo "Smoke test passed!"
restartPolicy: Never
backoffLimit: 3
EOF
05. Sync Waves¶
Waves control the order within each sync phase. Lower wave numbers are applied first:
cat <<'EOF' | kubectl apply -f -
# Wave 1: Create the namespace
apiVersion: v1
kind: Namespace
metadata:
name: wave-demo
annotations:
argocd.argoproj.io/sync-wave: "1"
---
# Wave 2: Create ConfigMaps and Secrets
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
namespace: wave-demo
annotations:
argocd.argoproj.io/sync-wave: "2"
data:
key: value
---
# Wave 3: Deploy the application
apiVersion: apps/v1
kind: Deployment
metadata:
name: wave-demo-app
namespace: wave-demo
annotations:
argocd.argoproj.io/sync-wave: "3"
spec:
replicas: 1
selector:
matchLabels:
app: wave-demo
template:
metadata:
labels:
app: wave-demo
spec:
containers:
- name: nginx
image: nginx:alpine
EOF

06. Hands-on¶
- Create a PreSync hook Job that prints “Pre-sync complete” and verify it runs before the main deployment:
??? success “Solution”
cat <<'EOF' | kubectl apply -f -
apiVersion: batch/v1
kind: Job
metadata:
name: presync-demo
namespace: guestbook
annotations:
argocd.argoproj.io/hook: PreSync
argocd.argoproj.io/hook-delete-policy: HookSucceeded
spec:
template:
spec:
containers:
- name: demo
image: alpine:3.18
command: [sh, -c, "echo Pre-sync hook running! && sleep 3"]
restartPolicy: Never
EOF
# Trigger a sync to see the hook run
argocd app sync guestbook
kubectl get jobs -n guestbook
- Add
sync-waveannotations to two ConfigMaps so that ConfigMap A (wave 1) is applied before ConfigMap B (wave 2):
??? success “Solution”
kubectl apply -f - <<'EOF'
apiVersion: v1
kind: ConfigMap
metadata:
name: wave-first
namespace: guestbook
annotations:
argocd.argoproj.io/sync-wave: "1"
data:
order: first
---
apiVersion: v1
kind: ConfigMap
metadata:
name: wave-second
namespace: guestbook
annotations:
argocd.argoproj.io/sync-wave: "2"
data:
order: second
EOF
07. Summary¶
- Sync phases execute in strict order: PreSync → Sync → PostSync → SyncFail (on failure)
- Hooks are standard Kubernetes resources (Jobs, Pods) with
argocd.argoproj.io/hookannotations hook-delete-policy: HookSucceededkeeps failed hooks for debugging while cleaning up successful ones- Sync waves (
argocd.argoproj.io/sync-wave) are integers - ArgoCD waits for all resources in wave N to be healthy before starting wave N+1 - Hooks are never part of the steady-state - they only exist during sync operations