Argo CD ist ein Werkzeug für GitOps auf Kubernetes: Der gewünschte Zustand des Clusters steht in einem Git-Repository, und Argo CD sorgt dafür, dass das Cluster diesem Zustand entspricht. Änderungen erfolgen ausschließlich über Commits – nicht über kubectl apply aus einer Shell.

Warum GitOps statt kubectl

Ohne GitOps:
  Wer hat die Konfiguration geaendert?   -> unbekannt
  Was war der Zustand vor 3 Tagen?       -> niemand weiss es
  Wie kommt ein Rollback zustande?       -> von Hand
  Wer darf aendern?                      -> alle mit Clusterzugriff

Mit GitOps:
  Jede Aenderung ist ein Commit        -> Verlauf, Urheber, Grund
  Der Zustand vor 3 Tagen ist ein Commit -> git checkout
  Rollback = Commit zuruecksetzen       -> ein Befehl
  Rechte = Schreibrecht im Repository   -> pruefbar, nachvollziehbar

Zusaetzlich: Das Cluster wird selbstheilend. Wer etwas von Hand
aendert, verliert die Aenderung beim naechsten Abgleich - mit
Meldung. Genau das ist gewollt.

Installation

kubectl create namespace argocd
kubectl apply -n argocd -f \
  https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

# Warten
kubectl -n argocd rollout status deploy/argocd-server

# Erster Zugang: Benutzer admin, Passwort aus einem Geheimnis
kubectl -n argocd get secret argocd-initial-admin-secret \
  -o jsonpath="{.data.password}" | base64 -d; echo
#   SOFORT aendern und das Geheimnis loeschen!

# CLI installieren
curl -sSL -o /usr/local/bin/argocd \
  https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64
chmod +x /usr/local/bin/argocd

argocd login argocd.example.org --username admin
argocd account update-password
argocd version

Die Anwendungsbeschreibung

# app.yaml - die zentrale Ressource
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: webshop-prod
  namespace: argocd
  finalizers:
    - resources-finalizer.argocd.argoproj.io    # beim Loeschen aufraeumen
spec:
  project: default

  source:
    repoURL: https://git.example.org/platform/k8s-manifests.git
    targetRevision: main
    path: apps/webshop/overlays/prod      # Kustomize-Overlay
    # Alternativ Helm:
    #   helm:
    #     valueFiles: [values-prod.yaml]
    #     parameters:
    #       - name: image.tag
    #         value: "1.4.2"

  destination:
    server: https://kubernetes.default.svc
    namespace: webshop

  syncPolicy:
    automated:
      prune: true        # nicht mehr vorhandene Ressourcen entfernen
      selfHeal: true     # manuelle Aenderungen zuruecksetzen
      allowEmpty: false  # Schutz: nie alles loeschen
    syncOptions:
      - CreateNamespace=true
      - PrunePropagationPolicy=foreground
      - ApplyOutOfSyncOnly=true
    retry:
      limit: 5
      backoff:
        duration: 10s
        factor: 2
        maxDuration: 5m

Der Ablauf im Alltag

# Zustand ansehen
argocd app list
argocd app get webshop-prod
argocd app diff webshop-prod          # was weicht ab?

# Synchronisieren
argocd app sync webshop-prod
argocd app sync webshop-prod --dry-run      # Vorschau, ohne zu aendern
argocd app history webshop-prod
argocd app rollback webshop-prod 12         # auf Stand 12 zurueck

# Warten, bis fertig (gut in Skripten)
argocd app wait webshop-prod --timeout 300

# Manuelles Abweichen sichtbar machen
#   Status "OutOfSync" -> jemand hat von Hand geaendert
#   Mit selfHeal: true wird es zurueckgesetzt und protokolliert

# Eine Anwendung loeschen (inklusive der Ressourcen)
argocd app delete webshop-prod --cascade

# Alle Anwendungen einer Gruppe
argocd app list -l team=webshop

App-of-Apps: viele Anwendungen verwalten

Statt jede Anwendung einzeln anzulegen, verwaltet man eine Wurzelanwendung, die weitere Anwendungsbeschreibungen aus dem Repository zieht.

