Teil D — Wie man betreibt. Zurück zur Übersicht.
Lernziel
Nach diesem Kapitel kennst du die vier GitOps-Prinzipien, kannst Push- von Pull-Verfahren unterscheiden und weißt, wie Geheimnisse in einem öffentlich lesbaren Repository sicher abgelegt werden. Du hast einen einfachen Pull-Abgleich für den KFZ-Rechner gebaut.
GitOps ist die konsequente Fortsetzung von Infrastructure as Code: Git ist nicht die Dokumentation des Systems, Git ist das System.
Vier Prinzipien:
Der vierte Punkt ist der eigentliche Unterschied zu allem Vorherigen. Eine Pipeline stellt einen Zustand einmal her. Ein GitOps-Automatismus hält ihn aufrecht.
PUSH (klassische Pipeline)
Git ──► Pipeline ──► Zugangsdaten ──► Zielsystem
▲
Die Pipeline braucht Schreibrechte
auf der Produktion.
PULL (GitOps)
Git ◄────── Agent im Zielsystem ──► wendet an
zieht regelmäßig
▲
Keine Zugangsdaten außerhalb des Zielsystems.
Die Pipeline endet an der Registry.
| Push | Pull | |
|---|---|---|
| Wer verbindet sich zu wem | Pipeline zum Ziel | Ziel zum Repository |
| Zugangsdaten für Produktion | in der Pipeline | im Zielsystem |
| Firewall | eingehend zum Ziel | nur ausgehend |
| Drift-Korrektur | nein | ja, laufend |
| Einrichtung | einfach | Agent nötig |
Der sicherheitstechnische Vorteil des Pull-Verfahrens ist erheblich: Die Pipeline braucht keine Produktionszugangsdaten mehr. Sie baut, prüft und legt in der Registry ab — mehr nicht. Wer die Pipeline übernimmt, hat damit noch keinen Zugriff auf die Produktion. Angesichts der Angriffsfläche aus Kapitel 7 ist das ein starkes Argument.
Bewährt hat sich die Trennung:
kfz-rechner/ (Anwendungsrepository)
├── src/
├── tests/
├── Containerfile
└── .gitlab-ci.yml baut das Image, legt es in der Registry ab
kfz-betrieb/ (Konfigurationsrepository)
├── test/
│ └── kfz-rechner.yaml Image-Tag: 2.5.1
├── abnahme/
│ └── kfz-rechner.yaml Image-Tag: 2.5.0
└── produktion/
└── kfz-rechner.yaml Image-Tag: 2.4.8
Warum getrennt? Der Ist-Zustand jeder Umgebung ist damit eine Zeile in einer Datei, und ein Deployment ist ein Commit. Der Git-Verlauf des Konfigurationsrepositories beantwortet lückenlos, welche Version wann in welcher Umgebung lief und wer sie freigegeben hat. Ein Rollback ist ein git revert.
Für regulierte Umgebungen ist das der entscheidende Punkt. Die Freigabe einer Produktivänderung wird zu einem Pull Request im Konfigurationsrepository — mit Prüfer, Zeitstempel und Begründung. Das Vier-Augen-Prinzip ist damit technisch erzwungen statt organisatorisch vereinbart, und der Nachweis fällt als Nebenprodukt an. Mehr dazu in Kapitel 17.
| Werkzeug | Umfeld | Anmerkung |
|---|---|---|
| Argo CD | Kubernetes, OpenShift | Weboberfläche, sehr verbreitet |
| Flux | Kubernetes | schlanker, stärker CLI-orientiert |
| OpenShift GitOps | OpenShift | Argo CD als Operator, integriert |
| systemd-Timer plus Skript | einzelner Server | reicht überraschend weit |
Die letzte Zeile ist ernst gemeint. GitOps ist ein Prinzip, kein Produkt — und auf einem einzelnen Server lässt es sich mit einem Zeitgeber und dreißig Zeilen Shell umsetzen.
Das offensichtliche Problem: Wenn alles in Git steht, stehen dort auch die Passwörter. Das darf nicht sein.
| Verfahren | Funktionsweise | Eignung |
|---|---|---|
| SOPS | Werte einzeln verschlüsselt, Struktur bleibt lesbar | gut, auch außerhalb von Kubernetes |
| Sealed Secrets | verschlüsselt für genau einen Cluster | Kubernetes |
| External Secrets Operator | verweist auf einen externen Tresor | Unternehmensumgebungen |
| Podman Secrets | Geheimnis lokal, Unit verweist darauf | einzelner Server |
# SOPS: Struktur lesbar, Werte verschlüsselt - gute Diffs im Git db: host: db-prod.intern benutzer: kfz_app passwort: ENC[AES256_GCM,data:8Kj2mQ==,iv:...,tag:...,type:str]
Ein häufiger Denkfehler: „Das Repository ist ja privat, da kann das Passwort ruhig im Klartext stehen.„
Ein privates Repository wird geklont — auf Notebooks, in CI-Runner, in Sicherungen. Es hat Leseberechtigte, die man nicht mehr überblickt, und es überlebt Personalwechsel. Der Klartext bleibt zudem für immer in der Historie, auch nach dem Löschen. Verschlüsselung kostet einen Nachmittag Einrichtung; der Alternativpfad kostet im Ernstfall den Wechsel sämtlicher Zugangsdaten.
#!/usr/bin/env bash # # Minimaler GitOps-Abgleich: holt den Sollzustand und stellt ihn her. # set -euo pipefail REPO="${HOME}/kfz-betrieb" UMGEBUNG="produktion" LOG_TAG="gitops" log() { logger -t "$LOG_TAG" "$*"; echo "$*"; } cd "$REPO" # --- 1. Sollzustand holen --- ALT="$(git rev-parse HEAD)" git fetch --quiet origin git reset --quiet --hard origin/main NEU="$(git rev-parse HEAD)" # --- 2. Gewünschtes Image aus der Konfiguration lesen --- SOLL_IMAGE="$(grep '^image:' "${UMGEBUNG}/kfz-rechner.yaml" | awk '{print $2}')" # --- 3. Ist-Zustand ermitteln --- IST_IMAGE="$(podman inspect kfz-rechner --format '{{.ImageName}}' 2>/dev/null || echo "keiner")" if [[ "$SOLL_IMAGE" == "$IST_IMAGE" ]]; then exit 0 # Soll = Ist, nichts zu tun fi log "Abweichung erkannt: ist=${IST_IMAGE} soll=${SOLL_IMAGE} (commit ${NEU:0:8})" # --- 4. Sollzustand herstellen --- podman pull "$SOLL_IMAGE" sed -i "s|^Image=.*|Image=${SOLL_IMAGE}|" \ "${HOME}/.config/containers/systemd/kfz-rechner.container" systemctl --user daemon-reload systemctl --user restart kfz-rechner.service # --- 5. Ergebnis prüfen, sonst zurückrollen --- sleep 5 if ! curl -fsS --max-time 5 http://127.0.0.1:8081/health > /dev/null; then log "FEHLER: Dienst antwortet nicht. Rolle zurück auf ${IST_IMAGE}." sed -i "s|^Image=.*|Image=${IST_IMAGE}|" \ "${HOME}/.config/containers/systemd/kfz-rechner.container" systemctl --user daemon-reload systemctl --user restart kfz-rechner.service exit 1 fi log "Abgleich erfolgreich: ${SOLL_IMAGE} (commit ${NEU:0:8})"
[Unit] Description=GitOps-Abgleich alle zwei Minuten [Timer] OnBootSec=2min OnUnitActiveSec=2min AccuracySec=10s [Install] WantedBy=timers.target
[Unit] Description=GitOps-Abgleich [Service] Type=oneshot ExecStart=/usr/local/bin/gitops-abgleich.sh
systemctl --user enable --now gitops-abgleich.timer systemctl --user list-timers journalctl --user -u gitops-abgleich.service -f
Aufgaben:
git revert im Konfigurationsrepository durch und stoppe die Zeit.Die letzte Frage ist die Pointe des Kapitels. Die Antwort lautet: keine. Die Pipeline endet an der Registry. Wer sie kompromittiert, kann ein Image ablegen — aber nichts ausrollen, solange niemand den entsprechenden Commit im Konfigurationsrepository freigibt.
| Anti-Pattern | Folge | Abhilfe |
|---|---|---|
| Änderungen von Hand am Zielsystem | werden beim nächsten Abgleich überschrieben — oder verhindern ihn | ausschließlich über Git |
| Geheimnisse im Klartext | Kompromittierung | SOPS, Sealed Secrets, externer Tresor |
| Anwendungs- und Konfigurationsrepository vermischt | Bauvorgang löst Deployment aus, keine saubere Freigabe | trennen |
| Abgleich ohne Prüfung | fehlerhafter Zustand wird stur hergestellt | Gesundheitsprüfung mit Rückfall |
| Kein Rückweg | Fehler wird endlos neu ausgerollt | Rollback im Skript vorsehen |
latest im Konfigurationsrepository | Git-Verlauf sagt nichts mehr aus | feste Version oder Digest |
Wenn jemand heute Nacht auf einem eurer Produktivsysteme von Hand eine Konfigurationsdatei ändert — wann und wie würdet ihr das erfahren?
Weiter mit Kapitel 12 — Observability