Jenkins-Pipeline: Local → Test → QS → Prod

Zielgruppe: DevOps. Zusätzlich zur bestehenden GitHub-Actions-Pipeline (siehe infra/ci/README.md) - beide bewusst nebeneinander demonstriert, wie Eureka UND Kubernetes-native Discovery in ADR-0007. Setzt Podman voraus, sonst nichts weiter (kein echter Kubernetes-Cluster nötig, siehe "Stolperstein" unten).

Die vier Stufen

Stufe Womit Auslöser Ziel
Local IntelliJ (oder jede andere IDE) + podman compose up -d für die Infrastruktur (Podman-Machine unter Windows) manuell, jederzeit localhost, kein Namespace
Test Jenkins, Stufen "Build & Unit-Tests" bis "Deploy nach Test" automatisch bei jedem Pipeline-Lauf Namespace library-test
QS Jenkins, Stufe "Deploy nach QS" automatisch, direkt nach Test Namespace library-qs
Prod Jenkins, Stufe "Deploy nach Prod" manuell freigegeben (input-Step) Namespace library

Local ist keine Jenkins-Stufe - es ist der Ausgangspunkt davor: eine Entwicklerin startet die Infrastruktur (cd infra && podman compose up -d postgres kafka rabbitmq redis keycloak, siehe docker-compose-guide.md) und lässt genau den Service, an dem sie gerade arbeitet, aus der IDE heraus laufen (mvn spring-boot:run bzw. IntelliJs eigener Spring-Boot-Run-Konfiguration, Default-Profil, zeigt auf localhost). Erst ein Push/PR stößt die Pipeline an, die dann automatisch bis Test und QS durchläuft und vor Prod auf eine explizite Freigabe wartet.

Jenkins lokal starten

Seit Phase 12 lebt Jenkins NICHT mehr in diesem Repository, sondern zentral, projekt- übergreifend in enterprise-workspace/shared/enterprise-infrastructure/ - ein einziges Jenkins für alle lokal angeschlossenen Lernprojekte statt eines pro Projekt (RAM-/Boot-Zeit- schonender, entspricht dem, wie ein echtes Team auch nicht pro Repository einen eigenen Jenkins-Server betreibt):

cd ../../shared/enterprise-infrastructure   # relativ zu diesem Projekt
podman compose up -d

Läuft unabhängig davon, welches Lernprojekt gerade geöffnet ist - einmal starten reicht, bleibt im Hintergrund verfügbar. Details (Aufbau, wie ein weiteres Projekt sich anschließt, Grenzen) siehe shared/enterprise-infrastructure/README.md.

Anders als bei einem gehosteten Dienst wie Bitbucket (SaaS - Atlassian betreibt den Server, man meldet sich nur an) ist Jenkins Software, die man selbst betreibt. Es gibt zwar auch einen nativen Windows-Installer auf jenkins.io, der laeuft aber ohne die im geteilten shared/enterprise-infrastructure/jenkins/Dockerfile vorinstallierten Werkzeuge (Maven, Node, Podman/Buildah, Helm, kubectl, Chromium) - die muessten dann manuell auf Windows installiert und in Jenkins konfiguriert werden. Der Container-Weg oben ist deshalb der in diesem Projekt vorgesehene. (Das Agent-Image muss podman mitbringen - nachzuruesten in enterprise-infrastructure, dem Nachbar-Repo.)

Was mit Jenkins-Daten (Jobs, Build-Historie, Credentials) beim Stoppen, Neuinstallieren der Container-Laufzeit oder beim Ziehen einer neueren Jenkins-Version passiert - inklusive des Zusammenspiels zwischen dem jenkins-data-Volume und plugins.txt - siehe docker-compose-guide.md (die dortige Erklärung gilt unverändert, nur dass das Volume jetzt in enterprise-infrastructure statt in diesem Projekt verwaltet wird).

Web-UI: http://jenkins.localhost (kein localhost:<port> mehr nötig - siehe reverse-proxy.md für den vollen Kontext, warum und wie das funktioniert). Anmeldedaten per Umgebungsvariable (JENKINS_ADMIN_USER/JENKINS_ADMIN_PASSWORD in shared/enterprise-infrastructure/docker-compose.yml, Default admin/admin - für den lokalen Lernbetrieb, nicht für einen Mehrnutzer-Betrieb gedacht). Der Pipeline-Job library-platform-pipeline existiert nach dem Start automatisch (siehe shared/enterprise-infrastructure/jenkins/casc.yaml, Jenkins Configuration-as-Code) - kein Klicken durch den Setup-Wizard nötig.

