Stage 5 · Platform
GitOps Operations
Sync Windows and Waves
Controlling deployment order with Argo CD sync waves, hooks, windows, and health checks.
Sync Ordering
When ArgoCD syncs an application, it needs to apply resources in the correct order. Namespaces must exist before deployments. ConfigMaps must exist before pods that use them. Services must exist before ingress resources. Sync waves and hooks control this ordering.
Sync Waves
# Wave 0: Namespace
apiVersion: v1
kind: Namespace
metadata:
name: production
annotations:
argocd.argoproj.io/sync-wave: "0"
---
# Wave 1: Secrets
apiVersion: v1
kind: Secret
metadata:
name: myapp-secrets
namespace: production
annotations:
argocd.argoproj.io/sync-wave: "1"
---
# Wave 2: ConfigMaps
apiVersion: v1
kind: ConfigMap
metadata:
name: myapp-config
namespace: production
annotations:
argocd.argoproj.io/sync-wave: "2"
---
# Wave 3: Database
apiVersion: apps/v1
kind: Deployment
metadata:
name: postgres
namespace: production
annotations:
argocd.argoproj.io/sync-wave: "3"
---
# Wave 4: Application
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
namespace: production
annotations:
argocd.argoproj.io/sync-wave: "4"
---
# Wave 5: Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myapp
namespace: production
annotations:
argocd.argoproj.io/sync-wave: "5"Resources with lower sync-wave values are applied first. Resources in the same wave are applied in parallel. ArgoCD waits for each wave to be healthy before applying the next wave.
Sync Hooks
# Pre-deploy hook: run database migration
apiVersion: batch/v1
kind: Job
metadata:
name: db-migrate
namespace: production
annotations:
argocd.argoproj.io/hook: PreSync
argocd.argoproj.io/hook-weight: "1"
argocd.argoproj.io/hook-delete-policy: HookSucceeded
spec:
template:
spec:
containers:
- name: migrate
image: ghcr.io/myorg/myapp:2.0.0
command: ["npm", "run", "migrate"]
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: myapp-secrets
key: database-url
restartPolicy: Never
backoffLimit: 1
---
# Post-deploy hook: notify deployment
apiVersion: batch/v1
kind: Job
metadata:
name: notify-deploy
namespace: production
annotations:
argocd.argoproj.io/hook: PostSync
argocd.argoproj.io/hook-weight: "2"
argocd.argoproj.io/hook-delete-policy: HookSucceeded
spec:
template:
spec:
containers:
- name: notify
image: curlimages/curl:latest
command:
- sh
- -c
- |
curl -X POST $SLACK_WEBHOOK \
-d '{"text":"Deployed myapp to production"}'
restartPolicy: Never
backoffLimit: 1Sync hooks run at specific points in the sync lifecycle. PreSync hooks run before resources are applied. PostSync hooks run after all resources are synced. HookSucceeded deletes the hook after it succeeds.
Sync Windows
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: production
namespace: argocd
spec:
description: Production applications
sourceRepos:
- "https://github.com/myorg/gitops-repo.git"
destinations:
- namespace: production
server: https://kubernetes.default.svc
clusterResourceWhitelist:
- group: ""
kind: Namespace
namespaceResourceWhitelist:
- group: ""
kind: "*"
syncWindows:
# Allow sync only during business hours
- kind: allow
schedule: "0 9-17 * * 1-5"
duration: 8h
applications:
- "*"
manualSync: true
# Block sync on weekends
- kind: deny
schedule: "0 0 * * 0,6"
duration: 24h
applications:
- "*"
# Emergency override
- kind: allow
schedule: "0 0 * * *"
duration: 24h
applications:
- "emergency-*"
manualSync: trueSync windows control when applications can be synced. The allow window permits sync during business hours (9 AM - 5 PM, weekdays). The deny window blocks sync on weekends. Emergency applications bypass the window.
Health Checks
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cm
namespace: argocd
data:
resource.customizations.health.apps_Deployment: |
hs = {}
hs.status = "Progressing"
hs.message = "Waiting for rollout"
if obj.status ~= nil then
if obj.status.updatedReplicas == obj.spec.replicas and
obj.status.readyReplicas == obj.spec.replicas then
hs.status = "Healthy"
hs.message = "All replicas are ready"
elseif obj.status.unavailableReplicas ~= nil and
obj.status.unavailableReplicas > 0 then
hs.status = "Degraded"
hs.message = obj.status.unavailableReplicas .. " replicas unavailable"
end
end
return hsCustom health checks use Lua scripts to determine resource health. This script checks that all replicas are updated and ready. ArgoCD uses health status to determine if a sync was successful.
Progressive Sync
Progressive sync applies changes to applications one at a time instead of all at once. This limits the blast radius of bad changes and allows verification between each application sync.
Use sync windows to restrict when deploys can happen, and progressive sync to control how they happen. Together, they provide defense-in-depth for production deployments.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.