GitOps für Infrastruktur: ArgoCD-Patterns und Fallstricke
GitOps mit ArgoCD für Kubernetes: Application-of-Applications, Secret-Handling, Drift-Erkennung, Multi-Cluster-Sync und progressive Rollouts.

GitOps macht Git zur einzigen Quelle der Wahrheit für den Infrastrukturzustand. Statt kubectl apply auszuführen oder durch Dashboards zu klicken, committest du Manifeste in ein Repository und ein Reconciliation-Controller—ArgoCD—stellt sicher, dass der Cluster dem in Git Deklarierten entspricht. Wenn jemand etwas manuell im Cluster ändert, erkennt ArgoCD die Drift und korrigiert sie.
Das klingt einfach, aber GitOps in der Produktion hat scharfe Kanten. Secret-Management, Multi-Cluster-Koordination, progressive Rollouts und die Reihenfolge von Anwendungsabhängigkeiten erfordern Patterns, die über die Grundlagentutorials hinausgehen.
Application-of-Applications-Pattern
Die einzelne Verwaltung Dutzender ArgoCD-Applications skaliert nicht. Das App-of-Apps-Pattern verwendet eine übergeordnete Application, die untergeordnete Applications deklarativ verwaltet.
# ❌ Jede App manuell über CLI verwalten
# argocd app create frontend --repo https://... --path frontend
# argocd app create backend --repo https://... --path backend
# argocd app create monitoring --repo https://... --path monitoring
# Skaliert nicht, keine Audit-Trail, kein deklaratives Management# ✅ Übergeordnete Application, die alle untergeordneten Apps verwaltet
# root-app/application.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: platform-root
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/org/platform-apps
targetRevision: main
path: apps
destination:
server: https://kubernetes.default.svc
namespace: argocd
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true# apps/frontend.yaml — untergeordnete Application
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: frontend
namespace: argocd
annotations:
argocd.argoproj.io/sync-wave: "2"
spec:
project: default
source:
repoURL: https://github.com/org/platform-apps
targetRevision: main
path: manifests/frontend
helm:
valueFiles:
- values.yaml
- values-production.yaml
destination:
server: https://kubernetes.default.svc
namespace: frontend
syncPolicy:
automated:
prune: true
selfHeal: trueSync Waves steuern die Reihenfolge: Infrastruktur (wave: 0) wird vor Datenbanken (wave: 1) bereitgestellt, und diese wiederum vor Anwendungen (wave: 2). Das verhindert Ausfälle durch fehlende Abhängigkeiten.
Secret-Management ohne Secrets in Git zu speichern
Das grundlegende Spannungsfeld in GitOps: Alles sollte in Git liegen, aber Secrets dürfen nicht in Git liegen. Mehrere Patterns lösen dies.
// Ansatz 1: Sealed Secrets — Secrets für die Speicherung in Git verschlüsseln
interface SealedSecretWorkflow {
steps: string[];
}
const sealedSecretsApproach: SealedSecretWorkflow = {
steps: [
// 1. Ein reguläres Kubernetes-Secret erstellen
"kubectl create secret generic db-creds --from-literal=password=s3cure --dry-run=client -o yaml > secret.yaml",
// 2. Mit dem öffentlichen Schlüssel des Clusters verschlüsseln
"kubeseal --format yaml < secret.yaml > sealed-secret.yaml",
// 3. Die verschlüsselte Version in Git committen
"git add sealed-secret.yaml && git commit -m 'Add db credentials'",
// 4. ArgoCD wendet sie an; der Controller entschlüsselt im Cluster
],
};
// Ansatz 2: External Secrets Operator — aus einem Vault referenzieren
// external-secret.yaml
const externalSecretManifest = `
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: db-credentials
namespace: backend
spec:
refreshInterval: 1h
secretStoreRef:
name: vault-backend
kind: ClusterSecretStore
target:
name: db-credentials
creationPolicy: Owner
data:
- secretKey: username
remoteRef:
key: production/database
property: username
- secretKey: password
remoteRef:
key: production/database
property: password
`;External Secrets Operator ist das bessere langfristige Pattern. Es entkoppelt den Secret-Lebenszyklus vom Deployment-Lebenszyklus—Secrets rotieren im Vault, ohne dass Git-Commits nötig sind.
Drift-Erkennung und Self-Healing
ArgoCD vergleicht kontinuierlich den Sollzustand (Git) mit dem Istzustand (Cluster). Wenn diese voneinander abweichen, kann es alarmieren oder automatisch korrigieren.
interface DriftPolicy {
autoSync: boolean;
selfHeal: boolean;
prune: boolean;
allowedDrift: DriftException[];
}
interface DriftException {
group: string;
kind: string;
jsonPointers: string[];
}
// Festlegen, welche Felder abweichen dürfen
// (von Controllern verwaltet, nicht von Menschen)
const driftPolicy: DriftPolicy = {
autoSync: true,
selfHeal: true,
prune: true,
allowedDrift: [
{
// HPA modifiziert die Replikanzahl
group: "apps",
kind: "Deployment",
jsonPointers: ["/spec/replicas"],
},
{
// Cert-manager aktualisiert TLS-Secrets
group: "",
kind: "Secret",
jsonPointers: ["/data"],
},
],
};
// Zugehörige ArgoCD-Application-Konfiguration
const ignoreDifferences = `
spec:
ignoreDifferences:
- group: apps
kind: Deployment
jsonPointers:
- /spec/replicas
- group: ""
kind: Secret
jsonPointers:
- /data/tls.crt
- /data/tls.key
`;Ohne ignoreDifferences kämpft ArgoCD ständig mit dem Horizontal Pod Autoscaler: ArgoCD setzt die Replikate auf den Git-Wert, HPA ändert sie sofort, ArgoCD erkennt die Drift und setzt sie zurück. Diese Schleife ist einer der häufigsten ArgoCD-Fallstricke.
Multi-Cluster-Sync-Strategie
Produktives GitOps umfasst in der Regel mehrere Cluster: Staging, Produktion und manchmal regionale Cluster. Die Struktur des Git-Repositories muss umgebungsspezifische Konfigurationen unterstützen.
interface MultiClusterConfig {
structure: "directory-per-env" | "branch-per-env" | "overlay";
}
// Empfohlen: Kustomize-Overlays
const repoStructure = {
"base/": {
"deployment.yaml": "Base deployment manifest",
"service.yaml": "Base service manifest",
"kustomization.yaml": "Base kustomization",
},
"overlays/staging/": {
"kustomization.yaml": `
bases:
- ../../base
patches:
- replica-count.yaml
configMapGenerator:
- name: app-config
literals:
- LOG_LEVEL=debug
- API_URL=https://api.staging.example.com
`,
},
"overlays/production/": {
"kustomization.yaml": `
bases:
- ../../base
patches:
- replica-count.yaml
- resource-limits.yaml
configMapGenerator:
- name: app-config
literals:
- LOG_LEVEL=warn
- API_URL=https://api.example.com
`,
},
};
// ArgoCD ApplicationSet für Multi-Cluster
const applicationSet = `
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: backend-service
namespace: argocd
spec:
generators:
- list:
elements:
- cluster: staging
url: https://staging-k8s.internal
overlay: staging
- cluster: production
url: https://prod-k8s.internal
overlay: production
template:
metadata:
name: 'backend-{{cluster}}'
spec:
source:
repoURL: https://github.com/org/platform-apps
targetRevision: main
path: 'manifests/backend/overlays/{{overlay}}'
destination:
server: '{{url}}'
namespace: backend
`;ApplicationSets generieren Applications aus Templates, reduzieren Duplikate und stellen Konsistenz über Cluster hinweg sicher. Jede Umgebung erhält dieselben Basis-Manifeste mit umgebungsspezifischen Overlays.
Integration progressiver Rollouts
GitOps mit ArgoCD lässt sich gut mit Argo Rollouts für progressive Bereitstellung kombinieren. Statt alle Pods auf einmal zu ersetzen, wird der Traffic schrittweise mit automatisierter Analyse umgeleitet.
# rollout.yaml — ersetzt das Deployment
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: backend-api
namespace: backend
spec:
replicas: 10
strategy:
canary:
steps:
- setWeight: 5
- pause: { duration: 5m }
- analysis:
templates:
- templateName: success-rate-check
- setWeight: 25
- pause: { duration: 10m }
- analysis:
templates:
- templateName: success-rate-check
- setWeight: 50
- pause: { duration: 10m }
- setWeight: 100
canaryService: backend-api-canary
stableService: backend-api-stable
selector:
matchLabels:
app: backend-api
template:
metadata:
labels:
app: backend-api
spec:
containers:
- name: api
image: registry.example.com/backend:v2.1.0# analysis-template.yaml
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
name: success-rate-check
spec:
metrics:
- name: success-rate
interval: 60s
successCondition: result[0] > 0.99
provider:
prometheus:
address: http://prometheus.monitoring:9090
query: |
sum(rate(http_requests_total{
service="backend-api",
status=~"2.."
}[5m])) /
sum(rate(http_requests_total{
service="backend-api"
}[5m]))Ein Git-Commit aktualisiert den Image-Tag, ArgoCD synct den Rollout, und Argo Rollouts leitet den Traffic schrittweise um. Wenn das Analyse-Template verschlechterte Erfolgsraten erkennt, rollt es automatisch zurück—ohne menschliches Zutun.
Wichtige Erkenntnisse
GitOps mit ArgoCD macht Git zur einzigen Quelle der Wahrheit für die Infrastruktur, bietet Audit-Trails, Rollback per git revert und deklaratives Cluster-Management. Verwende das App-of-Apps-Pattern mit Sync Waves, um Dutzende Anwendungen in der richtigen Abhängigkeitsreihenfolge zu verwalten. Verwende External Secrets Operator oder Sealed Secrets für Secrets—speichere niemals Klartext-Anmeldeinformationen in Git. Konfiguriere ignoreDifferences für Felder, die von Cluster-Controllern wie HPA und cert-manager verwaltet werden, um Reconciliation-Loops zu vermeiden. Strukturiere Multi-Cluster-Konfigurationen mit Kustomize-Overlays und ApplicationSets, um umgebungsspezifische Anwendungen aus Templates zu generieren. Integriere Argo Rollouts für progressive Bereitstellung, die Canary-Metriken automatisch analysiert und bei Degradation zurückrollt. Das Ziel ist ein System, bei dem ein git revert dein Disaster-Recovery-Plan ist—wenn der aktuelle Zustand defekt ist, stellt das Zurücksetzen des Commits automatisch den letzten bekannten guten Zustand wieder her.


