GitOps-Workflows: Infrastruktur über Pull Requests verwalten
GitOps-Workflows, die Kubernetes-Infrastruktur über Pull Requests mit ArgoCD und Flux verwalten: Repo-Struktur, Sync-Policies, Health Checks, Rollback.

Traditionelle Deployment-Pipelines schieben Änderungen in die Produktion: ein CI-Server baut Artefakte und deployed sie auf die Ziele. GitOps kehrt das um: der gewünschte Zustand lebt in Git, und ein Controller innerhalb des Clusters gleicht kontinuierlich die Realität mit dem deklarierten Zustand ab. Keine manuellen kubectl-Befehle, keine imperativen Skripte, keine Abweichung zwischen dem, was du glaubst deployed zu haben, und dem, was tatsächlich läuft.
Der Pull Request wird zum Deployment-Mechanismus. Einen Manifest-Change reviewen, mergen, und der Cluster konvergiert. Ein Deployment zurückrollen, indem man einen Commit reverteert.
Das GitOps-Modell
GitOps hat vier Prinzipien: deklarative Konfiguration, versionskontrollierter Zielzustand, automatisierte Anwendung und kontinuierliche Abstimmung.
# ❌ Imperatives Deployment — fragil, keine Audit-Trail
# kubectl set image deployment/api api=myapp:v2.3.1
# kubectl scale deployment/api --replicas=5
# kubectl apply -f hotfix-configmap.yaml
# Wer hat das ausgeführt? Wann? Wurde es geprüft?
# Was passiert, wenn der Cluster driftet?# ✅ Deklaratives GitOps — Git IST die Quelle der Wahrheit
# environments/production/api/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
namespace: production
labels:
app: api
version: v2.3.1
spec:
replicas: 5
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
version: v2.3.1
spec:
containers:
- name: api
image: registry.example.com/api:v2.3.1
ports:
- containerPort: 3000
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
cpu: 500m
memory: 512Mi
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 10
periodSeconds: 15
readinessProbe:
httpGet:
path: /ready
port: 3000
initialDelaySeconds: 5
periodSeconds: 10Jede Änderung ist ein Commit. Jedes Deployment ist ein Merge. Jedes Rollback ist ein Revert.
Repository-Struktur
Trenne Anwendungscode von Deployment-Konfiguration. Anwendungs-Repos enthalten Quellcode und CI-Pipelines. Konfig-Repos enthalten Kubernetes-Manifeste, nach Umgebung organisiert.
# infrastructure-config/ (GitOps-Konfig-Repo)
├── base/ # Gemeinsame Manifeste
│ ├── api/
│ │ ├── deployment.yaml
│ │ ├── service.yaml
│ │ ├── hpa.yaml
│ │ └── kustomization.yaml
│ └── worker/
│ ├── deployment.yaml
│ ├── service.yaml
│ └── kustomization.yaml
├── environments/
│ ├── staging/
│ │ ├── api/
│ │ │ ├── kustomization.yaml # Patches für Staging
│ │ │ └── replica-patch.yaml
│ │ └── kustomization.yaml
│ └── production/
│ ├── api/
│ │ ├── kustomization.yaml # Patches für Prod
│ │ ├── replica-patch.yaml
│ │ └── resource-patch.yaml
│ └── kustomization.yaml
└── argocd/ # ArgoCD-Application-Definitionen
├── staging.yaml
└── production.yaml
Mit Kustomize definieren Basismanifeste die gemeinsame Konfiguration. Umgebungs-Overlays patchen nur das, was abweicht — Replica-Anzahl, Ressourcenlimits, Umgebungsvariablen.
# environments/production/api/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../../base/api
namespace: production
patches:
- path: replica-patch.yaml
- path: resource-patch.yaml
images:
- name: registry.example.com/api
newTag: v2.3.1# environments/production/api/replica-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
spec:
replicas: 5ArgoCD Application-Konfiguration
ArgoCD beobachtet das Git-Repository und synchronisiert den Cluster-Zustand entsprechend. Die Application-Ressource definiert, was beobachtet und wie synchronisiert werden soll.
# argocd/production.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: production-api
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: production
source:
repoURL: https://github.com/myorg/infrastructure-config
targetRevision: main
path: environments/production
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true # Entfernt Ressourcen, die aus Git gelöscht wurden
selfHeal: true # Macht manuelle Cluster-Änderungen rückgängig
allowEmpty: false # Verhindert versehentliches Löschen aller Ressourcen
syncOptions:
- CreateNamespace=true
- PrunePropagationPolicy=foreground
- PruneLast=true
retry:
limit: 3
backoff:
duration: 5s
factor: 2
maxDuration: 1m
ignoreDifferences:
- group: apps
kind: Deployment
jsonPointers:
- /spec/replicas # Ignoriert HPA-verwaltete ReplicasDie Einstellung selfHeal: true ist kritisch: sie bedeutet, dass manuelle kubectl-Änderungen automatisch rückgängig gemacht werden. Die Quelle der Wahrheit ist Git, und der Cluster konvergiert kontinuierlich zu ihr.
Automatisierte Image-Updates
Wenn eine CI-Pipeline ein neues Image baut, muss sie das GitOps-Konfig-Repo aktualisieren. Das erzeugt einen Commit, den ArgoCD aufgreift.
# .github/workflows/build-and-update.yml
name: Build and Update Config
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
outputs:
image-tag: ${{ steps.meta.outputs.version }}
steps:
- uses: actions/checkout@v4
- name: Build and push image
id: meta
run: |
TAG="v$(date +%Y%m%d)-${GITHUB_SHA::8}"
echo "version=$TAG" >> $GITHUB_OUTPUT
docker build -t registry.example.com/api:$TAG .
docker push registry.example.com/api:$TAG
update-config:
needs: build
runs-on: ubuntu-latest
steps:
- name: Checkout config repo
uses: actions/checkout@v4
with:
repository: myorg/infrastructure-config
token: ${{ secrets.CONFIG_REPO_TOKEN }}
- name: Update image tag
run: |
cd environments/staging/api
kustomize edit set image \
registry.example.com/api:${{ needs.build.outputs.image-tag }}
- name: Commit and push
run: |
git config user.name "CI Bot"
git config user.email "ci@example.com"
git add .
git commit -m "chore: update api image to ${{ needs.build.outputs.image-tag }}"
git pushHealth Checks und Rollback
ArgoCD überwacht die Ressourcen-Gesundheit nach der Synchronisation. Wenn ein Deployment die Health Checks nicht besteht, kannst du automatisches Rollback konfigurieren oder es im Sync-Status erkennen.
# Custom health check für die API
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: production-api
spec:
# ... source- und destination-Konfiguration
syncPolicy:
automated:
prune: true
selfHeal: true
# Ressourcen-Gesundheitsbewertung
info:
- name: deployment-strategy
value: rolling-update# Sync-Status prüfen
argocd app get production-api
# Sync-Verlauf anzeigen
argocd app history production-api
# Auf vorherige Sync-Version zurückrollen
argocd app rollback production-api 2
# Oder einfach in Git reverteeren (bevorzugt — Git bleibt Quelle der Wahrheit)
git revert HEAD
git push origin main
# ArgoCD erkennt die Änderung und synchronisiert zurückDas git-basierte Rollback ist der korrekte GitOps-Ansatz. Anstatt ArgoCDs Rollback-Befehl zu nutzen, reverteere den Commit in Git. So bleibt das Git-Repository als einzige Quelle der Wahrheit erhalten, und die Revert-Commit-Message liefert eine klare Audit-Trail, die erklärt, warum das Rollback passiert ist.
Drift-Erkennung und Alerts
Auch wenn selfHeal aktiviert ist, solltest du Drift-Versuche überwachen: sie deuten oft auf betriebliche Probleme oder Team-Mitglieder hin, die den GitOps-Workflow umgehen.
# Prometheus-Alert für ArgoCD-Sync-Fehler
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: argocd-alerts
namespace: monitoring
spec:
groups:
- name: argocd
rules:
- alert: ArgoCDSyncFailed
expr: |
argocd_app_info{sync_status="OutOfSync"}
* on(name) group_left()
(time() - argocd_app_info{sync_status="OutOfSync"})
> 300
for: 5m
labels:
severity: warning
annotations:
summary: >-
Application {{ $labels.name }}
has been out of sync for more than 5 minutes
description: >-
Check ArgoCD for sync errors.
Run: argocd app get {{ $labels.name }}
- alert: ArgoCDAppDegraded
expr: |
argocd_app_info{health_status="Degraded"} == 1
for: 3m
labels:
severity: critical
annotations:
summary: >-
Application {{ $labels.name }}
health is degradedWichtige Erkenntnisse
GitOps macht Git zur einzigen Quelle der Wahrheit für den Infrastrukturzustand: jedes Deployment ist ein Merge, jedes Rollback ist ein Revert, und der Cluster gleicht kontinuierlich mit dem deklarierten Zustand ab, ohne dass imperative Befehle nötig sind. Trenne Anwendungs-Code-Repositories von Infrastruktur-Konfigurations-Repositories, damit Image-Builds Konfigurations-Updates über automatisierte Commits auslösen und eine klare Grenze zwischen dem, was die Anwendung ist, und dem, wie sie läuft, erhalten bleibt. Aktiviere selfHeal und prune in den ArgoCD-Sync-Richtlinien, damit manuelle Cluster-Änderungen automatisch rückgängig gemacht und gelöschte Ressourcen bereinigt werden, was verhindert, dass sich Configuration Drift ansammelt, wenn Teams den GitOps-Workflow umgehen. Überwache Out-of-Sync-Zustände und degraded Health mit Alerts, denn Drift-Versuche deuten oft auf Prozesslücken oder betriebliche Probleme hin: ihre schnelle Erkennung bewahrt die Integrität, die GitOps wertvoll macht.


