Zum Inhalt springen

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.

5 Min. Lesezeit
GitOps-Workflow-Diagramm, das zeigt, wie ArgoCD den Soll-Zustand aus Git-Repositories mit dem tatsächlichen Kubernetes-Cluster-Zustand abgleicht

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.

ymlyaml
# ❌ 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
ymlyaml
# ✅ Ü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
ymlyaml
# 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: true

Sync 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.

tstypescript
// 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.

tstypescript
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.

tstypescript
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.

ymlyaml
# 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
ymlyaml
# 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.

Wilfredo Rujel

Wilfredo Rujel

Full-Stack-Softwareentwickler

Diesen Beitrag teilenX