Deployments direkt aus der Pipeline auf den Cluster
Nicht jedes Team nutzt die GitLab-eigene Kubernetes-Integration. Oft reicht ein einfacher kubectl-Aufruf direkt aus der Pipeline heraus, solange Kubeconfig und Zugriffsrechte sauber und sicher konfiguriert sind. Dieser Artikel zeigt den kompletten Weg von der Kubeconfig-Variable bis zum geprueften Rollout.
Inhaltsverzeichnis
- 1. Kubernetes-Deployments direkt aus der Pipeline steuern
- 2. Kubeconfig sicher als CI-Variable bereitstellen
- 3. kubectl apply direkt aus dem CI-Job
- 4. Rollout-Status pruefen statt blind auf Erfolg zu vertrauen
- 5. Namespace- und Context-Handling pro Environment
- 6. RBAC und ServiceAccount: Zugriff auf das Noetigste beschraenken
- 7. Vergleich zur GitLab-eigenen Kubernetes-Integration
- 8. Rollback ueber kubectl bei fehlgeschlagenem Deployment
- 9. Fazit: kubectl aus der Pipeline heraus als pragmatischer Standardweg
- 10. Zusammenfassung
- 11. FAQ
1. Kubernetes-Deployments direkt aus der Pipeline steuern
Sobald eine Anwendung auf Kubernetes laeuft, stellt sich die Frage, wie ein neues Image nach erfolgreichem Build tatsaechlich auf dem Cluster landet. Der direkteste Weg ist ein kubectl-Aufruf innerhalb eines GitLab-CI-Jobs, der ein Deployment-Manifest anwendet oder ein bestehendes Deployment auf ein neues Image-Tag aktualisiert. Das ist technisch einfach, transparent nachvollziehbar im Pipeline-Log und ohne zusaetzliche GitLab-Features wie den Kubernetes Agent umsetzbar.
Der Ansatz eignet sich besonders fuer Teams, die bereits eine funktionierende kubectl-basierte Deployment-Routine von der Kommandozeile aus haben und diese lediglich automatisieren wollen, ohne die Architektur grundlegend zu aendern. Wichtig ist dabei, den Zugriff auf den Cluster so einzuschraenken, dass ein CI-Job nur das darf, was er tatsaechlich braucht, nicht mehr.
2. Kubeconfig sicher als CI-Variable bereitstellen
Die Kubeconfig-Datei enthaelt Zugangsdaten und Zertifikate fuer den Cluster-Zugriff und darf niemals im Repository landen. Der uebliche Weg ist, die vollstaendige Kubeconfig Base64-kodiert als geschuetzte, maskierte CI/CD-Variable vom Typ File anzulegen, in GitLab unter Settings > CI/CD > Variables. GitLab schreibt den Wert dann zur Laufzeit automatisch in eine temporaere Datei und stellt deren Pfad ueber die Variable selbst bereit, sodass kein manuelles Dekodieren im Skript noetig ist.
Fuer produktionsnahe Umgebungen sollte die Variable als protected markiert werden, sodass sie nur in Pipelines auf geschuetzten Branches oder Tags verfuegbar ist. Damit kann ein Merge Request von einem Feature-Branch aus niemals versehentlich Zugriff auf die Produktions-Kubeconfig erhalten, selbst wenn der Job-Name identisch mit dem Produktions-Deploy-Job waere.
# Kubeconfig lokal vorbereiten und Base64-kodieren
cat ~/.kube/config-production | base64 -w 0
# In GitLab: Settings > CI/CD > Variables
# Key: KUBECONFIG_PRODUCTION
# Typ: File
# Wert: <base64-dekodierter Inhalt oder direkt die Kubeconfig>
# Flags: Protected, Masked (falls unterstuetzt)
3. kubectl apply direkt aus dem CI-Job
Mit der Kubeconfig als Datei-Variable reicht ein schlanker Job, der das offizielle bitnami/kubectl-Image oder ein aehnliches, schlankes kubectl-Image nutzt und die Variable per KUBECONFIG-Umgebungsvariable referenziert. Statt eines vollstaendigen kubectl apply -f manifest.yaml empfiehlt sich in vielen Faellen kubectl set image, wenn lediglich ein neues Container-Image ausgerollt werden soll, ohne das restliche Manifest anzufassen.
Der Vorteil von kubectl set image gegenueber einem vollstaendigen apply ist, dass es gezielt nur das Image-Feld aendert und dadurch weniger Angriffsflaeche fuer versehentliche Konfigurationsaenderungen bietet, die eigentlich ueber einen separaten, bewussten Manifest-Commit laufen sollten. Fuer strukturelle Aenderungen am Deployment, etwa neue Environment-Variablen oder Resource-Limits, bleibt kubectl apply -f mit einem versionierten Manifest die richtige Wahl.
deploy-k8s:
stage: deploy
image: bitnami/kubectl:1.29
variables:
KUBECONFIG: $KUBECONFIG_PRODUCTION
script:
- kubectl config current-context
- kubectl set image deployment/api-service
api-service=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
--namespace=production
environment:
name: production
when: manual
4. Rollout-Status pruefen statt blind auf Erfolg zu vertrauen
kubectl set image oder kubectl apply kehren sofort zurueck, sobald Kubernetes die Aenderung entgegengenommen hat, unabhaengig davon, ob die neuen Pods tatsaechlich erfolgreich starten. Ein CI-Job, der nach dem apply-Befehl direkt als erfolgreich gilt, kann deshalb ein fehlerhaftes Deployment als gruene Pipeline durchwinken, obwohl die neuen Pods in einem CrashLoopBackOff haengen.
kubectl rollout status deployment/api-service --timeout=120s schliesst diese Luecke, indem der Befehl blockiert, bis der Rollout entweder erfolgreich abgeschlossen ist oder das Timeout erreicht wird, und dabei einen von null verschiedenen Exit-Code liefert, falls der Rollout fehlschlaegt. Dieser Exit-Code laesst den CI-Job dann korrekt fehlschlagen, was GitLab als rotes Pipeline-Ergebnis anzeigt und das Team unmittelbar informiert.
deploy-k8s:
stage: deploy
image: bitnami/kubectl:1.29
variables:
KUBECONFIG: $KUBECONFIG_PRODUCTION
script:
- kubectl set image deployment/api-service
api-service=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
--namespace=production
- kubectl rollout status deployment/api-service
--namespace=production --timeout=120s
environment:
name: production
when: manual
5. Namespace- und Context-Handling pro Environment
Bei mehreren Umgebungen wie staging und production lohnt es sich, fuer jede Umgebung eine eigene, klar benannte Kubeconfig-Variable und einen eigenen Namespace zu pflegen, statt einen einzigen Kubeconfig-Kontext per Skript umzuschalten. Das reduziert das Risiko, versehentlich mit dem falschen Kontext gegen den falschen Cluster zu arbeiten, deutlich, weil jeder Job von vornherein nur Zugriff auf genau eine Umgebung hat.
Die Umgebungsnamen in GitLab environment: sollten mit den Kubernetes-Namespaces uebereinstimmen oder zumindest eindeutig darauf abbilden, damit im GitLab Environments-Dashboard klar erkennbar ist, welcher Job welchen Cluster-Namespace betrifft. Diese Konsistenz erleichtert es spaeter auch, GitLab-Features wie Environment-URLs oder Deployment-Freezes sinnvoll zu nutzen.
6. RBAC und ServiceAccount: Zugriff auf das Noetigste beschraenken
Ein haeufiger Fehler ist, der CI-Pipeline eine Kubeconfig mit Cluster-Admin-Rechten zu geben, weil das die schnellste Loesung ist, um alle denkbaren kubectl-Befehle funktionsfaehig zu halten. Sicherer ist ein dediziertes ServiceAccount mit einer eng zugeschnittenen RBAC-Rolle, die nur Lese- und Schreibzugriff auf Deployments, Pods und ReplicaSets im relevanten Namespace erlaubt, keinen Zugriff auf Secrets anderer Namespaces oder Cluster-weite Ressourcen wie Nodes.
Ein Role- und RoleBinding-Paar, beschraenkt auf den Ziel-Namespace, reicht fuer die meisten Deployment-Pipelines vollstaendig aus. Das zugehoerige ServiceAccount-Token wird dann Teil der Kubeconfig, die als CI-Variable hinterlegt wird. Sollte diese Variable jemals kompromittiert werden, bleibt der Schaden auf die Rechte dieser eingeschraenkten Rolle begrenzt, statt den gesamten Cluster zu gefaehrden.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: ci-deployer
namespace: production
rules:
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "patch", "update"]
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
7. Vergleich zur GitLab-eigenen Kubernetes-Integration
GitLab bietet mit dem Kubernetes Agent eine alternative, tiefer integrierte Anbindung, bei der ein Agent-Pod innerhalb des Clusters laeuft und eine ausgehende Verbindung zu GitLab aufbaut, statt dass die Pipeline aktiv mit Zugangsdaten auf den Cluster zugreift. Das hat den Vorteil, dass keine Kubeconfig mit Zugangsdaten als CI-Variable gepflegt werden muss und der Cluster keine eingehenden Verbindungen von GitLab-Runnern erlauben muss, was in vielen Netzwerk-Setups sicherheitstechnisch vorzuziehen ist.
Der direkte kubectl-Ansatz aus diesem Artikel bleibt trotzdem relevant, weil er ohne zusaetzliche Agent-Installation im Cluster funktioniert, sich leichter debuggen laesst, da jeder Befehl explizit im Pipeline-Log sichtbar ist, und sich nahtlos in bestehende, bereits etablierte kubectl-Workflows einfuegt. Fuer kleinere Teams oder Projekte, bei denen der Aufwand fuer die Agent-Installation den Nutzen uebersteigt, bleibt die direkte Variante die pragmatischere Wahl.
8. Rollback ueber kubectl bei fehlgeschlagenem Deployment
Kubernetes speichert standardmaessig die Historie vorheriger ReplicaSet-Revisionen eines Deployments, wodurch kubectl rollout undo deployment/api-service --namespace=production das Deployment ohne manuelles Zuruecksetzen des Image-Tags auf die vorherige funktionierende Version zuruecksetzt. Das ist deutlich schneller als ein erneuter apply mit dem alten Image-Tag, weil Kubernetes selbst die letzte bekannte funktionierende Konfiguration vorhaelt.
Ein manueller Rollback-Job in der .gitlab-ci.yml, der when: manual nutzt, macht diesen Befehl jederzeit per Klick verfuegbar, ohne eine neue Pipeline anlegen zu muessen. Nach dem rollout undo empfiehlt sich erneut kubectl rollout status, um sicherzustellen, dass auch der Rollback selbst erfolgreich abgeschlossen wurde und nicht in einem weiteren fehlerhaften Zustand haengen bleibt.
rollback-k8s:
stage: deploy
image: bitnami/kubectl:1.29
variables:
KUBECONFIG: $KUBECONFIG_PRODUCTION
script:
- kubectl rollout undo deployment/api-service --namespace=production
- kubectl rollout status deployment/api-service
--namespace=production --timeout=120s
environment:
name: production
when: manual
9. Fazit: kubectl aus der Pipeline heraus als pragmatischer Standardweg
kubectl direkt aus GitLab CI heraus zu steuern, ist ein einfacher, transparenter und gut debugbarer Ansatz, der ohne zusaetzliche Infrastruktur im Cluster auskommt. Entscheidend fuer die Sicherheit ist eine restriktive RBAC-Rolle statt Cluster-Admin-Rechten sowie eine geschuetzte, dateibasierte CI-Variable fuer die Kubeconfig.
Wer bereits mehrere Cluster oder Umgebungen betreibt und zusaetzliche Sicherheit ohne eingehende Cluster-Verbindungen sucht, sollte den GitLab Kubernetes Agent als Alternative pruefen. Fuer die meisten kleineren bis mittleren Projekte reicht der direkte kubectl-Weg jedoch vollstaendig aus und laesst sich schneller einrichten.
| Methode | Setup-Aufwand | Sicherheitsmodell | Empfohlen fuer |
|---|---|---|---|
| Direktes kubectl aus CI-Job | Gering | Kubeconfig als geschuetzte Variable, ausgehend zu Cluster-API | Kleinere Teams, einfache Setups |
| GitLab Kubernetes Agent | Mittel bis hoch | Agent im Cluster, ausgehende Verbindung zu GitLab | Mehrere Cluster, hoehere Sicherheitsanforderungen |
| GitOps-Tool (z.B. ArgoCD, Flux) | Hoch | Deklarative Synchronisation, kein direkter CI-Zugriff auf Cluster | Groessere Teams mit vielen Deployments, hoher Automatisierungsgrad |
| Manuelles kubectl auf der CLI | Keins | Persoenliche Kubeconfig, kein Audit-Trail in GitLab | Nur fuer Debugging, nicht fuer Produktion |
Mironsoft
CI/CD-Pipelines, Zero-Downtime-Deployments und Release-Automatisierung
Deployments, die ohne Ausfallzeit und ohne Nervenkitzel laufen?
Wir prüfen bestehende GitLab-Pipelines auf fragile Deployment-Schritte und fehlende Absicherung und bauen daraus einen Release-Prozess mit Zero-Downtime-Deployments, automatisierten Checks und einem Rollback, dem ihr im Ernstfall vertrauen könnt.
Pipeline-Review
Bestehende .gitlab-ci.yml auf Fragilität, fehlende Stages und Sicherheitslücken prüfen.
Zero-Downtime-Deployment
Symlink-Releases, Health-Checks und Rollback-Strategien für Magento-Shops aufbauen.
CI/CD-Automatisierung
Tests, Security-Scans und Deployments zu einer zuverlässigen Pipeline verbinden.
10. Zusammenfassung
kubectl aus GitLab CI: Das Wichtigste auf einen Blick
Kubeconfig als File-Variable
Base64-kodierte Kubeconfig als geschuetzte, dateibasierte CI/CD-Variable hinterlegen.
Rollout-Status pruefen
kubectl rollout status nach jedem Deploy verhindert falsch-gruene Pipelines bei fehlgeschlagenen Rollouts.
Restriktives RBAC
Ein ServiceAccount mit eng zugeschnittener Role statt Cluster-Admin-Rechten begrenzt den Schaden bei Kompromittierung.
Agent als Alternative
Der GitLab Kubernetes Agent vermeidet eingehende Cluster-Verbindungen, kostet aber mehr Setup-Aufwand.