Cheveo Blog
gitops-argocd 12 min Lesezeit ·

ArgoCD OutOfSync systematisch debuggen: 12 Ursachen, 1 Workflow

OutOfSync ist das häufigste ArgoCD-Problem. 12 Ursachen mit argocd-Befehlen, echten Outputs und einem Decision-Tree, der jede Ursache in unter 5 Minuten findet.

Clemens Christen
Clemens Christen Certified Kubernetes Administrator (CKA)

TL;DR — OutOfSync heißt: Git-Zustand ≠ Cluster-Zustand. Das ist kein Fehler, sondern der Normalfall bei jeder Abweichung. 12 Ursachen decken 95% aller Fälle ab — von harmlosen Server-Side Defaults bis zu echten Drift-Problemen. Der 4-Befehl-Workflow (diff, get, logs, events) findet die Ursache in unter 5 Minuten.

🔖 Nur die YAMLs? Hier ist der interaktive ArgoCD OutOfSync-Cheatsheet — mit Copy-Button pro Pattern und häufigen Fehlern. Lesezeichen empfohlen.

Was OutOfSync wirklich bedeutet

ArgoCD vergleicht in regelmäßigen Zyklen (Standard: 3 Minuten) zwei Zustände:

  1. Desired State — das, was in Ihrem Git-Repository steht
  2. Live State — das, was tatsächlich im Cluster läuft

Jede Abweichung zwischen den beiden führt zum Status OutOfSync. Das kann bedeuten:

  • Ein Feld in einem Manifest wurde manuell im Cluster geändert (echter Drift)
  • Kubernetes hat ein Default-Feld hinzugefügt, das nicht in Ihrem Manifest steht (Phantom-Diff)
  • Ein Webhook hat ein Label oder Annotation injiziert (Mutation)
  • Das Sync ist fehlgeschlagen und der Cluster hat den alten Zustand

Die Schwierigkeit: ArgoCD unterscheidet nicht zwischen “gefährlichem Drift” und “harmlosem Default”. Beides ist OutOfSync. Sie müssen es.

Der 4-Befehl-Workflow

Egal welche Ursache — diese vier Befehle laufen immer zuerst.

Schritt 1: Diff anzeigen

argocd app diff <app-name>

Zeigt exakt welche Felder zwischen Git und Cluster abweichen. Das ist der wichtigste Befehl. Wenn Sie nur einen kennen: diesen.

Typischer Output bei Server-Side Defaults:

===== apps/Deployment default/api-server =====
--- desired
+++ live
@@ -18,6 +18,8 @@
   spec:
     containers:
     - name: api
+      terminationMessagePath: /dev/termination-log
+      terminationMessagePolicy: File
       image: registry.example.com/api:v1.2.3
+    dnsPolicy: ClusterFirst
+    schedulerName: default-scheduler

Sehen Sie Felder wie terminationMessagePath, dnsPolicy, schedulerName? Das sind Kubernetes-Defaults, die der API-Server automatisch setzt. Ihr Manifest ist korrekt — Kubernetes ergänzt nur.

Schritt 2: App-Status prüfen

argocd app get <app-name>

Zeigt den Gesamt-Status: Sync Status, Health Status, letzte Sync-Operation, und welche Ressourcen betroffen sind.

Name:               default/api-server
Sync Status:        OutOfSync
Health Status:      Healthy
Last Sync:          2026-05-25 10:15:03 +0200 CEST (ComparedTo)
Sync Resources:     3 out of sync

Wichtig: Healthy + OutOfSync bedeutet meistens harmlose Diffs. Degraded + OutOfSync ist ein echtes Problem.

Schritt 3: Controller-Logs prüfen

kubectl logs -n argocd -l app.kubernetes.io/name=argocd-application-controller --tail=50

Zeigt Sync-Fehler, RBAC-Probleme und Timeouts die in der UI nicht sichtbar sind.

