Argocd Advanced Patterns

Production engineering guide for argocd advanced patterns covering patterns, implementation strategies, and operational best practices.

ArgoCD is a GitOps continuous delivery tool for Kubernetes that excels at declarative, self-healing deployments. This page details advanced patterns for scaling ArgoCD across teams, environments, and complex applications, where the default setup becomes insufficient. These patterns address coordination across multiple repositories, versioned configurations, automated rollbacks, and hybrid deployment strategies. Use these when your fleet grows beyond a single Git repository and a flat cluster/ directory, and when teams need autonomy, consistency, and observability in their delivery workflows.

Multi-Repository, Multi-Cluster Topologies

When teams own independent services or applications, centralizing all manifests in one repo becomes unwieldy. Use a multi-repository model where each service lives in its own Git repository, each synced to its own ArgoCD application.

Each service repository contains its own argocd.yaml or argocd/ directory with a Application custom resource. The Application CR defines the sync source and target cluster.


apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: service-a
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/acme/service-a.git
    targetRevision: HEAD
    path: k8s
  destination:
    server: https://kubernetes.default.svc
    namespace: service-a-prod
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true
      - ApplyOutOfTreeResources=true

To manage multiple such applications, use ArgoCD’s ApplicationSet controller. It generates Application resources dynamically based on a template and a list of sources.

# argocd/applicationset.yaml
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: multi-service-apps
spec:
  generate:
    from:
      - list:
          elements:
            - cluster: prod
              repo: https://github.com/acme/service-a.git
              path: k8s
              namespace: service-a-prod
            - cluster: staging
              repo: https://github.com/acme/service-b.git
              path: k8s
              namespace: service-b-staging
    template:
      spec:
        project: default
        source:
          repoURL: '{{ .repo }}'
          targetRevision: HEAD
          path: '{{ .path }}'
        destination:
          server: https://kubernetes.default.svc
          namespace: '{{ .namespace }}'
        syncPolicy:
          automated:
            prune: true
            selfHeal: true

The ApplicationSet controller watches for changes in the source list and reconciles Application resources accordingly. This enables zero-touch provisioning of new services across clusters.

A common failure: ApplicationSet generates applications, but Application CRs are not properly reconciled. The ApplicationSet controller logs failed to create Application: application.argoproj.io "service-a-prod" already exists, but the Application object is not updated. The fix is to ensure ApplicationSet runs with syncOptions: [CreateNamespace=true] and Application CRs are not manually created.

Versioned Configuration with GitOps

When teams need to version configurations independently of code, use a config/ directory in the application repository. Each version is a Git branch or tag, and ArgoCD syncs to a specific version.

Set up a config/ directory with config/v1.2.0/, config/v1.3.0/, and so on. Each contains a k8s/ directory with Kubernetes manifests.

In Application CR:

spec:
  source:
    repoURL: https://github.com/acme/service-a.git
    targetRevision: v1.3.0
    path: config/v1.3.0/k8s
  syncPolicy:
    automated:
      selfHeal: true
      prune: true
    syncOptions:
      - ApplyOutOfTreeResources=true
      - CreateNamespace=true
      - SyncFromRevision=1.3.0

To promote a configuration version across environments, use a version.yaml file that defines the current version per environment.

# config/staging/version.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: config-version
  namespace: argocd
data:
  version: v1.3.0
  environment: staging

A ApplicationSet can use this to drive version promotion:

template:
  spec:
    source:
      repoURL: '{{ .repo }}'
      targetRevision: '{{ .version }}'
      path: config/{{ .version }}/k8s
    destination:
      server: '{{ .server }}'
      namespace: '{{ .namespace }}'

Failures in this pattern:

Automated Rollbacks on Health Check Failure

ArgoCD monitors application health via conditions and status. Use HealthCheck annotations and PostSync hooks to trigger rollbacks when a service fails.

In Deployment YAML:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: service-a
  annotations:
    argocd.argoproj.io/hook: PreSync,PostSync
    argocd.argoproj.io/hook-delete-policy: HookSucceeded
spec:
  template:
    metadata:
      annotations:
        argocd.argoproj.io/health-check: |
          {
            "type": "liveness",
            "path": "/health",
            "interval": "30s",
            "timeout": "10s"
          }

The HealthCheck annotation defines how ArgoCD checks the health of a resource. The PostSync hook runs after a sync and can trigger rollbacks.

# argocd/rollbacks/rollout-deployment.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: service-a
spec:
  syncPolicy:
    automated:
      selfHeal: true
      prune: true
      syncOptions:
        - ApplyOutOfTreeResources=true
        - CreateNamespace=true
        - SyncFromRevision=HEAD
    syncOptions:
      - RollbackOnFailure=true
      - CreateNamespace=true
      - ApplyOutOfTreeResources=true
      - SyncFromRevision=HEAD

When a Deployment fails health checks for 10 minutes, ArgoCD triggers a rollback. The RollbackOnFailure sync option causes ArgoCD to:

  1. Record the failed revision.
  2. Sync the Application to the previous revision.
  3. Update status.phase to Progressing and status.conditions with type: Rollback, status: True, message: Rolling back to revision <prev>.

