GitOps transforms infrastructure management from an imperative, error-prone process into a declarative, auditable one. ArgoCD is the de facto GitOps engine for Kubernetes — and with the right architecture, it can manage hundreds of applications across dozens of clusters with zero toil.
This guide covers what we’ve learned building ArgoCD platforms for engineering teams at scale.
Why GitOps? The Business Case
Before diving into ArgoCD specifics, it’s worth being precise about what GitOps delivers:
- Audit trail: Every change to production is a Git commit with an author, timestamp, and message
- Rollback: Revert any deployment to any previous state in seconds — not minutes or hours
- Drift detection: ArgoCD continuously compares Git state to cluster state and alerts on divergence
- Self-service: Developers can deploy by merging a PR — no Kubernetes access required
- Compliance: SOC 2 and ISO 27001 auditors love GitOps. Every production change is documented.
In our experience, teams adopting GitOps reduce deployment-related incidents by 60-80% within the first quarter.
ArgoCD Architecture for Scale
Core Components
┌─────────────────────────────────────────┐
│ ArgoCD Namespace │
│ │
│ ┌──────────────┐ ┌──────────────────┐ │
│ │ API Server │ │ Repo Server │ │
│ │ (WebUI/CLI) │ │ (Git + Helm) │ │
│ └──────────────┘ └──────────────────┘ │
│ ┌──────────────┐ ┌──────────────────┐ │
│ │ App Controller│ │ Redis (Cache) │ │
│ │ (Sync Engine) │ │ │ │
│ └──────────────┘ └──────────────────┘ │
└─────────────────────────────────────────┘
For production, always run ArgoCD with HA configuration:
- API server: 2+ replicas
- Repo server: 2+ replicas (CPU-intensive — Helm rendering)
- Application Controller: 1 replica (stateful, uses sharding for multi-cluster)
Repository Structure
The “app of apps” or “ApplicationSet” pattern is how you manage many applications:
gitops-repo/
├── apps/
│ ├── base/ # Shared base configs
│ └── overlays/
│ ├── staging/
│ └── production/
├── infrastructure/
│ ├── cert-manager/
│ ├── ingress-nginx/
│ └── monitoring/
└── argocd/
├── projects.yaml
└── applicationsets/
├── apps.yaml
└── infrastructure.yaml
ApplicationSets: Managing Many Apps at Once
ApplicationSets are ArgoCD’s superpower. Instead of creating 50 Application resources manually, you define a generator:
# argocd/applicationsets/apps.yaml
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: microservices
namespace: argocd
spec:
generators:
- git:
repoURL: https://github.com/your-org/gitops-repo
revision: HEAD
directories:
- path: "apps/overlays/production/*"
template:
metadata:
name: '{{path.basename}}'
spec:
project: production
source:
repoURL: https://github.com/your-org/gitops-repo
targetRevision: HEAD
path: '{{path}}'
destination:
server: https://kubernetes.default.svc
namespace: '{{path.basename}}'
syncPolicy:
automated:
prune: true # Delete resources removed from Git
selfHeal: true # Revert manual changes
syncOptions:
- CreateNamespace=true
- PrunePropagationPolicy=foreground
With this single ApplicationSet, every directory under apps/overlays/production/ becomes an ArgoCD Application automatically.
Multi-Cluster Management
ArgoCD can manage applications across multiple clusters from a single control plane:
# Register a remote cluster
argocd cluster add production-eks \
--name production-eks \
--kubeconfig ~/.kube/production
# Use in ApplicationSet
spec:
generators:
- matrix:
generators:
- clusters:
selector:
matchLabels:
environment: production
- git:
repoURL: https://github.com/your-org/gitops-repo
directories:
- path: "apps/*"
This generates one Application per service per cluster — fully automated.
Progressive Delivery with Argo Rollouts
Standard Kubernetes Deployments are all-or-nothing. Argo Rollouts enables canary and blue-green strategies:
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: api-server
spec:
replicas: 10
strategy:
canary:
steps:
- setWeight: 10 # Send 10% of traffic to canary
- pause: {duration: 5m}
- setWeight: 30
- pause: {duration: 5m}
- analysis: # Run automated analysis before proceeding
templates:
- templateName: success-rate
- setWeight: 100
selector:
matchLabels:
app: api-server
Combined with Prometheus metrics analysis:
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
name: success-rate
spec:
metrics:
- name: success-rate
interval: 2m
successCondition: result[0] >= 0.95
failureLimit: 3
provider:
prometheus:
address: http://prometheus.monitoring.svc.cluster.local:9090
query: |
sum(rate(http_requests_total{job="api-server",status=~"2.."}[5m])) /
sum(rate(http_requests_total{job="api-server"}[5m]))
If the success rate drops below 95% during rollout, ArgoCD automatically rolls back. Zero manual intervention.
Secrets Management in GitOps
The classic GitOps problem: how do you manage secrets without committing them to Git?
Option 1: Sealed Secrets
# Encrypt a secret with the cluster's public key
kubectl create secret generic my-secret \
--from-literal=password=supersecret \
--dry-run=client -o yaml | \
kubeseal --format yaml > sealed-secret.yaml
# Safe to commit to Git — only the cluster can decrypt it
Option 2: External Secrets Operator (recommended)
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: database-credentials
spec:
refreshInterval: 1h
secretStoreRef:
name: aws-secrets-manager
kind: ClusterSecretStore
target:
name: database-credentials
data:
- secretKey: password
remoteRef:
key: production/database
property: password
ESO pulls secrets from AWS Secrets Manager, GCP Secret Manager, or Vault — and syncs them as Kubernetes Secrets. No secrets in Git, ever.
CI + GitOps Integration
CI (testing, building) and GitOps (deploying) are complementary, not competing:
# GitHub Actions workflow: build + update GitOps repo
name: Build and Deploy
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build and push Docker image
run: |
IMAGE_TAG=${{ github.sha }}
docker build -t ghcr.io/your-org/api:$IMAGE_TAG .
docker push ghcr.io/your-org/api:$IMAGE_TAG
- name: Update GitOps repo
run: |
git clone https://github.com/your-org/gitops-repo
cd gitops-repo
# Update image tag in Kustomization
kustomize edit set image api=ghcr.io/your-org/api:${{ github.sha }}
git commit -am "ci: update api image to ${{ github.sha }}"
git push
ArgoCD detects the commit and syncs automatically. The deployment is fully automated, fully auditable.
What We Typically Find
When we audit engineering teams’ current deployment processes, we consistently find:
- Manual kubectl apply to production (no audit trail, no rollback)
- Secrets in ConfigMaps or .env files in Git
- No drift detection — production drifts from Git silently
- No canary/blue-green — all deploys are big-bang
GitOps with ArgoCD solves all of these. Implementation takes 2-4 weeks depending on existing complexity.
If you’d like KubeAce to design and implement a GitOps platform for your team, schedule a consultation. We can have you from zero to full ArgoCD-managed GitOps in under a month.