GitOps hat in kleinen Teams einen schlechten Ruf, und zwar zu Recht: Die meisten Anleitungen setzen einen Plattform-Stack voraus, den drei Entwickler niemals betreiben wollen. Dabei ist der Kern der Idee simpel – der gewünschte Zustand des Clusters steht in Git, ein Controller gleicht ab, fertig.
Dieser Guide zeigt ein ArgoCD-Setup, das genau so weit geht wie nötig: ein k3s-Knoten, ArgoCD darin, abgesicherter Zugang, eine überschaubare Repository-Struktur. Kein Service Mesh, keine sieben Umgebungen, kein Team, das nur die Plattform pflegt.
Was GitOps für kleine Teams tatsächlich löst
Der Gewinn liegt selten in der Geschwindigkeit. Er liegt darin, dass niemand mehr nachträglich herausfinden muss, warum die Produktion anders aussieht als gedacht. Ohne GitOps ist der tatsächliche Cluster-Zustand das Ergebnis aller kubectl apply-Aufrufe der letzten Monate – inklusive der schnellen Korrektur um 23 Uhr, von der niemand mehr weiß.
Konkret bekommst du drei Dinge:
- Nachvollziehbarkeit: Jede Änderung ist ein Commit, mit Autor, Zeitpunkt und Begründung.
- Rollback, der wirklich funktioniert: Der vorherige Stand ist ein
git revert, kein Rekonstruktionsversuch aus dem Gedächtnis. - Drift-Erkennung: ArgoCD meldet, wenn im Cluster etwas vom Git-Stand abweicht – auch bei manuellen Eingriffen.
Wann sich ArgoCD lohnt – und wann nicht
ArgoCD ist ein Kubernetes-Werkzeug. Wenn du keine Kubernetes-Workloads betreibst, ist es das falsche Werkzeug – für Docker-Compose-Dienste auf einem einzelnen Server bringt ein Git-Repository plus Ansible dasselbe Ergebnis mit weniger beweglichen Teilen.
Faustregel: Ab etwa fünf Anwendungen im Cluster oder ab dem Moment, in dem mehr als eine Person deployt, zahlt sich ArgoCD aus. Darunter ist es meist zusätzlicher Aufwand ohne Gegenwert.
1. Kubernetes-Basis: k3s statt Vollausbau
Für kleine Teams reicht k3s – eine vollwertige, zertifizierte Kubernetes-Distribution in einer einzelnen Binärdatei. Ein Server genügt für den Anfang; die Installation dauert unter einer Minute.
# k3s installieren (bringt Traefik als Ingress-Controller mit)
curl -sfL https://get.k3s.io | sh -
# kubeconfig fuer den eigenen Benutzer verfuegbar machen
mkdir -p ~/.kube
sudo cp /etc/rancher/k3s/k3s.yaml ~/.kube/config
sudo chown $(id -u):$(id -g) ~/.kube/config
# Cluster erreichbar?
kubectl get nodes
Ein Knoten heißt: keine Ausfallsicherheit. Für interne Werkzeuge und kleine Dienste ist das ein bewusster, vertretbarer Kompromiss – für alles, was Kunden direkt trifft, solltest du ihn nicht eingehen.
2. ArgoCD installieren
ArgoCD läuft im Cluster und verwaltet ihn von innen. Die offiziellen Manifeste installieren alle nötigen Komponenten in einen eigenen Namespace:
kubectl create namespace argocd
kubectl apply -n argocd \
-f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
# Warten, bis alle Pods laufen
kubectl -n argocd rollout status deploy/argocd-server
Das initiale Admin-Passwort liegt in einem Secret und sollte nach dem ersten Login ersetzt werden:
# Initiales Admin-Passwort auslesen
kubectl -n argocd get secret argocd-initial-admin-secret \
-o jsonpath="{.data.password}" | base64 -d; echo
# Fuer den ersten Zugriff ohne Ingress
kubectl port-forward svc/argocd-server -n argocd 8080:443
3. Zugang absichern
Die ArgoCD-Oberfläche darf nicht ungeschützt im Netz stehen – sie kann per Definition alles im Cluster ändern. Zwei Wege sind praktikabel:
- Kein öffentlicher Zugang: Zugriff ausschließlich über
kubectl port-forwardoder ein VPN beziehungsweise Tailscale. Für kleine Teams die einfachste und sicherste Variante. - Ingress mit TLS: Wenn ein Browser-Zugang von außen nötig ist, gehört ein Zertifikat davor – über cert-manager und Let's Encrypt – plus ein starkes Admin-Passwort und idealerweise SSO.
# Admin-Passwort aendern (argocd CLI)
argocd login argocd.beispielkunde.at
argocd account update-password
# Initiales Secret danach entfernen
kubectl -n argocd delete secret argocd-initial-admin-secret
Häufiger Fehler: ArgoCD öffentlich erreichbar machen und das initiale Admin-Passwort stehen lassen. Wer das Passwort hat, hat den Cluster.
4. Repository-Struktur, die nicht ausartet
Die häufigste Ursache für gescheiterte GitOps-Einführungen ist nicht die Technik, sondern eine Ordnerstruktur, die nach drei Monaten niemand mehr versteht. Für kleine Teams bewährt sich ein einzelnes Repository mit flacher Gliederung:
infra/
├── apps/ # je Anwendung ein Verzeichnis
│ ├── webshop/
│ │ ├── base/ # Deployment, Service, Ingress
│ │ └── overlays/
│ │ ├── staging/
│ │ └── production/
│ └── monitoring/
└── argocd/ # die Application-Definitionen selbst
└── applications.yaml
Umgebungen werden über Kustomize-Overlays abgebildet, nicht über getrennte Branches. Branch-basierte Umgebungen klingen zunächst naheliegend, führen aber schnell zu Merge-Konflikten und divergierenden Ständen – einer der Punkte, die ich in den GitOps-Anti-Patterns ausführlicher beschreibe.
5. Die erste Application anlegen
Eine Application verbindet ein Verzeichnis im Repository mit einem Ziel-Namespace im Cluster. Sie ist selbst wieder eine Kubernetes-Ressource – und gehört damit ebenfalls ins Git-Repository:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: webshop
namespace: argocd
spec:
project: default
source:
repoURL: https://git.beispielkunde.at/team/infra.git
targetRevision: main
path: apps/webshop/overlays/production
destination:
server: https://kubernetes.default.svc
namespace: webshop
syncPolicy:
automated:
prune: true # geloeschte Ressourcen auch im Cluster entfernen
selfHeal: true # manuelle Aenderungen zurueckdrehen
syncOptions:
- CreateNamespace=true
6. Sync-Strategie: automatisch oder manuell?
selfHeal: true ist der Schalter, der GitOps von "Git als Ablage" unterscheidet: Ändert jemand etwas direkt im Cluster, dreht ArgoCD es zurück. Das ist gewollt – und im ersten Monat gewöhnungsbedürftig, weil es Nothilfe-Eingriffe wirkungslos macht.
Ein pragmatischer Einstieg:
- Staging: vollautomatisch mit
pruneundselfHeal. Fehler fallen dort auf, wo sie nichts kosten. - Produktion: anfangs manuelle Freigabe. ArgoCD zeigt die Abweichung an, der Sync erfolgt per Klick.
- Nach ein paar Wochen ohne Überraschungen auch die Produktion automatisieren.
7. Secrets: der unangenehme Teil
Zugangsdaten gehören nicht im Klartext ins Repository – auch nicht in ein privates. Zwei Ansätze haben sich bewährt:
- Sealed Secrets: Ein Controller im Cluster hält den privaten Schlüssel; im Repository liegt nur die verschlüsselte Fassung. Einfach einzuführen, gut für kleine Setups.
- SOPS mit age: Verschlüsselung auf Dateiebene, unabhängig von Kubernetes – praktisch, wenn dieselben Geheimnisse auch außerhalb des Clusters gebraucht werden.
# Beispiel: Secret verschluesseln (Sealed Secrets)
kubectl create secret generic db-credentials \
--from-literal=password='...' \
--dry-run=client -o yaml | kubeseal -o yaml > db-credentials-sealed.yaml
# Nur die versiegelte Datei landet in Git
git add db-credentials-sealed.yaml
Wichtig: Der private Schlüssel des Sealed-Secrets-Controllers gehört ins Backup. Ohne ihn sind alle versiegelten Secrets nach einem Cluster-Neuaufbau wertlos.
8. Betrieb: Backup und Updates
Der angenehme Nebeneffekt von GitOps: Das Repository ist ein großer Teil des Backups. Was trotzdem gesichert gehört:
- k3s-Snapshots unter
/var/lib/rancher/k3s/server/db/snapshots– k3s legt sie standardmäßig regelmäßig an. - Persistente Volumes – Datenbanken und Uploads stehen nicht in Git.
- Der Sealed-Secrets-Schlüssel, siehe oben.
Ein Wiederherstellungstest gehört einmal gemacht, bevor man sich darauf verlässt – wie das methodisch aussieht, steht in Backup-Tests richtig machen.
Fazit
Ein brauchbares GitOps-Setup besteht aus einem k3s-Knoten, ArgoCD, einem Repository und einer Handvoll YAML-Dateien. Alles darüber hinaus – mehrere Cluster, Progressive Delivery, eigene Plattform-Abstraktionen – ist eine Antwort auf Probleme, die kleine Teams meist gar nicht haben.
Fang mit einer unkritischen Anwendung in Staging an, lass sie zwei Wochen laufen, und nimm erst dann die Produktion dazu. Der Punkt, an dem GitOps sich auszahlt, kommt nicht beim ersten Deployment, sondern beim ersten Rollback, der ohne Rätselraten funktioniert.