# apps/root.yaml - die Wurzelanwendung
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: root
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://git.example.org/platform/k8s-manifests.git
    targetRevision: main
    path: apps/                            # hier liegen weitere Application-Dateien
  destination:
    server: https://kubernetes.default.svc
    namespace: argocd
  syncPolicy:
    automated: {prune: true, selfHeal: true}

# Ergebnis: Eine neue Anwendung aufnehmen heisst:
#   1. Datei unter apps/ anlegen
#   2. Commit und Push
#   3. Argo CD zieht sie automatisch
#   Kein manuelles "argocd app create" mehr - alles im Verlauf.

# Mit ApplicationSet noch einen Schritt weiter:
#   Eine Vorlage erzeugt Anwendungen je Umgebung oder je Cluster
#   aus Verzeichnisstruktur oder Clusterliste.

Prüfliste

  1. Sind die Manifeste im Repository die einzige Quelle der Wahrheit – oder wird weiterhin von Hand geändert?
  2. Ist selfHeal: true aktiv, damit manuelle Änderungen zurückgesetzt werden?
  3. Ist prune: true mit Vorsicht aktiviert (Löschungen sind echt!)?
  4. Sind die Rechte im Git-Repository aussagekräftig – wer darf in den Produktionspfad committen?
  5. Sind Geheimnisse nicht im Klartext im Repository (Sealed Secrets, SOPS, External Secrets)?
  6. Ist die Zustandsprüfung aktiv, damit Argo CD weiß, wann ein Rollout fertig ist?
  7. Sind Rollback und das Verhalten bei fehlerhaften Änderungen einmal geübt worden?
  8. Wird die Argo-CD-Instanz selbst aktualisiert und überwacht?

Häufige Fehler

  1. Geheimnisse im Repository. Ein Klartextpasswort im Git-Verlauf bleibt dort, auch wenn es später entfernt wird. Verschlüsselung (SOPS, Sealed Secrets) ist Pflicht.
  2. prune: true ohne Verständnis. Eine Ressource aus dem Repository zu entfernen bedeutet echtes Löschen im Cluster – inklusive Datenbanken und Speichermedien, wenn keine Schutzmechanismen greifen.
  3. Keine Zustandsprüfungen. Ohne sie meldet Argo CD „synchronisiert“, während der Rollout noch läuft – und ein nachfolgender Schritt greift auf eine halbfertige Anwendung zu.
  4. Cluster-Ressourcen ohne Namensraum. Was namespace nicht braucht (ClusterRole, Namespace, CustomResourceDefinition), muss korrekt angegeben werden – sonst fehlt es oder wird an der falschen Stelle angelegt.
  5. Selbstverwaltung außer Acht gelassen. Wird Argo CD aus demselben Repository verwaltet, das es überwacht, kann eine fehlerhafte Änderung die eigene Steuerung außer Betrieb setzen. Getrennt halten.
  6. Abgleichintervall zu lang. Standard sind drei Minuten. Bei wichtigen Anwendungen kann eine Abfrage (Webhook aus dem Repository) den Abgleich beschleunigen.
  7. Keine Trennung nach Umgebung. Produktion und Testumgebung im gleichen Pfad und mit gleichen Rechten führt unweigerlich zu Fehlern. Verzeichnisse je Umgebung, Rechte je Umgebung.
  8. Argo CD ohne Überwachung. Der Ausfall der Steuerung ist der stille Ausfall: Es funktioniert weiter – bis zur nächsten Änderung, die nicht mehr ankommt.

Wann GitOps passt – und wann nicht

Gut geeignet: Kubernetes-Umgebungen mit mehreren Umgebungen, Teams mit Änderungsnachverfolgung, wiederkehrende Konfiguration über Cluster hinweg.

Weniger geeignet: Ein einzelner Server ohne Cluster (dort passen Ansible oder ein Werkzeug wie Argo CD nicht), Umgebungen mit regulierten Änderungsfenstern und ohne Repository-Zugriff (dort braucht es einen zusätzlichen Freigabeprozess), und Situationen, in denen niemand Git versteht.

Verwandte Grundlagen: GitOps, Argo CD, Kubernetes, Kubernetes-Architektur.