A silent failure: RollbackOnFailure is set, but the Application does not roll back after a sync failure. The reason is that status.conditions must include type: Health, status: False, lastTransitionTime, and message. ArgoCD checks status.conditions and only considers a health check failure if the Health condition is False for at least syncPolicy.rolloutDuration.

To verify, use kubectl get application service-a -o yaml and check status.conditions:

status:
  conditions:
    - type: Health
      status: False
      lastTransitionTime: "2024-04-15T10:00:00Z"
      message: "Deployment is not ready after 10 minutes"

Hybrid Deployment: Canary with Blue-Green

Combine canary and blue-green deployments using ArgoCD’s Rollout support and ApplicationSet.

Start with a Deployment for service-a and a Rollout resource that manages canary and stable versions.

# k8s/rollout.yaml
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: service-a
spec:
  replicas: 5
  selector:
    matchLabels:
      app: service-a
  template:
    metadata:
      labels:
        app: service-a
    spec:
      containers:
        - name: app
          image: acme/service-a:v1.2.0
          ports:
            - containerPort: 8080
  strategy:
    canary:
      canaryService: service-a-canary
      stableService: service-a-stable
      steps:
        - setWeight: 20
        - pause: {}
        - setWeight: 50
        - pause: {}
        - setWeight: 100

Use ApplicationSet to drive canary promotion across clusters:

template:
  spec:
    source:
      repoURL: https://github.com/acme/service-a.git
      targetRevision: v1.3.0
      path: k8s
    destination:
      server: https://kubernetes.default.svc
      namespace: service-a-prod
    syncPolicy:
      automated:
        syncOptions:
          - ApplyOutOfTreeResources=true
          - CreateNamespace=true
          - SyncFromRevision=v1.3.0
          - RollbackOnFailure=true
      syncOptions:
        - RolloutDuration=300s

A common edge: Rollout resource is not in the Application source path. ArgoCD syncs Deployment, but the Rollout CR is not applied. The fix is to ensure k8s/rollout.yaml is included in the Application sync path.

Another edge: Rollout steps are not applied. ArgoCD logs Rollout is not progressing: step 1 not applied. The cause is that Rollout CR is not watched by ArgoCD. Add argocd.argoproj.io/hook: PostSync to Rollout metadata.

metadata:
  annotations:
    argocd.argoproj.io/hook: PostSync

When Rollout is synced, ArgoCD applies the Rollout resource and starts the rollout process. The Rollout controller updates status and conditions in the Rollout object.

Check kubectl get rollout service-a -o yaml:

status:
  phase: Progressing
  conditions:
    - type: Progressing
      status: True
      reason: NewReplicaSetAvailable
      message: "Rollout is progressing"
    - type: Available
      status: False
      reason: MinimumReplicasAvailable
      message: "Minimum replicas available"

Observability and Debugging

ArgoCD exposes rich status information via kubectl get application, kubectl describe application, and argocd app get <name>.

Common issues and their fixes:

Check status.conditions:

  status:
    conditions:
      - type: Sync
        status: True
        lastTransitionTime: "2024-04-15T10:00:00Z"
        message: "Synced to revision v1.3.0"
      - type: Health
        status: False
        lastTransitionTime: "2024-04-15T10:05:00Z"
        message: "Deployment is not ready"

The Health condition is the source of truth. Set syncPolicy.syncOptions to include SyncFromRevision=HEAD.

Run argocd app diff service-a:

  argocd app diff service-a
  # Output shows:
  #   - resource: Deployment/service-a
  #     status: OutOfSync
  #     reason: "Spec has changed"

The diff output reveals changes in spec.replicas, spec.template.spec.containers, and spec.selector.matchLabels. Manually sync with argocd app sync service-a --prune.

Check argocd app logs service-a:

  argocd app logs service-a --tail=100
  # Output shows:
  #   INFO[2024-04-15T10:10:00Z] Syncing application service-a to revision v1.2.0
  #   INFO[2024-04-15T10:10:30Z] Application service-a synced successfully
  #   INFO[2024-04-15T10:11:00Z] Rolling back application service-a to revision v1.2.0
  #   ERROR[2024-04-15T10:11:05Z] Failed to rollback: failed to apply manifest: error parsing YAML

The error is often in a ConfigMap or Secret not applied correctly. Use kubectl get configmap -n argocd -o yaml to inspect the argocd-cm ConfigMap for syncOptions and applicationSet.

Use argocd app get service-a -o yaml to inspect the full state. The status section contains all the information needed to debug sync, health, and rollout issues.

These patterns form a robust foundation for ArgoCD at scale. They are not features but practices built on the core principles of GitOps: declarative configuration, versioned state, and automated reconciliation.

This page was rewritten on 15 October 2026. It replaced a templated version that was not specific to its own title. How these pages are written and checked. If anything here is wrong, tell us at [email protected] and we will correct it.