ArgoCD
02 / 02

App of Apps, Sync Waves & Multi-Tenancy

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: true

Sync 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: Never

AppProject: 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 themselves

Why 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