Voraussetzung: ein Cluster mit oc login
als Admin, Namespace library. Die interne Registry muss eingeschaltet sein
(Schritt 7 zeigt wie). Auf SNO/CRC steht sie per Default auf Removed.
1 Die Kette im Überblick
Vier Objektarten, ein Weg: Quellcode wird zu einem laufenden Container.
Nur Schritt 2 und 3 (BuildConfig, Build-Pod) sind optional – wer extern baut (wie die Bibliothek, Schritt 12), pusht direkt in Schritt 4 und überspringt den Build-Pod im Cluster komplett.
2 Mit oc new-app starten
oc new-app rät aus der Eingabe, was zu tun ist, und legt einen
ganzen Satz Objekte auf einmal an.
oc new-app ist ein schlaues Gerüst-Werkzeug: du gibst ihm etwas, es rät, was du willst, und legt einen Satz Objekte an. Eine Git-URL wird zu Build-Kette plus Deployment, ein Image nur zu einem Deployment, ein Template zu dessen Objekten. Gut zum Ausprobieren – für Produktion nimmt man Helm.
oc new-app erkennt an der Eingabe, was du willst: eine Git-URL wird zu ImageStream + BuildConfig + Deployment + Service, ein Container-Image nur zu Deployment + Service, ein Template zu dessen Objekten. Eine Route legt es nicht an – die kommt mit oc expose. oc new-build macht nur die Build-Seite. Mit --dry-run -o yaml siehst du alles vorher.oc new-apprät aus der Eingabe: Git-URL → BuildConfig + S2I, Image → nur Deployment, Template → dessen Objekte- legt typisch an:
ImageStream(s),BuildConfig,Deployment,Service - keine Route – die kommt separat mit
oc expose svc/catalog(B4) - die Sprache wird an Dateien im Repo erkannt (
pom.xml,package.json,go.mod…) → passendes Builder-Image oc new-app -o yaml --dry-run=clientzeigt alles vorher, ohne etwas anzulegenoc new-build: nur die Build-Seite (ImageStream + BuildConfig), kein Deployment – für den Fall, dass der Deploy woanders liegt-l app=catalogsetzt gemeinsame Labels →oc delete all -l app=catalogräumt den ganzen Satz zusammen auf- weitere Flags:
--name=,-e KEY=val,--strategy=docker|source,-i <imagestream>,--context-dir= - seit OCP 4.14 entsteht ein
Deployment, nichtDeploymentConfig(B2) - gut zum Ausprobieren und für die Prüfung – für Produktion nimmt man Helm (B11) oder Kustomize (deklarativ, versioniert, reviewbar)
- Trick:
oc new-app --dry-run -o yamlals Startpunkt für ein eigenes Chart abgreifen - Bibliothek:
new-apphöchstens zum Skizzieren – die 8 Dienste kommen als Helm-Chart (ein generischeslibrary-service-Chart je Dienst gefüllt), deployt von Jenkins nach dem externen Build (E1) - OCP-Unterschied:
oc new-appist OpenShift-eigen – das nächste Kubernetes-Äquivalent istkubectl create deployment
# zuerst nur ansehen, ohne etwas anzulegen: oc new-app https://github.com/sclorg/nodejs-ex -n library --dry-run=client -o yaml --name=demo-build | head -40 # jetzt wirklich: oc new-app https://github.com/sclorg/nodejs-ex -n library --name=demo-build -l app=demo-build oc get is,bc,deploy,svc -n library -l app=demo-build
new-app legt typisch an: einen ImageStream (Schritt 6), ein
BuildConfig (Schritt 3), ein Deployment und einen
Service. Keine Route – die kommt separat mit
oc expose svc/demo-build. Die Sprache wird an Dateien im Repo erkannt
(package.json, pom.xml, go.mod…), das passende
S2I-Builder-Image wird automatisch gewählt.
nur die Build-Seiteoc new-build
legt nur ImageStream + BuildConfig an, kein Deployment – für den
Fall, dass der Deploy woanders liegt (Helm, Schritt 12).
3 Das BuildConfig-Objekt
Das Rezept „wie entsteht dieses Image“ – jeder Lauf ist ein
eigenes Build-Objekt in einem Build-Pod.
Ein BuildConfig beschreibt, wie aus Quellcode ein Image wird. Jeder Lauf ist ein Build-Objekt, ausgeführt in einem Build-Pod (als builder-SA). Drei Strategien: S2I (Code + Builder-Image, kein Dockerfile), Docker (aus einem Dockerfile), custom (eigenes Builder-Image steuert alles). Ergebnis landet als ImageStreamTag (C1).
BuildConfig hält Input (Git / Binary / Dockerfile), Strategie (S2I / Docker / Custom) und Output. Jeder Build läuft in einem Build-Pod als builder-SA und pusht das Ergebnis als ImageStreamTag. Trigger (Webhook, ImageChange, ConfigChange) starten ihn. Der Haken: Build-Pods brauchen Cluster-CPU – auf kleinen Clustern baut man besser außerhalb und spiegelt nur (C1).- ein
BuildConfigist das Rezept „wie entsteht dieses Image“ – jeder Lauf ist einBuild-Objekt in einem Build-Pod (alsbuilder-SA) - Source (S2I): Quellcode + Builder-Image → fertiges App-Image, kein Dockerfile – das
assemble-Skript baut (C3) - Docker: baut aus einem
Dockerfileim Repo – intern mit Buildah, kein Docker-Daemon im Cluster - Custom: ein eigenes Builder-Image bestimmt den ganzen Ablauf (selten, für Spezial-Tooling)
- Input: Git (mit
ref), Binary (oc start-build --from-dir), Dockerfile inline, Files aus einem anderen Image –contextDirfür Monorepos - Trigger am BuildConfig: Webhook (GitHub / GitLab / Bitbucket / generic, eine URL im Repo), ImageChange am Builder-Image (holt Base-Image-Patches automatisch), ConfigChange
- Output: gepusht als
ImageStreamTagin die interne Registry (C5) – der neue Digest kann über einen Image-Trigger den Rollout auslösen (C1, C6) - Lebenszyklus: New → Pending → Running → Complete / Failed / Error / Cancelled.
runPolicy: Serial / Parallel / SerialLatestOnly - der Haken: Build-Pods brauchen Cluster-CPU – auf der Single-Node-SNO konkurrieren sie direkt mit den 8 laufenden Diensten
- wann man S2I doch nimmt: kein
Dockerfilepflegen wollen, oder Auto-Rebuild bei einem Base-Image-CVE (ImageChange am Builder). Wer schon eine CI hat, baut besser dort - Befehle:
oc start-build catalog --from-dir=. --follow,oc logs -f build/catalog-3,oc cancel-build catalog-3,oc get builds - Bibliothek: kein
BuildConfigim Cluster – Jenkins baut die 9 Images mitpodman build(Maven im Container gegen die Host-Engine), dannpodman pushin die interne Registry. Die ImageStreams entstehen durch den Push, nicht durch einen Build-Pod - OCP-Unterschied: identisch – die Docker-Strategie nutzt in beiden Buildah
| Strategie | macht |
|---|---|
| Source (S2I) | Quellcode + Builder-Image → fertiges App-Image, kein Dockerfile nötig – das assemble-Skript des Builder-Images baut |
| Docker | baut aus einem Dockerfile im Repo – intern mit Buildah, kein Docker-Daemon im Cluster |
| Custom | ein eigenes Builder-Image bestimmt den ganzen Ablauf – selten, für Spezial-Tooling |
Trigger am BuildConfig: ein Webhook (GitHub/GitLab/generic, eine URL im
Repo), ImageChange am Builder-Image (holt Base-Image-Patches automatisch
nach), ConfigChange. Lebenszyklus:
New → Pending → Running → Complete (oder
Failed/Error/Cancelled).
runPolicy steuert, ob parallele Builds erlaubt sind:
Serial, Parallel, SerialLatestOnly.
4 Einen Build laufen lassen
Ein manueller Start, live verfolgt.
oc start-build demo-build -n library --follow # oder ohne zu warten: oc start-build demo-build -n library oc get builds -n library oc logs -f build/demo-build-2 -n library # ein Build, der zu lange braucht oder haengt: oc cancel-build demo-build-2 -n library
der Haken auf SNOBuild-Pods brauchen echte Cluster-CPU – auf einer Single-Node konkurrieren sie direkt mit allen laufenden Diensten. Ein Build mitten in einer Demo kann spürbar bremsen.
Fertig gebaut landet das Image automatisch als neuer Eintrag im ImageStream
(Schritt 6) – oc get istag demo-build:latest zeigt den frischen Digest.
5 Webhook live auslösen
oc new-app hat in Schritt 2 automatisch zwei Webhook-Trigger
mit zufälligem Secret angelegt – die sieht man sich einmal live an, statt sie nur
als Konzept zu kennen.
oc describe bc/demo-build -n library | grep -A2 "Webhook"
# Webhook Generic:
# URL: https://api.sno.<ip>.nip.io:6443/apis/build.openshift.io/v1/namespaces/library/buildconfigs/demo-build/webhooks/<secret>/generic
# Webhook GitHub:
# URL: https://api.sno.<ip>.nip.io:6443/.../webhooks/<secret>/github
# die generic-URL genuegt sich selbst - einfach POSTen loest einen Build aus:
WEBHOOK_URL=$(oc describe bc/demo-build -n library | awk '/Webhook Generic/{getline; print $2}')
curl -sk -X POST "$WEBHOOK_URL"
oc get builds -n library -w
Ein echtes GitHub-/GitLab-/Bitbucket-Repo trägt genau so eine URL
unter Settings → Webhooks ein – ein Push landet dann automatisch hier.
Der Unterschied zur generic-URL: die drei Provider-Typen parsen den Payload
und prüfen darin den Branch gegen spec.source.git.ref – passt der
Branch nicht, wird der Build still ausgelassen (der Webhook antwortet
trotzdem mit 200). generic prüft nur das Secret in der URL, keinen Branch,
außer du schickst selbst einen git.ref im JSON-Body mit.
wo das Secret herkommtBei oc new-app
generiert OpenShift es automatisch. Von Hand:
oc set triggers bc/demo-build --from-webhook --webhook-secret=<secret>,
oder in der YAML unter spec.triggers[].generic.secretReference.
6 ImageStream, Digest, die Tag-Falle
Ein ImageStream ist ein clusterinterner, namespaced Zeiger auf Images – er speichert keine Bytes, sondern je Tag die Digest-Historie.
Ein ImageStream speichert keine Image-Bytes – das Image liegt in einer Registry. Der Stream führt Buch: welcher Digest (sha256) stand wann hinter welchem Tag. Zusammen mit dem Image-Trigger (C6) löst das die klassische Tag-Falle: ein neuer Push unter :latest löst auf OpenShift wirklich einen Rollout aus.
ImageStream hält keine Bytes – die liegen in der Registry. Er merkt sich, welcher Digest hinter jedem Tag stand. Der Image-Trigger (C6) schreibt diesen Digest in die Pod-Vorlage, statt den Tag stehen zu lassen. Darum löst ein erneuter Push unter :latest hier wirklich einen Rollout aus – die Tag-Falle, die reines Kubernetes hat, ist zu. Freigeben heißt einen Zeiger verschieben: oc tag catalog:sha-abc catalog:prod.- ein
ImageStreamist ein clusterinterner, namespaced Zeiger auf Images – er speichert keine Bytes, sondern je Tag die Digest-Historie - ein
ImageStreamTag(catalog-service:9f3ab21,catalog-service:prod) ist eine Marke, die zu einem Digest (sha256) auflöst - die Tag-Falle: mit reinem Kubernetes bleibt die Pod-Vorlage bei
catalog:latest– ein erneuter Push ändert sie nicht, es passiert nichts - OpenShift löst sie auf zwei Arten: der Image-Trigger (C6) trägt den neuen Digest in die Pod-Vorlage – oder man pusht von vornherein unter einem unveränderlichen Tag (so macht es die Bibliothek)
- der einzige Ort, an dem
:latestzuverlässig wirkt – im Chart und im Deployment sonst nie:latest - Freigabe durch Um-Taggen:
oc tag catalog-service:9f3ab21 catalog-service:prod– ein Release ist nur ein Zeiger, atomar und umkehrbar - ein externes Image in den Cluster holen:
oc import-image catalog --from=ghcr.io/org/catalog:1.4 --confirm,importPolicy.scheduled: trueimportiert periodisch nach lookupPolicy.local: truelässt ein reinesDeploymentden Tag über den Stream auflösen, statt die Registry direkt zu nennen- Pods ziehen mit dem Token der
default-/builder-SA – kein Extra-Secret für die interne Registry (C5) - Befehle:
oc get is,oc get istag,oc describe is catalog-service(Digest-Historie),oc tag,oc import-image - Preis:
ImageStreamgibt es nur bei OpenShift – ein Helm-Chart, dasImageStreamTag-Referenzen nutzt, läuft auf reinem Kubernetes nicht - Bibliothek: Jenkins baut die 9 Images außerhalb und
podman pushsie in die interne Registry – der Pfadlibrary/catalog-service:<git-sha>legt automatisch einenImageStreamcatalog-servicein nslibraryan. Ein unveränderlicher Tag je Build, darum kein:latestund kein Image-Trigger nötig - OCP-Unterschied: identisch – ImageStreams sind Kern-OpenShift, in OKD und OCP gleich
oc get is demo-build -n library
oc describe is demo-build -n library # zeigt die Digest-Historie je Tag
oc get istag demo-build:latest -n library -o jsonpath='{.image.dockerImageReference}{"\n"}'
die Tag-FalleMit reinem Kubernetes bleibt
die Pod-Vorlage bei demo-build:latest – ein erneuter Push ändert sie
nicht, es passiert einfach nichts. OpenShift löst das auf zwei Arten:
ein Image-Trigger (C6) trägt den neuen Digest automatisch in die
Pod-Vorlage ein – oder man pusht von vornherein unter einem unveränderlichen
Tag (so macht es die Bibliothek, Schritt 12).
Ein externes Image in den Cluster holen: oc import-image demo --from=registry.access.redhat.com/ubi9/ubi:latest --confirm,
importPolicy.scheduled: true importiert periodisch nach.
lookupPolicy.local: true lässt ein reines Deployment den Tag über den
Stream auflösen, statt die Registry direkt zu nennen. Pods ziehen mit dem Token der
default-/builder-ServiceAccount – kein Extra-Secret für
die interne Registry nötig.
7 Die interne Registry von Hand
Der image-registry-ClusterOperator verwaltet sie im Namespace
openshift-image-registry – auf SNO/CRC per Default auf Removed.
OpenShift bringt eine eigene Container-Registry mit, verwaltet von einem Operator. Sie hat zwei Adressen: eine interne (im Cluster, zum Ziehen und für Build-Pods) und eine externe Route (zum Schieben von außen, muss erst freigeschaltet werden). Pods ziehen ohne Extra-Secret. oc adm prune images hält sie klein.
ClusterIP-Service unter image-registry.openshift-image-registry.svc:5000 – dahin ziehen Pods und schieben Build-Pods. Die externe Route default-route-openshift-image-registry.apps.<cluster> existiert erst nach defaultRoute: true; dahin schiebt man mit podman login (Token über --password-stdin). Pods brauchen kein Extra-Secret. oc adm prune images zeigt die Vorschau; mit --confirm wird gelöscht.- ein Operator (
image-registry-ClusterOperator) verwaltet sie im Namespaceopenshift-image-registry– auf SNO/CRC steht sie per Default aufRemoved - einschalten:
oc patch configs.imageregistry.operator.openshift.io/cluster --type=merge -p '{"spec":{"managementState":"Managed","defaultRoute":true}}'plus ein Storage-Backend - zwei Adressen: innen
image-registry.openshift-image-registry.svc:5000(ClusterIP, zum Ziehen und für Build-Pods) - außen
default-route-openshift-image-registry.apps.<cluster>(eine Route) – existiert erst nachdefaultRoute: true, dahin schiebt man vom Laptop oder aus der CI - selbstsigniertes Zertifikat →
podman push --tls-verify=falseoder die Router-CA vertrauen - Anmeldung:
oc whoami -t | podman login -u kubeadmin --password-stdin default-route-openshift-image-registry.apps.<cluster>– das Token landet nicht in der Shell-History - Pods ziehen ohne Extra-Secret: die
default-/builder-SA jedes Namespace hat ein auto-provisioniertes Pull-Secret für die interne Registry (A6, B10) - cross-namespace ziehen: der ziehenden SA die Rolle
oc policy add-role-to-user system:image-puller ... -n <quell-namespace>geben - Pruning:
oc adm prune images --keep-tag-revisions=3 --keep-younger-than=60mzeigt eine Vorschau,--confirmerst nach Prüfung ergänzen - automatisch: der
imagePruner-CronJob (im Operator konfiguriert) – ohne Pruning läuft der Storage voll und Pushes schlagen fehl - jeder Push aktualisiert die Tag-Historie des
ImageStream(C1) - Bibliothek: die interne Registry ist das Ziel für alle 9 Images. Einmalig
managementState: Managed, ein Storage-PVC (vorab als RWO anlegen – der Operator will RWX,local-pathkann nur RWO),defaultRoute: true. Jenkins pusht mit dem Dauer-Token derpipeline-SA (Rollensystem:image-builder+registry-editor), Credokd-registry - nach
sno.ps1 uphängt der Operator an einer veralteten Leader-Lease (Attempting to acquire leader lease) – der Post-up-Hook (sno-wsl.sh remediate) löscht sie, sonst bekommt der erstepodman loginein connection refused - Status:
oc get co image-registry. OCP-Unterschied: identisch – Quay ist ein zusätzliches Produkt, keine Voraussetzung
# einschalten (Storage-PVC vorher als RWO anlegen, siehe G3):
oc patch configs.imageregistry.operator.openshift.io/cluster --type=merge \
-p '{"spec":{"managementState":"Managed","defaultRoute":true}}'
oc get co image-registry -w
# anmelden - das Token landet nicht in der Shell-History:
HOST=$(oc get route default-route -n openshift-image-registry -o jsonpath='{.spec.host}')
oc whoami -t | podman login -u kubeadmin --password-stdin --tls-verify=false "$HOST"
# ein Image von aussen pushen:
podman tag registry.access.redhat.com/ubi9/ubi-minimal:latest "$HOST/library/handtest:v1"
podman push --tls-verify=false "$HOST/library/handtest:v1"
oc get is handtest -n library
Zwei Adressen: innen image-registry.openshift-image-registry.svc:5000
(ClusterIP, zum Ziehen und für Build-Pods), außen die Route aus
defaultRoute: true – dahin schiebt man vom Laptop oder aus der CI. Das
Zertifikat ist auf OKD/SNO selbstsigniert, darum --tls-verify=false oder die
Router-CA vertrauen. Cross-namespace ziehen braucht eine Extra-Rolle:
oc policy add-role-to-user system:image-puller system:serviceaccount:<ns>:default -n library.
8 Freigabe durch Um-Taggen
Ein Release ist nur ein Zeiger – atomar und umkehrbar, kein Rebuild.
oc tag library/demo-build:latest library/demo-build:prod oc get istag demo-build:prod -n library # ein Rollback ist derselbe Befehl, rueckwaerts: oc tag library/demo-build:v-vorherige library/demo-build:prod
Ein Deployment, das demo-build:prod referenziert (mit
lookupPolicy.local: true), sieht den neuen Digest sofort – ohne Rebuild,
ohne Push. Genau das nutzen Image-Trigger (C6), um einen Rollout auszulösen, sobald sich
ein Tag bewegt.
9 Branch, Trigger, Umgebung
Das klassische Muster: feature/… baut nur, develop
deployt nach Test/QS, main oder release/… deployt nach Prod
– jeder Branch löst über denselben Webhook-Mechanismus (Schritt 5) etwas
anderes aus.
spec.source.git.ref: develop hört auf genau diesen Branch – Build → Tag :test → Deploy mit dem Test-Overlayspec.source.git.ref: main – Build → Tag :prod → Deploy mit dem Prod-Overlay, oft mit manueller Freigabe davorDer Trick liegt in Schritt 5: die drei Provider-Webhooks prüfen
den Branch aus dem Payload gegen spec.source.git.ref – ein Push auf
feature/x trifft die Webhook-URL des develop-BuildConfigs zwar auch
(dieselbe Repo-Konfiguration meldet an alle passenden Hooks), löst dort aber
keinen Build aus, weil der Branch nicht passt. Ein BuildConfig pro Umgebung
ist deshalb der einfachste Weg, Branch und Umgebung fest zu verdrahten – die Alternative
ist ein CI-System außenrum (Jenkins Multibranch, Tekton mit einem CEL-Interceptor-Filter auf
body.ref), das selbst entscheidet, welche Pipeline für welchen Branch läuft.
Konfiguration je Umgebung
Zwei übliche Wege, beide schon in dieser Anleitung gezeigt: ein ImageStream-Tag
je Stufe (:test/:prod, Schritt 8 – Promotion ist
Um-Taggen) und ein Helm-Values-Overlay je Stufe (values-test.yaml/
values-prod.yaml, unterscheidet DB-Host, Replica-Zahl, Ressourcen-Limits,
Feature-Flags – der Chart und die Image-Digest bleiben gleich).
| klassisches Branch-per-Stage | wie die Bibliothek es vereinfacht |
|---|---|
| ein BuildConfig je Umgebung, gebunden an einen Branch | kein BuildConfig im Cluster – Jenkins baut extern (Schritt 12) |
Tag/Overlay je Stufe (:test/:prod) | ein unveränderlicher Tag je Build, der Git-SHA – kein :latest, keine Stufen-Tags |
| Namespace- oder Cluster-pro-Stufe | ein Namespace library auf einer SNO |
| Promotion = nächstes Overlay deployen, ausgelöst durch Git | lokal (Spring dev, H2) → CRC (volles OpenShift lokal) → SNO (die Demo-Prod) – von Hand angestossen |
Kein Widerspruch: das klassische Muster lohnt sich, sobald mehrere Leute an mehreren Umgebungen gleichzeitig arbeiten. Bei einem Ein-Personen-Demoprojekt mit einer SNO ist der direkte Weg schneller und ehrlicher – mehr Umgebungen vorzutäuschen als es gibt, hilft niemandem.
10 Vom Tag zum Deploy: Helm
Schritt 9 hat erklärt, welches Overlay welche Umgebung bekommt – hier folgt der Befehl, der es wirklich tut. Ein winziger Chart reicht, um die Verbindung zu zeigen.
mkdir -p demo-build-chart/templates
cat > demo-build-chart/Chart.yaml <<'YAML'
apiVersion: v2
name: demo-build-chart
version: 0.1.0
YAML
cat > demo-build-chart/values.yaml <<'YAML'
image:
repository: image-registry.openshift-image-registry.svc:5000/library/demo-build
tag: latest
replicaCount: 1
YAML
cat > demo-build-chart/templates/deployment.yaml <<'YAML'
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-build-helm
spec:
replicas: {{ .Values.replicaCount }}
selector: { matchLabels: { app: demo-build-helm } }
template:
metadata: { labels: { app: demo-build-helm } }
spec:
containers:
- name: app
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
ports: [{ containerPort: 8080 }]
YAML
cat > values-test.yaml <<'YAML'
image: { tag: latest }
replicaCount: 1
YAML
cat > values-prod.yaml <<'YAML'
image: { tag: prod }
replicaCount: 2
YAML
# Test-Umgebung: das :latest-Image aus Schritt 4, ein Replica
helm upgrade --install demo-build ./demo-build-chart -n library -f values-test.yaml
helm list -n library
# "Promotion": derselbe Chart, das naechste Overlay, der Tag aus Schritt 8
helm upgrade --install demo-build ./demo-build-chart -n library -f values-prod.yaml
oc get pods -n library -l app=demo-build-helm
Genau das ist die Zeile aus der Tabelle in Schritt 9: derselbe Chart,
nur das Overlay und der Image-Tag wechseln – kein neuer Build, kein neuer Push, nur ein
anderer Zeiger und andere Werte. Das Release-Objekt (ein Secret im Namespace)
trägt den Verlauf, helm rollback demo-build 1 -n library geht
zurück. Das volle Modell – Release, Diff, Rollback, wo Helm aufhört –
steht in helm-am-bibliothek-chart.html,
diese Anleitung zeigt nur die Verbindung zur Build-Kette.
11 Aufräumen: Pruning
Jeder Push schreibt eine neue Zeile in die Tag-Historie – ohne Aufräumen läuft der Storage der Registry irgendwann voll.
# erst eine Vorschau, nichts wird geloescht: oc adm prune images --keep-tag-revisions=3 --keep-younger-than=60m # nach Pruefung wirklich loeschen: oc adm prune images --keep-tag-revisions=3 --keep-younger-than=60m --confirm
Automatisch läuft das über den imagePruner-CronJob, den der
Operator konfiguriert – von Hand ist er für den seltenen Fall, dass der Storage
schon eng wird.
12 Wie die Bibliothek es macht
| Baustein | real |
|---|---|
| BuildConfig | keins im Cluster – Jenkins baut die 9 Images extern mit podman build (Maven im Container gegen die Host-Engine), kein Build-Pod, keine Cluster-CPU dafür verbraucht |
| Push | Jenkins pusht mit podman push unter library/<dienst>:<git-sha> in die interne Registry – der Pfad legt automatisch einen ImageStream je Dienst an |
| Tag-Strategie | ein unveränderlicher Tag je Build (der Git-SHA) – kein :latest, darum kein Image-Trigger nötig, das Helm-Chart referenziert den SHA direkt |
| Rechte | die SA pipeline pusht mit einem Dauer-Token, Rollen system:image-builder + registry-editor (A5) |
| Bekannte Störung | nach sno.ps1 up hängt der Operator oft an einer veralteten Leader-Lease – der Post-up-Hook (sno-wsl.sh remediate) räumt das, sonst bekommt der erste podman login ein connection refused |
oc new-app/new-build nutzt die Bibliothek höchstens zum
Skizzieren – für echten Deploy kommt Helm (B11), nicht der generierte Satz aus
Schritt 2.