DevOps · ArgoCD|11 min read|

Advanced Kubernetes Deployment Patterns with ArgoCD

ArgoCD goes far beyond syncing Kubernetes manifests. Teams using ArgoCD only as 'automatic kubectl apply' aren't leveraging the capabilities that make it the most powerful deployment orchestrator in the Kubernetes ecosystem. This guide covers advanced patterns: sync waves for ordering complex deployments, resource hooks for pre and post-sync operations, ApplicationSets for managing dozens of clusters from a single repository.

Sync Waves: ordering complex deployments

A complex application deployment can have dependencies: the database must be available before the API starts, the API must be available before the worker starts, migrations must complete before new code starts serving traffic. Sync Waves let you define the creation order of resources within an ArgoCD Application.

yaml
# Wave 0: CRDs and namespaces — always first
apiVersion: v1
kind: Namespace
metadata:
  name: production
  annotations:
    argocd.argoproj.io/sync-wave: "0"
---
# Wave 1: ConfigMaps and Secrets — before Deployments
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
  annotations:
    argocd.argoproj.io/sync-wave: "1"
---
# Wave 2: Deployments and StatefulSets
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
  annotations:
    argocd.argoproj.io/sync-wave: "2"
---
# Wave 3: Ingress — after services are ready
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: api-ingress
  annotations:
    argocd.argoproj.io/sync-wave: "3"

Resource Hooks: pre and post-sync operations

yaml
# PreSync hook — run migrations before deployment
apiVersion: batch/v1
kind: Job
metadata:
  name: db-migration
  annotations:
    argocd.argoproj.io/hook: PreSync
    argocd.argoproj.io/hook-delete-policy: HookSucceeded
spec:
  template:
    spec:
      restartPolicy: Never
      containers:
      - name: migrate
        image: company/api:latest
        command: ["npm", "run", "db:migrate"]

ApplicationSets: managing multiple clusters and environments

yaml
# ApplicationSet — deploy same service across multiple clusters
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: api-all-clusters
  namespace: argocd
spec:
  generators:
  - matrix:
      generators:
      - clusters:
          selector:
            matchLabels:
              region: latam
      - list:
          elements:
          - env: staging
          - env: production
  template:
    metadata:
      name: 'api-{{name}}-{{env}}'
    spec:
      source:
        path: 'apps/api/{{env}}'
      destination:
        server: '{{server}}'
        namespace: '{{env}}'

External Secrets Operator: the right secrets pattern

yaml
# ExternalSecret — sync from AWS Secrets Manager
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: db-credentials
  namespace: production
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: aws-secrets-manager
    kind: ClusterSecretStore
  target:
    name: db-credentials
  data:
  - secretKey: DATABASE_URL
    remoteRef:
      key: prod/api/database
      property: url
External Secrets Operator rotates secrets automatically — when you update the value in AWS Secrets Manager or Vault, ESO syncs the change to the Kubernetes Secret within the refreshInterval. No redeploy required.

Custom diff: ignoring runtime-changed fields

yaml
spec:
  ignoreDifferences:
  - group: apps
    kind: Deployment
    jsonPointers:
    - /spec/replicas     # ignore replicas managed by HPA

Frequently Asked Questions

How many Applications can ArgoCD manage before performance degrades?
ArgoCD scales well to 1,000-2,000 Applications on a standard server. For more than that, the recommended architecture is ArgoCD with multiple Application Controllers (sharding) or one ArgoCD instance per managed cluster. In practice, enterprises that experience performance issues rarely exceed 500 Applications — the problem is usually sync frequency, not Application count.
How do I manage ArgoCD RBAC so each team only sees their applications?
By combining AppProjects and RBAC. Each team has an AppProject restricting allowed repos, clusters, and namespaces. ArgoCD RBAC (argocd-rbac-cm configmap) assigns roles to teams: p, role:team-payments, applications, *, payments-*/*, allow. This lets the payments team manage their Applications without seeing the user team's.
What happens with stateful applications (databases) in ArgoCD?
ArgoCD manages StatefulSets correctly, but the update strategy for databases requires more care than for stateless applications. For databases in Kubernetes (PostgreSQL with CloudNativePG, Redis with operators), it's common to use resource hooks to control the operator update process and verify cluster health before proceeding.
How do I implement automatic rollback if a PostSync hook fails?
ArgoCD doesn't auto-rollback when a hook fails — it marks the Application as Degraded and stops sync. For real automatic rollback, you need Argo Rollouts integrated with ArgoCD. Argo Rollouts can rollback automatically based on Prometheus metrics (error rate, latency) without manual intervention, far more sophisticated than a simple hook failure rollback.
Is ArgoCD Image Updater necessary, or is it better to update images from the CI pipeline?
From the CI pipeline is the most predictable and auditable approach — every image update has a Git commit with an identified author. ArgoCD Image Updater (detecting new registry images and auto-updating) is useful for development environments where you want automatic deploys on every push, but in production the visibility of the CI pipeline is preferable.

Does your team want to implement advanced deployment patterns with ArgoCD in production? We have experience operating ArgoCD in enterprise clusters.

Talk to our team

Related articles

IQS

Engineering Team — IQS

Software, cloud, and DevOps engineers with enterprise project experience.