Schritt 4: Events prüfen

kubectl get events -n <target-namespace> --sort-by=.lastTimestamp | tail -20

Zeigt Kubernetes-Events die der Sync ausgelöst hat: fehlgeschlagene Deployments, Admission-Webhook-Rejections, Quota-Limits.

Die 12 häufigsten Ursachen

1. Server-Side Defaults

Symptom: OutOfSync bei Feldern die Sie nie gesetzt haben (terminationMessagePath, dnsPolicy, schedulerName, revisionHistoryLimit).

Ursache: Der Kubernetes API-Server ergänzt Default-Werte beim Erstellen einer Ressource. Ihr Manifest hat diese Felder nicht, der Live-State schon. ArgoCD sieht eine Differenz.

Fix:

# In der Application-Spec:
spec:
  ignoreDifferences:
    - group: apps
      kind: Deployment
      jsonPointers:
        - /spec/template/spec/dnsPolicy
        - /spec/template/spec/schedulerName
        - /spec/revisionHistoryLimit

Oder global für den ganzen Cluster ab ArgoCD 2.5+:

# argocd-cm ConfigMap:
resource.customizations.ignoreDifferences.apps_Deployment: |
  jsonPointers:
    - /spec/template/spec/dnsPolicy
    - /spec/template/spec/schedulerName

2. Mutating Webhooks

Symptom: OutOfSync bei Labels, Annotations oder ganzen Containern die Sie nicht definiert haben (z.B. sidecar.istio.io/inject, Linkerd-Proxy-Container).

Ursache: Ein Mutating Admission Webhook (Istio, Linkerd, Vault Agent, OPA Gatekeeper) verändert die Ressource nach dem Apply. Git kennt den injizierten Sidecar nicht → Diff.

Fix: ignoreDifferences für die spezifischen Pfade:

spec:
  ignoreDifferences:
    - group: apps
      kind: Deployment
      jqPathExpressions:
        - .spec.template.metadata.annotations."sidecar.istio.io/status"
        - .spec.template.spec.initContainers[] | select(.name == "istio-init")
        - .spec.template.spec.containers[] | select(.name == "istio-proxy")

3. Helm Template vs. Helm Install

Symptom: OutOfSync bei Helm-Charts, obwohl helm install lokal funktioniert.

Ursache: ArgoCD nutzt helm template (Client-seitig), nicht helm install (Server-seitig). helm template hat keinen Cluster-Zugriff — .Capabilities.APIVersions, lookup-Funktionen und Server-Side Hooks funktionieren nicht oder liefern andere Ergebnisse.

Diagnose:

# Lokal vergleichen was ArgoCD sieht:
helm template <release> <chart> --values values.yaml > /tmp/argocd-view.yaml
# vs. was helm install erzeugt:
helm install <release> <chart> --values values.yaml --dry-run > /tmp/helm-view.yaml
diff /tmp/argocd-view.yaml /tmp/helm-view.yaml

Fix: Vermeide lookup und .Capabilities in Templates, oder setze die ApiVersions in der ArgoCD Application-Spec:

spec:
  source:
    helm:
      apiVersions:
        - monitoring.coreos.com/v1

4. Immutable Fields

Symptom: Sync schlägt fehl mit field is immutable — nicht nur OutOfSync, sondern SyncFailed.

Ursache: Kubernetes erlaubt keine Änderungen an bestimmten Feldern nach der Erstellen: spec.selector.matchLabels bei Deployments, spec.clusterIP bei Services, spec.volumeName bei PVCs.

Fix: Die Ressource muss gelöscht und neu erstellt werden. In ArgoCD:

argocd app sync <app-name> --resource <group>/<kind>/<name> --replace

Oder sicherer: Sync mit --prune und Recreate-Strategie in der Annotation:

metadata:
  annotations:
    argocd.argoproj.io/sync-options: Replace=true

5. RBAC / Berechtigungsfehler