Voraussetzung für einen echten Build: ein Git-Credential. Dieses Repository ist privat - ein realer Testlauf (per REST-API ausgelöst, siehe Verifikation unten) scheiterte prompt beim git fetch mit Invalid username or token. Password authentication is not supported for Git operations. - GitHub verweigert anonymes Klonen. Unter "Manage Jenkins → Credentials" ein Credential vom Typ "Username with password" anlegen (Username = GitHub-Login, Passwort = ein GitHub Personal Access Token mit repo-Scope, KEIN echtes Passwort - GitHub akzeptiert seit Langem nur noch Token), danach in der Job-Konfiguration unter "Source Code Management" als Credentials auswählen. Bewusst nicht in casc.yaml vorbelegt - ein Token ist ein Geheimnis (siehe PR-Checkliste, Security) und gehört nicht in eine versionierte Datei, exakt dieselbe Begründung wie bei den fehlenden KUBECONFIG_*-Credentials weiter unten.

Alle Werkzeuge, die das Jenkinsfile braucht (Maven 3.9.9, Node 20, Podman/Buildah, Helm, kubectl, Chromium), sind bereits im Image gebaut (siehe shared/enterprise-infrastructure/jenkins/Dockerfile) - deshalb kommt das Jenkinsfile ohne Jenkins' eigene, UI-gestützte Tool-Auto-Provisionierung aus. Diese Versionen sind aktuell auf DIESES eine Projekt zugeschnitten - Grenzen dieses Ansatzes, sobald ein zweites Projekt mit anderen Tool-Versionen dazukommt, siehe shared/enterprise-infrastructure/README.md, Abschnitt "Grenzen".

Wie die Umgebungen sich unterscheiden

Kein dupliziertes Set an Values-Dateien pro Umgebung (8 Services × 3 Umgebungen = 24 Dateien wären unübersichtlich). Stattdessen nutzt die Pipeline Helms Layering-Mechanismus: die bestehenden infra/helm/values/<service>-values.yaml (2 Replicas, Autoscaling an) sind bereits "Prod-Shape" - für Prod ändert sich nichts. Für Test und QS liegt je EINE zusätzliche, service-übergreifende Overlay-Datei unter infra/helm/values/env/ (test-values.yaml, qs-values.yaml), die als zweite -f hinter der Service-Datei übergeben wird:

helm upgrade --install catalog-service infra/helm/library-service \
  -f infra/helm/values/catalog-service-values.yaml \
  -f infra/helm/values/env/test-values.yaml \
  -n library-test --create-namespace --set image.tag=<git-sha>

Test reduziert Replica-Anzahl und Ressourcen-Limits (schnelle, günstige Automatisierung), QS bleibt näher an Prod-Größen, aber ohne Autoscaling (wenige gleichzeitige menschliche Tester:innen brauchen keine automatische Lastskalierung).

Stolperstein: kein echter Kubernetes-Cluster vorhanden (QS/Prod) - Test-Stufe seit Phase 11 gelöst

Wie in kubernetes-guide.md ausführlich dokumentiert, lief für dieses Projekt lange kein funktionierender Kubernetes-Cluster (CodeReady-Containers/OKD-Versuch an abgelaufenen Zertifikaten und RAM-Konflikten mit der lokalen Compose-Infrastruktur gescheitert). Die Deploy-Stufen würden ins Leere laufen, wenn sie das einfach ignorieren würden.

Lösung, ehrlich statt vorgetäuscht: jede Deploy-Stufe versucht zuerst, ein Jenkins-Credential namens KUBECONFIG_TEST/KUBECONFIG_QS/KUBECONFIG_PROD (Typ "Secret file") zu laden. Fehlt es, fällt die Stufe automatisch auf helm template (Dry-Run, reines Rendern der Kubernetes-Manifeste ohne sie irgendwohin zu schicken) zurück, genau wie es der bestehende helm-lint-Job in .github/workflows/ci.yml heute schon tut. Die Pipeline ist damit immer lauffähig und grün, ohne einen Cluster zu behaupten, den es nicht gibt.

Für die Test-Stufe ist das seit Phase 11 kein Dry-Run-Dauerzustand mehr: ein lokaler kind-Cluster (siehe kind-cluster.md) liefert ein echtes KUBECONFIG_TEST, gegen das "Deploy nach Test" wirklich deployt (inklusive kind load docker-image, mit KIND_EXPERIMENTAL_PROVIDER=podman, vor jedem Helm-Aufruf, siehe loadImageIntoKindIfClusterAvailable im Jenkinsfile). QS und Prod bleiben bewusst Dry-Run-Kandidaten: in der Realität wären das separate, dauerhafte Cluster (Cloud-Managed oder ein eigener CRC/OKD-Cluster), nicht das Laptop einer einzelnen Person, das nach jedem Neustart wieder bei null anfängt - für sie gilt weiterhin, einfach die passenden Credentials unter "Manage Jenkins → Credentials" anzulegen, sobald ein solcher Cluster verfügbar ist, kein Code-Änderung nötig.

Vertiefungsaufgaben (nicht umgesetzt)

⌂ Cockpit