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.
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:
- Desired State — das, was in Ihrem Git-Repository steht
- 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"
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 ansehen7. 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:
- kubectl Debugging Cheatsheet — 12 Befehle für jedes Pod-Problem
- NetworkPolicy Cheatsheet — 12 Patterns zum Copy-Pasten
- CrashLoopBackOff systematisch fixen — 7 Ursachen, 1 Workflow
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 ansehenWeiterlesen
kubectl Debugging Cheatsheet: 12 Befehle für Production-Incidents
Strukturierter Debugging-Workflow für Kubernetes in Production: 12 kubectl-Befehle in der richtigen Reihenfolge - von Pod-Status bis ephemeral debug containers.
8 min
Kubernetes NetworkPolicy Cheatsheet: 12 Patterns zum Copy-Pasten
NetworkPolicies sind mächtig aber verwirrend. 12 produktionsreife YAML-Patterns für Ingress, Egress, Namespace-Isolation und Monitoring. Inklusive AND-vs-OR-Falle.
11 minBrauchen 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