Symptom: OutOfSync, Sync-Versuch schlägt fehl mit forbidden im Controller-Log.

Ursache: Der ArgoCD Application Controller hat nicht die nötigen Cluster-Rechte um die Ressource zu erstellen oder zu ändern.

Diagnose:

kubectl logs -n argocd -l app.kubernetes.io/name=argocd-application-controller --tail=100 | grep -i "forbidden\|unauthorized"

Fix: ClusterRole/RoleBinding des ArgoCD Service Accounts erweitern, oder die fehlenden API-Gruppen im ArgoCD Project whitelisten.

6. Fehlender Namespace

Symptom: OutOfSync mit namespace not found im Sync-Log.

Ursache: Das Manifest referenziert einen Namespace der noch nicht existiert. ArgoCD erstellt Namespaces nicht automatisch (es sei denn, der Namespace ist Teil des Manifests).

Fix: Namespace als eigene Ressource im selben Application-Manifest aufnehmen und mit Sync Wave sicherstellen, dass er zuerst erstellt wird:

apiVersion: v1
kind: Namespace
metadata:
  name: my-app
  annotations:
    argocd.argoproj.io/sync-wave: "-1"
2-Tage Hands-on Workshop

GitOps mit ArgoCD - vom Push zum Production-Deploy

Vom App-of-Apps Pattern bis Progressive Delivery: alles, was Sie für GitOps in der Produktion brauchen.

Workshop-Details ansehen

7. Resource Quota überschritten

Symptom: OutOfSync + exceeded quota in Events.

Ursache: Der Namespace hat eine ResourceQuota und die Sync-Operation würde das Limit überschreiten.

Diagnose:

kubectl describe resourcequota -n <namespace>
kubectl get events -n <namespace> | grep -i quota

Fix: Entweder die Quota erhöhen oder die Resource Requests/Limits im Manifest anpassen.

8. Kustomize Build-Fehler

Symptom: OutOfSync + kustomize build Fehler im Controller-Log.

Ursache: Das Kustomize-Overlay hat einen Fehler — fehlende Basis, ungültiger Patch, inkompatible API-Versionen.

Diagnose:

# Lokal testen:
kustomize build overlays/production/

Fix: Kustomize-Fehler beheben. Häufigste Ursache: relative Pfade in kustomization.yaml die im ArgoCD-Kontext (der das Repo in /tmp klont) nicht auflösen.

9. Finalizer blockiert Löschung

Symptom: OutOfSync bei einer Ressource die gelöscht werden sollte. Ressource bleibt mit Status Terminating.

Ursache: Ein Finalizer auf der Ressource verhindert die Löschung, weil der zugehörige Controller nicht mehr läuft oder nicht erreichbar ist.

Diagnose:

kubectl get <resource> <name> -o jsonpath='{.metadata.finalizers}'

Fix:

kubectl patch <resource> <name> --type merge -p '{"metadata":{"finalizers":null}}'

10. Sync-Loop (Auto-Sync + Phantom-Diff)

Symptom: ArgoCD synct alle 3 Minuten, Status wechselt zwischen Synced und OutOfSync, Application-Controller-Logs zeigen ständige Sync-Operationen.

Ursache: Auto-Sync ist aktiviert. Jeder Sync erzeugt sofort wieder OutOfSync durch Server-Side Defaults oder Webhooks. ArgoCD synct erneut. Loop.

Diagnose:

argocd app get <app-name> --show-operation
# Zeigt die letzten Sync-Operationen mit Timestamps

Fix: ignoreDifferences für die verursachenden Felder (Ursache 1 oder 2), oder Server-Side Diff aktivieren:

# argocd-cm ConfigMap:
application.resourceTrackingMethod: annotation+label
controller.diff.server.side: "true"

11. Git-Repository nicht erreichbar

Symptom: OutOfSync + ComparisonError + failed to load initial state of resource im App-Status.

