ArgoCD: App of Apps, Sync Waves & Multi-Tenancy
App of Apps Pattern
# A root Application whose git source contains OTHER Application
# manifests -- syncing the root bootstraps an entire fleet from one
# git-tracked entry point, instead of manually creating each Application.
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: root-app
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/myorg/manifests.git
targetRevision: main
path: applications # this directory contains child Application YAMLs
destination:
server: https://kubernetes.default.svc
namespace: argocd
syncPolicy:
automated:
prune: true
selfHeal: trueSync Waves & Hooks -- Ordering
# Sync wave -- controls the ORDER resources apply in, within one Application
apiVersion: v1
kind: Namespace
metadata:
name: my-app
annotations:
argocd.argoproj.io/sync-wave: "-1" # applied before wave 0
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-api
annotations:
argocd.argoproj.io/sync-wave: "0" # default wave
# Sync hook -- runs at a specific point in the sync LIFECYCLE, not just order
apiVersion: batch/v1
kind: Job
metadata:
name: db-migration
annotations:
argocd.argoproj.io/hook: PreSync # runs before the main sync applies
argocd.argoproj.io/hook-delete-policy: HookSucceeded
spec:
template:
spec:
containers:
- name: migrate
image: myapp/migrate:latest
restartPolicy: NeverAppProject: Multi-Tenant Guardrails
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: team-payments
namespace: argocd
spec:
description: Payments team applications
sourceRepos:
- https://github.com/myorg/payments-manifests.git
destinations:
- server: https://kubernetes.default.svc
namespace: payments-* # restricted to this team's namespaces
clusterResourceWhitelist:
- group: ''
kind: Namespace
namespaceResourceBlacklist:
- group: ''
kind: ResourceQuota # this team can't modify quotas themselvesWhy Pull-Based GitOps (Security Model)
CI builds/tests/pushes an image and commits a new tag to the manifests repo -- CI never gets direct deploy credentials to the cluster.
ArgoCD lives inside the cluster and only needs read access to git -- pull model, not push.
A compromised CI pipeline can at most alter what's committed to git (still goes through PR review), not directly push into production infrastructure.
selfHeal enforces git as the true source of truth even against a direct kubectl edit made by someone with cluster access.
Keep your own version of these notes — editable, searchable, and organised by your stack.
Start free