ArgoCD
Declarative GitOps continuous delivery tool for Kubernetes
ArgoCD is the most popular GitOps continuous delivery tool for Kubernetes. It automates the deployment of applications to specified target environments, ensuring clusters match the desired state defined in Git.
What you'll learn
- ArgoCD architecture and components
- Installation and configuration strategies
- Application and ApplicationSet patterns
- Progressive delivery with Argo Rollouts
- Multi-cluster and multi-tenant setups
- Enterprise features and RBAC
Related tools
- Argo Rollouts for progressive delivery
- Argo Events for event-driven automation
- Argo Workflows for CI pipelines
- Helm and Kustomize for templating
Why ArgoCD?#
ArgoCD brings declarative, GitOps-based continuous delivery to Kubernetes with enterprise-grade features:
| Feature | Benefit |
|---|---|
| Rich Web UI | Visual application topology and real-time sync status |
| Multi-cluster | Deploy to multiple clusters from a single control plane |
| SSO Integration | OIDC, SAML, LDAP, GitHub, GitLab authentication |
| RBAC | Fine-grained access control with projects and roles |
| Auto-sync | Automatic deployment when Git changes |
| Self-healing | Detect and correct configuration drift |
Architecture#
1┌─────────────────────────────────────────────────────────────────┐2│ ArgoCD Components │3│ │4│ ┌─────────────────┐ ┌─────────────────┐ │5│ │ API Server │◄───►│ Web UI │ │6│ │ (gRPC/REST) │ │ (Dashboard) │ │7│ └────────┬────────┘ └─────────────────┘ │8│ │ │9│ ┌────────▼────────┐ ┌─────────────────┐ │10│ │ Repo Server │ │ Application │ │11│ │ (Git/Helm/Kust) │ │ Controller │ │12│ └─────────────────┘ └────────┬────────┘ │13│ │ │14│ ┌─────────────────┐ ┌────────▼────────┐ │15│ │ Dex (SSO) │ │ Redis Cache │ │16│ └─────────────────┘ └─────────────────┘ │17└─────────────────────────────────────────────────────────────────┘Components#
API Server Exposes the ArgoCD API as gRPC and REST endpoints. Handles authentication, RBAC enforcement, and serves the Web UI.
Repository Server Connects to Git repositories and generates Kubernetes manifests. Supports Helm, Kustomize, Jsonnet, and plain YAML.
Application Controller Monitors running applications and compares the current state against the desired state. Triggers sync operations and manages lifecycle.
Redis Caches Git repository state and application manifests for improved performance.
Dex Provides SSO integration with external identity providers.
Installation#
Using Helm (Recommended)#
1#!/bin/bash2# ArgoCD installation script34# Create namespace5kubectl create namespace argocd67# Add ArgoCD Helm repository8helm repo add argo https://argoproj.github.io/argo-helm9helm repo update1011# Install ArgoCD with custom values12helm install argocd argo/argo-cd \13 --namespace argocd \14 --values argocd-values.yaml \15 --wait1617# Get initial admin password18kubectl -n argocd get secret argocd-initial-admin-secret \19 -o jsonpath="{.data.password}" | base64 -d2021echo "ArgoCD installed successfully"Helm Values Configuration#
1# argocd-values.yaml2global:3 image:4 repository: quay.io/argoproj/argocd5 tag: v2.9.367server:8 replicas: 2910 ingress:11 enabled: true12 ingressClassName: nginx13 hosts:14 - argocd.example.com15 tls:16 - secretName: argocd-tls17 hosts:18 - argocd.example.com1920 config:21 url: https://argocd.example.com22 application.instanceLabelKey: argocd.argoproj.io/instance2324 # OIDC configuration25 oidc.config: |26 name: Okta27 issuer: https://company.okta.com/oauth2/default28 clientID: $oidc.clientId29 clientSecret: $oidc.clientSecret30 requestedScopes: ["openid", "profile", "email", "groups"]3132 # Repository credentials33 repositories: |34 - url: https://github.com/company/gitops-repo.git35 passwordSecret:36 name: github-creds37 key: password38 usernameSecret:39 name: github-creds40 key: username4142 rbacConfig:43 policy.csv: |44 p, role:org-admin, applications, *, */*, allow45 p, role:org-admin, clusters, *, *, allow46 p, role:org-admin, repositories, *, *, allow47 p, role:developer, applications, get, */*, allow48 p, role:developer, applications, sync, */*, allow49 p, role:developer, logs, get, */*, allow50 g, DevOps, role:org-admin51 g, Developers, role:developer52 policy.default: role:readonly5354controller:55 replicas: 156 resources:57 requests:58 cpu: 500m59 memory: 512Mi60 limits:61 cpu: 1000m62 memory: 1Gi6364repoServer:65 replicas: 266 resources:67 requests:68 cpu: 250m69 memory: 256Mi70 limits:71 cpu: 500m72 memory: 512Mi7374redis:75 enabled: true76 resources:77 requests:78 cpu: 100m79 memory: 128Mi8081dex:82 enabled: true8384applicationSet:85 enabled: true86 replicas: 18788notifications:89 enabled: true90 argocdUrl: https://argocd.example.com9192 notifiers:93 service.slack: |94 token: $slack-token95 service.webhook.github: |96 url: https://api.github.com97 headers:98 - name: Authorization99 value: token $github-token100101 triggers:102 trigger.on-sync-succeeded: |103 - when: app.status.sync.status == 'Synced'104 send: [app-sync-succeeded]105 trigger.on-sync-failed: |106 - when: app.status.sync.status == 'Unknown'107 send: [app-sync-failed]108109 templates:110 template.app-sync-succeeded: |111 slack:112 attachments: |113 [{114 "color": "#18be52",115 "title": "{{.app.metadata.name}} synced successfully",116 "fields": [{117 "title": "Repository",118 "value": "{{.app.spec.source.repoURL}}",119 "short": true120 }]121 }]Application Definitions#
Single Application#
1# applications/payment-service.yaml2apiVersion: argoproj.io/v1alpha13kind: Application4metadata:5 name: payment-service6 namespace: argocd7 labels:8 team: payments9 environment: production10 annotations:11 notifications.argoproj.io/subscribe.on-sync-succeeded.slack: payments-deploys12 notifications.argoproj.io/subscribe.on-sync-failed.slack: payments-alerts13 finalizers:14 - resources-finalizer.argocd.argoproj.io15spec:16 project: payments1718 source:19 repoURL: https://github.com/company/gitops-repo.git20 targetRevision: main21 path: apps/payment-service/overlays/production2223 destination:24 server: https://kubernetes.default.svc25 namespace: payments2627 syncPolicy:28 automated:29 prune: true30 selfHeal: true31 allowEmpty: false32 syncOptions:33 - CreateNamespace=true34 - PrunePropagationPolicy=foreground35 - PruneLast=true36 - ApplyOutOfSyncOnly=true37 retry:38 limit: 539 backoff:40 duration: 5s41 factor: 242 maxDuration: 3m4344 ignoreDifferences:45 - group: apps46 kind: Deployment47 jsonPointers:48 - /spec/replicas49 - group: ""50 kind: ConfigMap51 jqPathExpressions:52 - .data.webhook-url5354 revisionHistoryLimit: 10Helm Application#
1apiVersion: argoproj.io/v1alpha12kind: Application3metadata:4 name: prometheus-stack5 namespace: argocd6spec:7 project: infrastructure89 source:10 repoURL: https://prometheus-community.github.io/helm-charts11 chart: kube-prometheus-stack12 targetRevision: 55.0.013 helm:14 releaseName: prometheus15 valueFiles:16 - values.yaml17 - values-production.yaml18 parameters:19 - name: grafana.adminPassword20 value: $grafana-admin-password21 values: |22 prometheus:23 prometheusSpec:24 retention: 30d2526 destination:27 server: https://kubernetes.default.svc28 namespace: monitoring2930 syncPolicy:31 automated:32 prune: true33 selfHeal: trueApp of Apps Pattern#
The App of Apps pattern enables managing multiple applications through a single parent application.
1# applications/root-app.yaml2apiVersion: argoproj.io/v1alpha13kind: Application4metadata:5 name: root-application6 namespace: argocd7spec:8 project: default910 source:11 repoURL: https://github.com/company/gitops-repo.git12 targetRevision: main13 path: applications14 directory:15 recurse: true1617 destination:18 server: https://kubernetes.default.svc19 namespace: argocd2021 syncPolicy:22 automated:23 prune: true24 selfHeal: trueEnvironment-Specific Apps#
1# applications/apps/production-apps.yaml2apiVersion: argoproj.io/v1alpha13kind: Application4metadata:5 name: production-applications6 namespace: argocd7spec:8 project: production910 source:11 repoURL: https://github.com/company/gitops-repo.git12 targetRevision: main13 path: environments/production1415 destination:16 server: https://prod-cluster.example.com17 namespace: argocd1819 syncPolicy:20 automated:21 prune: true22 selfHeal: trueApplicationSets#
ApplicationSets automate the creation of Applications based on generators.
Multi-Environment Deployment#
1apiVersion: argoproj.io/v1alpha12kind: ApplicationSet3metadata:4 name: microservices5 namespace: argocd6spec:7 generators:8 - matrix:9 generators:10 # Cluster generator11 - clusters:12 selector:13 matchLabels:14 environment: production15 # Git directory generator16 - git:17 repoURL: https://github.com/company/gitops-repo.git18 revision: main19 directories:20 - path: apps/*2122 template:23 metadata:24 name: '{{path.basename}}-{{name}}'25 labels:26 app: '{{path.basename}}'27 cluster: '{{name}}'28 spec:29 project: production3031 source:32 repoURL: https://github.com/company/gitops-repo.git33 targetRevision: main34 path: '{{path}}/overlays/{{metadata.labels.environment}}'3536 destination:37 server: '{{server}}'38 namespace: '{{path.basename}}'3940 syncPolicy:41 automated:42 prune: true43 selfHeal: true44 syncOptions:45 - CreateNamespace=truePull Request Preview Environments#
1apiVersion: argoproj.io/v1alpha12kind: ApplicationSet3metadata:4 name: pr-preview-environments5 namespace: argocd6spec:7 generators:8 - pullRequest:9 github:10 owner: company11 repo: application12 tokenRef:13 secretName: github-token14 key: token15 labels:16 - preview17 requeueAfterSeconds: 601819 template:20 metadata:21 name: 'pr-{{number}}-{{branch_slug}}'22 annotations:23 preview-url: 'https://pr-{{number}}.preview.example.com'24 spec:25 project: preview2627 source:28 repoURL: https://github.com/company/application.git29 targetRevision: '{{head_sha}}'30 path: deploy/preview31 helm:32 parameters:33 - name: ingress.host34 value: 'pr-{{number}}.preview.example.com'35 - name: image.tag36 value: 'pr-{{number}}'3738 destination:39 server: https://kubernetes.default.svc40 namespace: 'preview-{{number}}'4142 syncPolicy:43 automated:44 prune: true45 selfHeal: true46 syncOptions:47 - CreateNamespace=trueList Generator#
1apiVersion: argoproj.io/v1alpha12kind: ApplicationSet3metadata:4 name: team-applications5 namespace: argocd6spec:7 generators:8 - list:9 elements:10 - team: payments11 apps: ["payment-api", "payment-worker", "payment-scheduler"]12 - team: users13 apps: ["user-api", "auth-service"]14 - team: orders15 apps: ["order-api", "inventory-service"]1617 template:18 metadata:19 name: '{{team}}-apps'20 spec:21 project: '{{team}}'22 source:23 repoURL: https://github.com/company/{{team}}-services.git24 targetRevision: main25 path: deploy26 destination:27 server: https://kubernetes.default.svc28 namespace: '{{team}}'Projects#
Projects provide logical grouping of applications with access control.
1apiVersion: argoproj.io/v1alpha12kind: AppProject3metadata:4 name: payments5 namespace: argocd6spec:7 description: "Payments team applications"89 # Source repositories allowed10 sourceRepos:11 - https://github.com/company/payments-*.git12 - https://github.com/company/shared-charts.git1314 # Destination clusters and namespaces15 destinations:16 - namespace: payments-*17 server: https://kubernetes.default.svc18 - namespace: payments19 server: https://prod-cluster.example.com2021 # Allowed Kubernetes resources22 clusterResourceWhitelist:23 - group: ''24 kind: Namespace25 - group: 'networking.k8s.io'26 kind: Ingress2728 namespaceResourceBlacklist:29 - group: ''30 kind: Secret31 name: 'production-*'3233 namespaceResourceWhitelist:34 - group: 'apps'35 kind: Deployment36 - group: 'apps'37 kind: StatefulSet38 - group: ''39 kind: Service40 - group: ''41 kind: ConfigMap42 - group: ''43 kind: Secret44 - group: 'batch'45 kind: Job46 - group: 'batch'47 kind: CronJob4849 # Roles within the project50 roles:51 - name: developer52 description: Developer access to payments project53 policies:54 - p, proj:payments:developer, applications, get, payments/*, allow55 - p, proj:payments:developer, applications, sync, payments/*, allow56 - p, proj:payments:developer, applications, action/*, payments/*, allow57 - p, proj:payments:developer, logs, get, payments/*, allow58 groups:59 - payments-developers6061 - name: admin62 description: Admin access to payments project63 policies:64 - p, proj:payments:admin, applications, *, payments/*, allow65 - p, proj:payments:admin, repositories, *, payments/*, allow66 groups:67 - payments-admins6869 # Sync windows for controlled deployments70 syncWindows:71 - kind: allow72 schedule: '0 6-18 * * 1-5' # Weekdays 6am-6pm73 duration: 12h74 applications:75 - '*'76 namespaces:77 - '*'78 - kind: deny79 schedule: '0 18-6 * * *' # Nights80 duration: 12h81 applications:82 - '*-production'83 manualSync: true8485 # Orphaned resources monitoring86 orphanedResources:87 warn: true88 ignore:89 - group: ''90 kind: ConfigMap91 name: kube-root-ca.crtArgo Rollouts Integration#
Argo Rollouts provides progressive delivery strategies for ArgoCD.
Canary Deployment#
1apiVersion: argoproj.io/v1alpha12kind: Rollout3metadata:4 name: payment-service5 namespace: payments6spec:7 replicas: 108 revisionHistoryLimit: 5910 selector:11 matchLabels:12 app: payment-service1314 template:15 metadata:16 labels:17 app: payment-service18 spec:19 containers:20 - name: payment-service21 image: company/payment-service:v1.0.022 ports:23 - containerPort: 808024 resources:25 requests:26 cpu: 100m27 memory: 128Mi28 limits:29 cpu: 500m30 memory: 512Mi31 livenessProbe:32 httpGet:33 path: /health34 port: 808035 initialDelaySeconds: 3036 periodSeconds: 1037 readinessProbe:38 httpGet:39 path: /ready40 port: 808041 initialDelaySeconds: 542 periodSeconds: 54344 strategy:45 canary:46 # Traffic routing with Istio47 trafficRouting:48 istio:49 virtualService:50 name: payment-service-vsvc51 routes:52 - primary53 destinationRule:54 name: payment-service-destrule55 canarySubsetName: canary56 stableSubsetName: stable5758 # Canary steps59 steps:60 - setWeight: 561 - pause: { duration: 2m }62 - setWeight: 1063 - pause: { duration: 5m }64 - setWeight: 2565 - pause: { duration: 10m }66 - setWeight: 5067 - pause: { duration: 15m }68 - setWeight: 7569 - pause: { duration: 10m }70 - setWeight: 1007172 # Analysis for automated promotion/rollback73 analysis:74 templates:75 - templateName: success-rate76 - templateName: latency77 startingStep: 278 args:79 - name: service-name80 value: payment-service8182 maxUnavailable: 183 maxSurge: 2Analysis Templates#
1apiVersion: argoproj.io/v1alpha12kind: AnalysisTemplate3metadata:4 name: success-rate5 namespace: payments6spec:7 args:8 - name: service-name9 metrics:10 - name: success-rate11 interval: 1m12 count: 1013 successCondition: result[0] >= 0.9914 failureLimit: 315 provider:16 prometheus:17 address: http://prometheus.monitoring:909018 query: |19 sum(rate(20 http_requests_total{21 service="{{args.service-name}}",22 status=~"2.."23 }[5m]24 )) / sum(rate(25 http_requests_total{26 service="{{args.service-name}}"27 }[5m]28 ))2930---31apiVersion: argoproj.io/v1alpha132kind: AnalysisTemplate33metadata:34 name: latency35 namespace: payments36spec:37 args:38 - name: service-name39 metrics:40 - name: p99-latency41 interval: 1m42 count: 1043 successCondition: result[0] <= 50044 failureLimit: 345 provider:46 prometheus:47 address: http://prometheus.monitoring:909048 query: |49 histogram_quantile(0.99,50 sum(rate(51 http_request_duration_seconds_bucket{52 service="{{args.service-name}}"53 }[5m]54 )) by (le)55 ) * 1000Blue-Green Deployment#
1apiVersion: argoproj.io/v1alpha12kind: Rollout3metadata:4 name: payment-api-bluegreen5 namespace: payments6spec:7 replicas: 589 selector:10 matchLabels:11 app: payment-api1213 template:14 metadata:15 labels:16 app: payment-api17 spec:18 containers:19 - name: payment-api20 image: company/payment-api:v2.0.021 ports:22 - containerPort: 80802324 strategy:25 blueGreen:26 activeService: payment-api-active27 previewService: payment-api-preview28 autoPromotionEnabled: false29 scaleDownDelaySeconds: 30030 previewReplicaCount: 231 prePromotionAnalysis:32 templates:33 - templateName: smoke-tests34 args:35 - name: service-name36 value: payment-api-preview37 postPromotionAnalysis:38 templates:39 - templateName: success-rate40 args:41 - name: service-name42 value: payment-api-activeNotifications#
Configure notifications for deployment events.
1apiVersion: v12kind: ConfigMap3metadata:4 name: argocd-notifications-cm5 namespace: argocd6data:7 service.slack: |8 token: $slack-token910 template.app-deployed: |11 message: |12 Application {{.app.metadata.name}} is now running version {{.app.status.sync.revision}}.13 slack:14 attachments: |15 [{16 "color": "#18be52",17 "title": "{{.app.metadata.name}}",18 "title_link": "{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",19 "fields": [{20 "title": "Sync Status",21 "value": "{{.app.status.sync.status}}",22 "short": true23 }, {24 "title": "Repository",25 "value": "{{.app.spec.source.repoURL}}",26 "short": true27 }]28 }]2930 trigger.on-deployed: |31 - when: app.status.operationState.phase in ['Succeeded'] and app.status.health.status == 'Healthy'32 send: [app-deployed]3334 trigger.on-sync-failed: |35 - when: app.status.operationState.phase in ['Failed', 'Error']36 send: [app-sync-failed]3738 template.app-sync-failed: |39 message: |40 Application {{.app.metadata.name}} sync failed.41 Error: {{.app.status.operationState.message}}42 slack:43 attachments: |44 [{45 "color": "#E96D76",46 "title": "{{.app.metadata.name}} sync failed",47 "title_link": "{{.context.argocdUrl}}/applications/{{.app.metadata.name}}",48 "fields": [{49 "title": "Error",50 "value": "{{.app.status.operationState.message}}",51 "short": false52 }]53 }]Best Practices#
Repository Structure#
1gitops-repo/2├── apps/3│ ├── base/4│ │ └── payment-service/5│ │ ├── deployment.yaml6│ │ ├── service.yaml7│ │ └── kustomization.yaml8│ └── overlays/9│ ├── dev/10│ ├── staging/11│ └── production/12├── infrastructure/13│ ├── cert-manager/14│ ├── ingress-nginx/15│ └── monitoring/16├── clusters/17│ ├── dev/18│ ├── staging/19│ └── production/20└── applications/21 ├── root-app.yaml22 └── applicationsets/Security Recommendations#
- Enable RBAC - Use projects and roles to limit access
- SSO Integration - Use OIDC/SAML instead of local accounts
- Sync Windows - Restrict production deployments to business hours
- Secret Management - Use Sealed Secrets or External Secrets Operator
- Network Policies - Limit ArgoCD's network access
Performance Tuning#
- Repository Caching - Enable Git repository caching
- Manifest Generation Caching - Cache rendered manifests
- Increase Repo Server Replicas - For large deployments
- Resource Limits - Set appropriate limits for controllers