Ursache: ArgoCD kann das Git-Repository nicht mehr erreichen — abgelaufene Credentials, rotierter SSH-Key, Netzwerkproblem.

Diagnose:

argocd repo list
argocd repo get <repo-url>
kubectl logs -n argocd -l app.kubernetes.io/name=argocd-repo-server --tail=50

Fix: Repository-Credentials aktualisieren:

argocd repo add <url> --username <user> --password <token>

12. Stale Cache

Symptom: OutOfSync verschwindet nach Hard-Refresh, kommt aber nach dem nächsten Sync-Zyklus zurück. Oder: Änderungen in Git werden nicht erkannt.

Ursache: Der ArgoCD Repo-Server cached geklonte Repositories. Bei großen Repos oder vielen Branches kann der Cache veraltet sein.

Fix:

# Soft refresh (Re-Compare ohne Cache-Invalidierung):
argocd app get <app-name> --refresh

# Hard refresh (Cache komplett invalidieren):
argocd app get <app-name> --hard-refresh

Wenn das Problem persistiert, den Repo-Server restarten:

kubectl rollout restart deployment argocd-repo-server -n argocd

Server-Side Diff: Die Nuklear-Option

Ab ArgoCD 2.5+ können Sie Server-Side Diff aktivieren. Statt helm template lokal auszuführen, schickt ArgoCD das Manifest an den API-Server mit kubectl diff --server-side. Der Server wendet Defaults und Webhooks an bevor der Vergleich stattfindet. Ergebnis: 80% weniger Phantom-Diffs.

# argocd-cm ConfigMap:
controller.diff.server.side: "true"

Vorsicht: Server-Side Diff erfordert, dass der ArgoCD Service Account PATCH Rechte auf alle verwalteten Ressourcen hat. Prüfen Sie Ihre RBAC bevor Sie das aktivieren.

Decision-Tree: Schnelle Diagnose

OutOfSync
├── argocd app diff zeigt nur Default-Felder?
│   └── Ja → Ursache 1 (Server-Side Defaults) oder 2 (Webhooks)
│        → ignoreDifferences konfigurieren
├── Sync-Versuch schlägt fehl?
│   ├── "field is immutable" → Ursache 4 → Replace-Sync
│   ├── "forbidden" → Ursache 5 → RBAC prüfen
│   ├── "namespace not found" → Ursache 6 → Sync Waves
│   ├── "exceeded quota" → Ursache 7 → Quota anpassen
│   └── Kustomize/Helm-Fehler → Ursache 3 oder 8 → Lokal testen
├── Ressource stuck in Terminating?
│   └── Ursache 9 → Finalizer entfernen
├── Sync-Loop (ständiges Re-Sync)?
│   └── Ursache 10 → ignoreDifferences oder Server-Side Diff
├── ComparisonError?
│   └── Ursache 11 → Repo-Credentials prüfen
└── Hard-Refresh löst es temporär?
    └── Ursache 12 → Repo-Server restarten

Wie es weitergeht

Im GitOps mit ArgoCD Workshop bauen wir ein komplettes ArgoCD-Setup inkl. App-of-Apps Pattern, Sealed Secrets und Drift-Detection — und debuggen absichtlich kaputte Syncs, damit Sie die Patterns aus diesem Artikel unter Anleitung anwenden.

Verwandt aus unserer Serie:

2-Tage Hands-on Workshop

GitOps mit ArgoCD - vom Push zum Production-Deploy

Vom App-of-Apps Pattern bis Progressive Delivery: alles, was Sie für GitOps in der Produktion brauchen.

Workshop-Details ansehen
Kostenfrei · 30 Minuten

Brauchen Sie eine zweite Meinung zu Ihrem Cluster?

Buchen Sie einen kostenfreien 30-Minuten Kubernetes Health-Check. Wir schauen uns Ihr Setup an und geben konkrete Hinweise, ohne Verkaufsgespräch.

Termin buchen