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.
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.
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:
targetRevision: v1.3.0 fails to sync when v1.3.0 is a tag, not a branch. ArgoCD logs Error: git fetch error: branch v1.3.0 not found. The solution is to set source.repoURL to https://github.com/acme/service-a.git and ensure targetRevision is a tag, or use source.revision: v1.3.0 with source.ref: v1.3.0.SyncFromRevision is not applied when the Application is created. The SyncFromRevision field is only used during the initial sync and not on subsequent changes. For full versioning, use syncPolicy.syncOptions with SyncFromRevision=v1.3.0.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:
Application to the previous revision.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"
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"
ArgoCD exposes rich status information via kubectl get application, kubectl describe application, and argocd app get <name>.
Common issues and their fixes:
status.phase is Synced 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.
targetRevision is correct 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.
We use cookies for analytics (Google Analytics) and advertising (Google AdSense) to improve your experience and support free content. Privacy Policy