Gateway-API als Alternative zum Ingress in allen Inhouse-Charts #114

Closed
opened 2026-10-12 16:52:38 +02:00 by jlab-bot · 3 comments
Member

Alle Inhouse-Charts sollen die Gateway-API als Alternative zum Ingress unterstützen. Das ist keine Template-Übersetzung: ein HTTPRoute hat weder TLS noch Klasse, beides sitzt am Gateway — und damit verschiebt sich, wem was gehört.

Gemessener Stand

Charts mit Ingress-Template 21 (plus template-chart)
Templates mit cert-manager.io/cluster-issuer 21
Charts mit fest verdrahteten nginx-Annotationen 6

Die Konvention ist einheitlich: ingress.enabled, ingress.clusterIssuer (required), ingress.domain (required), ingress.className (Vorgabe nginx), additives ingress.annotations, TLS-Secret tls-<release>-<chart>-ingress, das cert-manager aus der Annotation erzeugt.

Fünf Sonderfälle, die der Sweep kennen muss: matrix-synapse rendert seine Ingresses in einer Schleife über mehrere Apps; keycloak und bulwark haben je zwei; homeassistant ist die dokumentierte Ingress-Ausnahme (flexibler Upstream-Stil); garage hat ingress.enabled: false als Vorgabe; stalwart rendert je Knotengruppe.

Was sich wohin verschiebt

heute im Chart Gateway-API wem gehört es
ingress.domain HTTPRoute.spec.hostnames Chart
Backend-Service, path: / Prefix backendRefs, matches[].path Chart
ingress.className gatewayClassName am Gateway Plattform
cert-manager-Annotation + TLS-Secret Zertifikat am Gateway-Listener Plattform
ingress.annotations kein Gegenstück teils nirgends

Folge 1: ingress.clusterIssuer ist im Gateway-Modus bedeutungslos

Er ist heute required(), und im Gateway-Modus rendert der Chart kein Zertifikat. Ein verlangter Wert, der nichts tut, ist genau die Gattung, die dieses Repository sonst erschlägt. Er wird deshalb bedingt verlangt — nur bei ingress.enabled. Das ist eine Lockerung, also nicht breaking.

Folge 2: die Annotationen haben teils keinen Platz, und das ist gemessen

proxy-body-size:  bulwark, calibre-web-automated, outline, paperless-ngx, zipline
rewrite-target:   bulwark, freesailarr

rewrite-target hat ein Gegenstück: den URLRewrite-Filter im HTTPRoute. proxy-body-size nicht — die Gateway-API kennt keine Body-Size, das ist implementierungsspezifische Politik. Wer outline auf Gateway umstellt, verliert still seine Upload-Grenze und bekommt die des Gateways. Besonders bitter bei genau dem Chart, bei dem #12 offen ist, weil Anwendung und Ingress schon heute um Faktor zehn auseinanderliegen.

Entscheidungen

1. Implementierungs-neutral. Die Charts rendern nur HTTPRoute mit parentRefs — kein Gateway, kein gatewayClassName, kein Zertifikat, und kein implementierungsspezifisches Policy-Objekt. Das ist der Teil, der für nginx-gateway-fabric, Cilium, Envoy Gateway und Istio gleich aussieht. Ein ClientSettingsPolicy oder ClientTrafficPolicy im Chart würde ihn an eine Implementierung binden, gegen die Portabilitäts-Konvention, und an eine CRD, deren Vorhandensein er nicht prüfen kann.

2. Die Upload-Grenze wird dokumentiert, nicht nachgebaut. Die fünf betroffenen Charts drucken im Gateway-Modus in NOTES.txt aus, dass die Grenze aus ihrem Wert nicht durchgesetzt wird und am Gateway oder per Policy der jeweiligen Implementierung zu setzen ist. Der Preis ist benannt und bewusst: wer die Ausgabe überliest, bekommt die Gateway-Vorgabe, und der Fehler erscheint als Proxy-Meldung statt als Anwendungsmeldung. Diese Folge ergibt sich aus Entscheidung 1 und ist keine zweite Wahl.

3. Pilot, dann Konvention, dann Sweep. Nicht 22 Charts in einem PR — das wären 22 Minor-Bumps und 22 Veröffentlichungen auf einmal, und die fünf Sonderfälle gingen in der Masse unter.

Die Form

httpRoute:
  enabled: false     # Gegenstück zu ingress.enabled, Vorgabe aus
  parentRefs: []     # Name/Namespace/sectionName des Gateways — Plattform-Objekt
  hostnames: []      # leer = [ingress.domain], damit es eine Quelle der Wahrheit gibt
  • Kein Auto-Erkennen. Ohne die Gateway-API-CRDs scheitert ein HTTPRoute beim Installieren, und .Capabilities.APIVersions ist zur Template-Zeit unzuverlässig. Also ein Wert, kein Rätselraten.
  • Gegenseitig ausschließend, mit Render-Abbruch, der beide Wertepfade namentlich nennt. Zwei Wege auf denselben Service unter einem Hostnamen sind schon auf DNS-Ebene ein Konflikt; eine Migration läuft über einen zweiten Hostnamen.
  • parentRefs ist im Gateway-Modus verpflichtend. Ohne Elternteil hängt die Route an nichts und ist einfach wirkungslos — stiller Fehler, also Render-Abbruch.
  • Hostnamen aus einer Quelle. hostnames leer bedeutet [ingress.domain]. Zwei Werte, die übereinstimmen müssen, laufen auseinander.
  • NOTES.txt sagt, welcher Modus aktiv ist, wie es keycloak für seine Fälle schon tut.

Prüfung — und der Punkt, an dem eine Attrappe nichts belegt

Die Fixtures bekommen die echten Gateway-API-CRDs, keine Stub-CRD. Mit einer Attrappe ohne Schema nimmt der API-Server auch ein fehlerhaftes HTTPRoute an, und der Install-Test belegt dann nichts außer „etwas wurde angelegt". Der Standard-Channel-Satz von upstream bringt echte Schema-Validierung mit — damit prüft der Lauf, ob es ein gültiges HTTPRoute ist, und fängt ein verdrehtes parentRefs oder backendRefs.

Dazu eine CI-Zusicherung auf Render-Ebene, in der Form, die mit #96 gerade gelandet ist (ci/run-selector-match-test.sh): wird ein HTTPRoute gerendert, muss jeder backendRefs-Eintrag einen Service nennen, den derselbe Render erzeugt, und parentRefs darf nicht leer sein. Überlagerungen unter ci/httproute/<chart>.yaml, damit die Zusicherung nicht vakuum-grün ist. Dieselbe stille Klasse, dieselbe Antwort.

Was unbeweisbar bleibt und so im PR stehen muss: dass Verkehr wirklich fließt. In k3d läuft kein Gateway-Controller, es routet also nichts. Der Install-Test kann belegen, dass das Objekt schema-gültig ist und der Pod Ready wird — nicht, dass die Route funktioniert.

Pilot: cyberchef

Gewählt nach Belegen: ein einziges Ingress-Template, keine nginx-Annotationen, Fixture vorhanden — und eine statische Anwendung ohne Datenbank und ohne Anmeldung. Damit isoliert der erste Durchgang wirklich die Mechanik.

Ausgeschlossen und warum: rss-bridge ist für Änderungen eingefroren (#51); stalwart wurde gerade angefasst und rendert je Knotengruppe; homeassistant und voucher-vault werden von #94 berührt; garage hat den Ingress standardmäßig aus, der Install-Test würde den Pfad also nicht gehen; ytdlp-web-player hängt am oauth2-proxy-Subchart.

Umfang des Piloten: cyberchef (Template, values.yaml, values.schema.json, NOTES.txt), die echten CRDs plus eine Überlagerung in den Fixtures, die CI-Zusicherung samt Job, und die Konvention in README und Chart-Style-Guide. Minor, weil additiv mit unveränderten Vorgaben — zu belegen mit einem leeren helm template-Diff gegen origin/main für die Vorgaben.

Danach

Der Sweep über die übrigen 20 in wenigen PRs statt in einem, die fünf Sonderfälle jeweils eigens begründet. template-chart bekommt die Form mit dem Piloten, damit kein neuer Chart sie erfindet.

Nicht in diesem Umfang

Das Gateway selbst, seine Listener und deren Zertifikate gehören nach cluster-config. Ebenso die Entscheidung, welche Implementierung läuft — die Charts bleiben ihr gegenüber offen, und genau deshalb kann sie später fallen, ohne die Charts erneut anzufassen.

Alle Inhouse-Charts sollen die **Gateway-API** als Alternative zum Ingress unterstützen. Das ist keine Template-Übersetzung: ein `HTTPRoute` hat **weder TLS noch Klasse**, beides sitzt am Gateway — und damit verschiebt sich, wem was gehört. ## Gemessener Stand | | | | --- | --- | | Charts mit Ingress-Template | **21** (plus `template-chart`) | | Templates mit `cert-manager.io/cluster-issuer` | 21 | | Charts mit fest verdrahteten nginx-Annotationen | **6** | Die Konvention ist einheitlich: `ingress.enabled`, `ingress.clusterIssuer` (required), `ingress.domain` (required), `ingress.className` (Vorgabe `nginx`), additives `ingress.annotations`, TLS-Secret `tls-<release>-<chart>-ingress`, das cert-manager aus der Annotation erzeugt. **Fünf Sonderfälle**, die der Sweep kennen muss: `matrix-synapse` rendert seine Ingresses in einer **Schleife über mehrere Apps**; `keycloak` und `bulwark` haben je **zwei**; `homeassistant` ist die dokumentierte Ingress-Ausnahme (flexibler Upstream-Stil); `garage` hat `ingress.enabled: false` als Vorgabe; `stalwart` rendert je Knotengruppe. ## Was sich wohin verschiebt | heute im Chart | Gateway-API | wem gehört es | | --- | --- | --- | | `ingress.domain` | `HTTPRoute.spec.hostnames` | Chart | | Backend-Service, `path: /` Prefix | `backendRefs`, `matches[].path` | Chart | | `ingress.className` | `gatewayClassName` am **Gateway** | **Plattform** | | cert-manager-Annotation + TLS-Secret | Zertifikat am **Gateway-Listener** | **Plattform** | | `ingress.annotations` | **kein Gegenstück** | teils nirgends | ### Folge 1: `ingress.clusterIssuer` ist im Gateway-Modus bedeutungslos Er ist heute `required()`, und im Gateway-Modus rendert der Chart **kein** Zertifikat. Ein verlangter Wert, der nichts tut, ist genau die Gattung, die dieses Repository sonst erschlägt. Er wird deshalb **bedingt** verlangt — nur bei `ingress.enabled`. Das ist eine Lockerung, also nicht breaking. ### Folge 2: die Annotationen haben teils keinen Platz, und das ist gemessen ``` proxy-body-size: bulwark, calibre-web-automated, outline, paperless-ngx, zipline rewrite-target: bulwark, freesailarr ``` `rewrite-target` hat ein Gegenstück: den `URLRewrite`-Filter im `HTTPRoute`. **`proxy-body-size` nicht** — die Gateway-API kennt keine Body-Size, das ist implementierungsspezifische Politik. Wer `outline` auf Gateway umstellt, verliert still seine Upload-Grenze und bekommt die des Gateways. Besonders bitter bei genau dem Chart, bei dem **#12** offen ist, weil Anwendung und Ingress schon heute um Faktor zehn auseinanderliegen. ## Entscheidungen **1. Implementierungs-neutral.** Die Charts rendern **nur** `HTTPRoute` mit `parentRefs` — kein Gateway, kein `gatewayClassName`, kein Zertifikat, und **kein** implementierungsspezifisches Policy-Objekt. Das ist der Teil, der für nginx-gateway-fabric, Cilium, Envoy Gateway und Istio gleich aussieht. Ein `ClientSettingsPolicy` oder `ClientTrafficPolicy` im Chart würde ihn an eine Implementierung binden, gegen die Portabilitäts-Konvention, und an eine CRD, deren Vorhandensein er nicht prüfen kann. **2. Die Upload-Grenze wird dokumentiert, nicht nachgebaut.** Die fünf betroffenen Charts drucken im Gateway-Modus in `NOTES.txt` aus, dass die Grenze aus ihrem Wert **nicht durchgesetzt** wird und am Gateway oder per Policy der jeweiligen Implementierung zu setzen ist. Der Preis ist benannt und bewusst: wer die Ausgabe überliest, bekommt die Gateway-Vorgabe, und der Fehler erscheint als Proxy-Meldung statt als Anwendungsmeldung. Diese Folge ergibt sich aus Entscheidung 1 und ist keine zweite Wahl. **3. Pilot, dann Konvention, dann Sweep.** Nicht 22 Charts in einem PR — das wären 22 Minor-Bumps und 22 Veröffentlichungen auf einmal, und die fünf Sonderfälle gingen in der Masse unter. ## Die Form ```yaml httpRoute: enabled: false # Gegenstück zu ingress.enabled, Vorgabe aus parentRefs: [] # Name/Namespace/sectionName des Gateways — Plattform-Objekt hostnames: [] # leer = [ingress.domain], damit es eine Quelle der Wahrheit gibt ``` - **Kein Auto-Erkennen.** Ohne die Gateway-API-CRDs scheitert ein `HTTPRoute` beim Installieren, und `.Capabilities.APIVersions` ist zur Template-Zeit unzuverlässig. Also ein Wert, kein Rätselraten. - **Gegenseitig ausschließend**, mit Render-Abbruch, der **beide** Wertepfade namentlich nennt. Zwei Wege auf denselben Service unter einem Hostnamen sind schon auf DNS-Ebene ein Konflikt; eine Migration läuft über einen zweiten Hostnamen. - **`parentRefs` ist im Gateway-Modus verpflichtend.** Ohne Elternteil hängt die Route an nichts und ist einfach wirkungslos — stiller Fehler, also Render-Abbruch. - **Hostnamen aus einer Quelle.** `hostnames` leer bedeutet `[ingress.domain]`. Zwei Werte, die übereinstimmen müssen, laufen auseinander. - **`NOTES.txt` sagt, welcher Modus aktiv ist**, wie es `keycloak` für seine Fälle schon tut. ## Prüfung — und der Punkt, an dem eine Attrappe nichts belegt **Die Fixtures bekommen die *echten* Gateway-API-CRDs, keine Stub-CRD.** Mit einer Attrappe ohne Schema nimmt der API-Server auch ein fehlerhaftes `HTTPRoute` an, und der Install-Test belegt dann nichts außer „etwas wurde angelegt". Der Standard-Channel-Satz von upstream bringt echte Schema-Validierung mit — damit prüft der Lauf, ob es ein **gültiges** `HTTPRoute` ist, und fängt ein verdrehtes `parentRefs` oder `backendRefs`. **Dazu eine CI-Zusicherung auf Render-Ebene**, in der Form, die mit #96 gerade gelandet ist (`ci/run-selector-match-test.sh`): wird ein `HTTPRoute` gerendert, muss jeder `backendRefs`-Eintrag einen **Service nennen, den derselbe Render erzeugt**, und `parentRefs` darf nicht leer sein. Überlagerungen unter `ci/httproute/<chart>.yaml`, damit die Zusicherung nicht vakuum-grün ist. Dieselbe stille Klasse, dieselbe Antwort. **Was unbeweisbar bleibt und so im PR stehen muss:** dass Verkehr wirklich fließt. In k3d läuft kein Gateway-Controller, es routet also nichts. Der Install-Test kann belegen, dass das Objekt schema-gültig ist und der Pod `Ready` wird — nicht, dass die Route funktioniert. ## Pilot: `cyberchef` Gewählt nach Belegen: ein einziges Ingress-Template, **keine** nginx-Annotationen, Fixture vorhanden — und eine statische Anwendung ohne Datenbank und ohne Anmeldung. Damit isoliert der erste Durchgang wirklich die Mechanik. Ausgeschlossen und warum: `rss-bridge` ist für Änderungen eingefroren (#51); `stalwart` wurde gerade angefasst und rendert je Knotengruppe; `homeassistant` und `voucher-vault` werden von #94 berührt; `garage` hat den Ingress standardmäßig aus, der Install-Test würde den Pfad also nicht gehen; `ytdlp-web-player` hängt am oauth2-proxy-Subchart. Umfang des Piloten: `cyberchef` (Template, `values.yaml`, `values.schema.json`, `NOTES.txt`), die echten CRDs plus eine Überlagerung in den Fixtures, die CI-Zusicherung samt Job, und die Konvention in README und `Chart-Style-Guide`. **Minor**, weil additiv mit unveränderten Vorgaben — zu belegen mit einem leeren `helm template`-Diff gegen `origin/main` für die Vorgaben. ## Danach Der Sweep über die übrigen 20 in wenigen PRs statt in einem, die fünf Sonderfälle jeweils eigens begründet. `template-chart` bekommt die Form mit dem Piloten, damit kein neuer Chart sie erfindet. ## Nicht in diesem Umfang Das Gateway selbst, seine Listener und deren Zertifikate gehören nach `cluster-config`. Ebenso die Entscheidung, welche Implementierung läuft — die Charts bleiben ihr gegenüber offen, und genau deshalb kann sie später fallen, ohne die Charts erneut anzufassen.
Author
Member

Stand nach dem Merge von Gruppe 3: der Sweep ist durch, bis auf einen Chart

Pilot und alle drei Gruppen sind gemergt. Dieses Issue bleibt offen, und zwar nur noch aus einem Grund.

Runde PR Charts
Pilot #115 cyberchef
Gruppe 1 #116 acht Charts ohne nginx-Annotationen
Gruppe 2 #117 calibre-web-automated, outline, paperless-ngx, zipline, freesailarr
Gruppe 3 #120 keycloak, bulwark, matrix-synapse, stalwart, homeassistant, ytdlp-web-player

Nachgeprüft nach dem letzten Merge: main auf 6d79d8f, sechs publish-helm-chart-Läufe erfolgreich (einer je Chart), Wiki unverändert auf 1e684ca, und dieses Issue nicht auto-geschlossen — alle vier PRs trugen Part of, nie Fixes, was hier genau richtig war.

Die Render-Zusicherung ci/run-httproute-match-test.sh steht bei 56 Zusicherungen über 21 Charts, von 4 über 2 beim Piloten.

Was noch fehlt: rss-bridge

Der Chart ist durch #51 für Änderungen eingefroren. Dieses Issue kann nicht geschlossen werden, solange #51 offen ist — es ist die einzige verbleibende Abhängigkeit, und sie liegt nicht in diesem Umfang.

Was der Sweep an Prämissen dieses Issues widerlegt hat

Der Rumpf oben enthält Zahlen und Sonderfälle, die sich beim Messen nicht gehalten haben. Sie sind in den jeweiligen PRs korrigiert; hier zusammengefasst, damit niemand den Rumpf als Quelle benutzt:

  • bulwark hat einen Ingress, nicht zwei, und kein rewrite-target — und kann keins haben: NEXT_PUBLIC_BASE_PATH ist in das Bundle kompiliert. Die vier Treffer, die meine rewrite-target-Tabelle gezählt hat, sind alle Widerlegungen dieser Idee im Chart-Text, keine Vorkommen. Damit ist freesailarr der einzige Chart dieser Gattung geblieben.
  • matrix-synapse rendert keine Schleife über Apps (das ist freesailarr): ein Ingress mit zwei Host-Regeln, daraus zwei HTTPRoute-Objekte, weil spec.hostnames für das ganze Objekt gilt.
  • stalwart rendert kein Routing-Objekt je Knotengruppe — das tun Services und StatefulSets; die Route ist eine.
  • Die Gateway-API hat ein CORS-Gegenstück. HTTPCORSFilter liegt im Standard-Channel von v1.6.3, Support: Extended. Mein „kein Gegenstück" war falsch. Gerendert wird trotzdem keins, aber aus einem besseren Grund: der Preflight ist die unübersetzbare Hälfte, und Authorization macht jede Webmail-Anfrage preflight-pflichtig — die ausdrückbare Hälfte ist die nutzlose. (responseHeaderModifier ist ebenfalls Extended, nicht Core.)

Dazu zwei Befunde, die der Sweep nebenbei erzeugt hat und die über ihn hinausreichen:

  • #118 — freesailarrs fehlende Schrägstrich-Umleitung, behoben in #119. Ursprung war keine Lücke des Sweeps, sondern eine Lücke des Charts, die ein Betreiber in jk-cluster-config mit einer Annotation hoher Risikostufe geschlossen hatte; der Gateway-Modus lässt ingress.annotations fallen und damit die Kompensation.
  • #122 — die vier keycloak-realm-*-Ingresses aus jk-cluster-config wären im Chart abbildbar, app-root entspricht exakt einem RequestRedirect/ReplaceFullPath. Eigenes Issue, weil es ein Feature in beiden Modi wäre und eine Cross-Repo-Migration.

Unverändert unbeweisbar

In CI läuft kein Gateway-Controller, keine HTTPRoute erreicht je Accepted: True. „Es routet" steht in keinem der vier PRs. Belegt sind schema-gültige Objekte gegen die echten Gateway-API-CRDs (Install-Test, bezahlt vom Piloten) und die Render-Zusicherungen. Die dokumentierten Verluste — proxy-body-size, die Puffergrößen, CORS — stehen im Gateway-Zweig von NOTES.txt, und diesen Text liest keine Pipeline-Stufe: helm template gibt ihn nicht aus, nichts unter ci/ liest ihn. Sein Syntax ist von jedem Render-Test gedeckt, seine Aussagen von nichts.

# Stand nach dem Merge von Gruppe 3: der Sweep ist durch, bis auf einen Chart Pilot und alle drei Gruppen sind gemergt. Dieses Issue bleibt **offen**, und zwar nur noch aus einem Grund. | Runde | PR | Charts | | --- | --- | --- | | Pilot | #115 | `cyberchef` | | Gruppe 1 | #116 | acht Charts ohne nginx-Annotationen | | Gruppe 2 | #117 | `calibre-web-automated`, `outline`, `paperless-ngx`, `zipline`, `freesailarr` | | Gruppe 3 | #120 | `keycloak`, `bulwark`, `matrix-synapse`, `stalwart`, `homeassistant`, `ytdlp-web-player` | Nachgeprüft nach dem letzten Merge: `main` auf `6d79d8f`, **sechs** `publish-helm-chart`-Läufe erfolgreich (einer je Chart), Wiki unverändert auf `1e684ca`, und dieses Issue **nicht** auto-geschlossen — alle vier PRs trugen `Part of`, nie `Fixes`, was hier genau richtig war. Die Render-Zusicherung `ci/run-httproute-match-test.sh` steht bei **56 Zusicherungen über 21 Charts**, von 4 über 2 beim Piloten. ## Was noch fehlt: `rss-bridge` Der Chart ist durch **#51** für Änderungen eingefroren. **Dieses Issue kann nicht geschlossen werden, solange #51 offen ist** — es ist die einzige verbleibende Abhängigkeit, und sie liegt nicht in diesem Umfang. ## Was der Sweep an Prämissen dieses Issues widerlegt hat Der Rumpf oben enthält Zahlen und Sonderfälle, die sich beim Messen nicht gehalten haben. Sie sind in den jeweiligen PRs korrigiert; hier zusammengefasst, damit niemand den Rumpf als Quelle benutzt: - **`bulwark` hat einen Ingress, nicht zwei, und kein `rewrite-target`** — und kann keins haben: `NEXT_PUBLIC_BASE_PATH` ist in das Bundle kompiliert. Die vier Treffer, die meine `rewrite-target`-Tabelle gezählt hat, sind alle **Widerlegungen** dieser Idee im Chart-Text, keine Vorkommen. Damit ist `freesailarr` der einzige Chart dieser Gattung geblieben. - **`matrix-synapse` rendert keine Schleife über Apps** (das ist `freesailarr`): ein Ingress mit zwei Host-Regeln, daraus zwei `HTTPRoute`-Objekte, weil `spec.hostnames` für das ganze Objekt gilt. - **`stalwart` rendert kein Routing-Objekt je Knotengruppe** — das tun Services und StatefulSets; die Route ist eine. - **Die Gateway-API hat ein CORS-Gegenstück.** `HTTPCORSFilter` liegt im Standard-Channel von v1.6.3, `Support: Extended`. Mein „kein Gegenstück" war falsch. Gerendert wird trotzdem keins, aber aus einem besseren Grund: der **Preflight** ist die unübersetzbare Hälfte, und `Authorization` macht jede Webmail-Anfrage preflight-pflichtig — die ausdrückbare Hälfte ist die nutzlose. (`responseHeaderModifier` ist ebenfalls Extended, nicht Core.) Dazu zwei Befunde, die der Sweep nebenbei erzeugt hat und die über ihn hinausreichen: - **#118** — `freesailarr`s fehlende Schrägstrich-Umleitung, behoben in #119. Ursprung war keine Lücke des Sweeps, sondern eine Lücke des Charts, die ein Betreiber in `jk-cluster-config` mit einer Annotation hoher Risikostufe geschlossen hatte; der Gateway-Modus lässt `ingress.annotations` fallen und damit die Kompensation. - **#122** — die vier `keycloak-realm-*`-Ingresses aus `jk-cluster-config` wären im Chart abbildbar, `app-root` entspricht exakt einem `RequestRedirect`/`ReplaceFullPath`. Eigenes Issue, weil es ein Feature in **beiden** Modi wäre und eine Cross-Repo-Migration. ## Unverändert unbeweisbar In CI läuft **kein Gateway-Controller**, keine `HTTPRoute` erreicht je `Accepted: True`. „Es routet" steht in keinem der vier PRs. Belegt sind schema-gültige Objekte gegen die echten Gateway-API-CRDs (Install-Test, bezahlt vom Piloten) und die Render-Zusicherungen. Die dokumentierten Verluste — `proxy-body-size`, die Puffergrößen, CORS — stehen im Gateway-Zweig von `NOTES.txt`, und **diesen Text liest keine Pipeline-Stufe**: `helm template` gibt ihn nicht aus, nichts unter `ci/` liest ihn. Sein Syntax ist von jedem Render-Test gedeckt, seine Aussagen von nichts.
Author
Member

Der Gateway-Modus läuft in Produktion — erstmals belegt, nicht nur gerendert

Jeder der vier PRs dieses Sweeps sagt ausdrücklich, dass „es routet" in CI nicht zeigbar ist: dort läuft kein Gateway-Controller, keine HTTPRoute erreicht je Accepted: True. Belegt waren schema-gültige Objekte gegen die echten CRDs und die Render-Zusicherungen.

Am 13.10.2026 ist freesailarr.jk-dev.de auf den Gateway-Modus umgeschwenkt. Gemessen am laufenden System:

Es gibt keine freesailarr-Ingress-Objekte mehr. Der Host läuft über das Gateway.

Eine App unter Unterpfad antwortet korrekt mit ihrem Basispfad:

GET https://freesailarr.jk-dev.de/radarr
→ 302, server: Kestrel
  location: https://freesailarr.jk-dev.de/radarr/login?returnUrl=%2Fradarr

Das ist radarr selbst, und returnUrl=%2Fradarr zeigt, dass es seinen Basispfad kennt. Damit arbeitet der Helfer freesailarr.published aus Gruppe 2 (PR #117) in Produktion — ohne ihn wäre RADARR__SERVER__URLBASE im Gateway-Modus leer, weil ingress.enabled dort konstruktionsbedingt false ist, und die Oberfläche wäre hinter einem Ready-Pod kaputt. Genau der Befund, der damals gemessen statt behauptet wurde.

Die Umleitung aus #119 wirkt, und zwar aus dem Chart:

GET https://freesailarr.jk-dev.de/qbittorrent
→ 301, location: https://freesailarr.jk-dev.de/qbittorrent/

Das Snippet des Betreibers, das diese Umleitung im Ingress-Modus leistete, hat keinen Träger mehr — ingress.annotations fallen im Gateway-Modus weg. Die Signatur bestätigt den Wechsel: vorher nginx mit content-type: text/html, 162 Bytes und HSTS, jetzt 17 Bytes, kein Content-Type, kein HSTS. Es ist die Exact/RequestRedirect-Regel des Charts. (Erschlossen aus dem Wegfall des Trägers und der Signatur — httproutes und gatewayclasses sind für die lesende Identität RBAC-gesperrt, die Implementierung ist von hier aus nicht benennbar.)

Die offene Frage aus #118 ist beantwortet

GET https://freesailarr.jk-dev.de/qbittorrent?foo=bar
→ location: https://freesailarr.jk-dev.de/qbittorrent/?foo=bar

Der Query-String bleibt erhalten. Die Spezifikation schweigt dazu — HTTPRequestRedirectFilter hat in v1.6.3 die Felder Scheme, Hostname, Path, Port, StatusCode und kein Query-Feld —, die Dokumentation des Charts bleibt also richtig, dass es nicht zusagbar ist. Für diese Implementierung ist es jetzt gemessen, und die Asymmetrie zum $is_args$args des Snippets ist in der Praxis keine.

Was daraus folgt

Das Snippet in jk-cluster-config ist jetzt wirkungslos und kann weg. Vorher wäre das Entfernen falsch gewesen — es war im Ingress-Modus das Einzige, was die Umleitung leistete. Es verliert seine Wirkung nicht durch den Chart, sondern dadurch, dass der Modus ingress.annotations fallen lässt.

#122 hat damit einen funktionierenden Präzedenzfall. Dort steht die Host-Migration als „Migration, kein Edit" mit einem Fenster, in dem es beide Objekte oder keines gibt. Dieses Fenster ist hier einmal durchlaufen worden, ohne Ausfall.

Und rss-bridge

Der letzte offene Chart dieses Issues. Der Maintainer hat entschieden, ihn trotz #51 umzustellen. Günstig dafür: seine laufende Ingress trägt keine einzige nginx-Annotation, der Schirm aus Gruppe 3 kommt hier also leer zurück. Ungünstig: der Install-Test dieses Charts scheitert weiter auf dem Runner — auf #51 ist das mit PR #62 belegt, die mit rotem Install-Test gemergt wurde. Der rote Test ist dort ein bekannter Umgebungsfehler und kein Befund über die Umstellung; die Einzelheiten stehen auf #51.

# Der Gateway-Modus läuft in Produktion — erstmals belegt, nicht nur gerendert Jeder der vier PRs dieses Sweeps sagt ausdrücklich, dass „es routet" in CI **nicht** zeigbar ist: dort läuft kein Gateway-Controller, keine `HTTPRoute` erreicht je `Accepted: True`. Belegt waren schema-gültige Objekte gegen die echten CRDs und die Render-Zusicherungen. Am 13.10.2026 ist `freesailarr.jk-dev.de` auf den Gateway-Modus umgeschwenkt. Gemessen am laufenden System: **Es gibt keine `freesailarr`-Ingress-Objekte mehr.** Der Host läuft über das Gateway. **Eine App unter Unterpfad antwortet korrekt mit ihrem Basispfad:** ``` GET https://freesailarr.jk-dev.de/radarr → 302, server: Kestrel location: https://freesailarr.jk-dev.de/radarr/login?returnUrl=%2Fradarr ``` Das ist radarr selbst, und `returnUrl=%2Fradarr` zeigt, dass es seinen Basispfad kennt. Damit arbeitet der Helfer `freesailarr.published` aus Gruppe 2 (PR #117) in Produktion — ohne ihn wäre `RADARR__SERVER__URLBASE` im Gateway-Modus leer, weil `ingress.enabled` dort konstruktionsbedingt `false` ist, und die Oberfläche wäre hinter einem `Ready`-Pod kaputt. Genau der Befund, der damals gemessen statt behauptet wurde. **Die Umleitung aus #119 wirkt, und zwar aus dem Chart:** ``` GET https://freesailarr.jk-dev.de/qbittorrent → 301, location: https://freesailarr.jk-dev.de/qbittorrent/ ``` Das Snippet des Betreibers, das diese Umleitung im Ingress-Modus leistete, hat keinen Träger mehr — `ingress.annotations` fallen im Gateway-Modus weg. Die Signatur bestätigt den Wechsel: vorher nginx mit `content-type: text/html`, 162 Bytes und HSTS, jetzt 17 Bytes, kein Content-Type, kein HSTS. Es ist die `Exact`/`RequestRedirect`-Regel des Charts. (Erschlossen aus dem Wegfall des Trägers und der Signatur — `httproutes` und `gatewayclasses` sind für die lesende Identität RBAC-gesperrt, die Implementierung ist von hier aus nicht benennbar.) ## Die offene Frage aus #118 ist beantwortet ``` GET https://freesailarr.jk-dev.de/qbittorrent?foo=bar → location: https://freesailarr.jk-dev.de/qbittorrent/?foo=bar ``` **Der Query-String bleibt erhalten.** Die Spezifikation schweigt dazu — `HTTPRequestRedirectFilter` hat in v1.6.3 die Felder `Scheme`, `Hostname`, `Path`, `Port`, `StatusCode` und kein Query-Feld —, die Dokumentation des Charts bleibt also richtig, dass es nicht zusagbar ist. Für diese Implementierung ist es jetzt gemessen, und die Asymmetrie zum `$is_args$args` des Snippets ist in der Praxis keine. ## Was daraus folgt **Das Snippet in `jk-cluster-config` ist jetzt wirkungslos und kann weg.** Vorher wäre das Entfernen falsch gewesen — es war im Ingress-Modus das Einzige, was die Umleitung leistete. Es verliert seine Wirkung nicht durch den Chart, sondern dadurch, dass der Modus `ingress.annotations` fallen lässt. **#122 hat damit einen funktionierenden Präzedenzfall.** Dort steht die Host-Migration als „Migration, kein Edit" mit einem Fenster, in dem es beide Objekte oder keines gibt. Dieses Fenster ist hier einmal durchlaufen worden, ohne Ausfall. ## Und `rss-bridge` Der letzte offene Chart dieses Issues. Der Maintainer hat entschieden, ihn **trotz #51** umzustellen. Günstig dafür: seine laufende Ingress trägt **keine einzige nginx-Annotation**, der Schirm aus Gruppe 3 kommt hier also leer zurück. Ungünstig: der Install-Test dieses Charts scheitert weiter auf dem Runner — auf #51 ist das mit PR #62 belegt, die mit rotem Install-Test gemergt wurde. Der rote Test ist dort ein bekannter Umgebungsfehler und kein Befund über die Umstellung; die Einzelheiten stehen auf #51.
Author
Member

Genehmigter Plan: rss-bridge auf die Gateway-API — der letzte Chart dieses Issues

rss-bridge ist nachgewiesen der letzte: 22 Charts tragen ein Ingress-Template, 21 ein HTTPRoute-Template, und die Differenz ist genau dieser. Der Maintainer hat entschieden, ihn trotz #51 umzustellen.

Gemessene Grundlage

main version: 2.0.0+up2026.09.30, appVersion: "2026-09-30"
Cluster dasselbe Image, Ready=True, 0 Restarts
neuester Datums-Tag der Registry 2026-09-30 — alles Neuere sind sha-* und latest
nginx-Annotationen auf der laufenden Ingress keine
Chart-Form ingress.hosts ist eine required Liste mit Helfer rss-bridge.tlsGroups; live drei Hosts, drei TLS-Secrets

Umfang

1. Eine HTTPRoute mit allen drei Hostnamen. Anders als bei den Keycloak-Realms (#122) unterscheidet sich hier nichts je Host: alle drei liefern denselben Service auf /. spec.hostnames ist eine Liste, also genügt ein Objekt.

Dabei wird rss-bridge.tlsGroups im Gateway-Modus gegenstandslos — der Helfer existiert nur, um Hosts nach TLS-Secret zu gruppieren, und TLS sitzt dort am Gateway-Listener. Das ist eine Vereinfachung und gehört als solche benannt, nicht bloß übersetzt.

2. httpRoute.hostnames als eigener Wert, ingress.hosts wird bedingt verlangt. Heute steht dort required "At least one ingress host must be provided (ingress.hosts)" — im Gateway-Modus ein verlangter Wert ohne Wirkung, also „Folge 1" dieses Issues.

Eigener Wert statt Wiederverwendung von ingress.hosts: diese Liste trägt TLS-Secret-Namen je Host, die im Gateway-Modus bedeutungslos sind. Sie wiederzuverwenden würde fremde Struktur in den neuen Modus schleppen. (Zum Vergleich: bei freesailarr wurde hostnames im Schema aktiv abgelehnt, weil eine chart-globale Liste nicht sagen könnte, zu welcher der zehn Apps sie gehört. Hier gehört sie zum einen Dienst, ist also sinnvoll.)

3. Der Annotations-Schirm ist sauber. Die laufende Ingress trägt keine einzige nginx-Annotation. rss-bridge wäre damit der erste Chart des Sweeps, dessen Gateway-Zweig in NOTES.txt keinen Verlust zu erklären hat — zu bestätigen, nicht zu unterstellen.

4. #40 fährt mit. rss-bridge/templates/_helpers.tpl ist die letzte Datei im Repository mit dem veralteten Satz („charts in this repo deliberately have no…"), geprüft per git grep über origin/main. #51 sieht das in seinem Umfang ausdrücklich so vor.

5. Keine appVersion-Änderung — gemessen, es gibt nichts Neueres.

6. Version Minor 2.1.0+up2026.09.30 — additiv mit unveränderten Vorgaben, und die Lockerung eines required ist keine Verschärfung. Zu belegen mit einem leeren helm template-Diff gegen origin/main für die Vorgaben.

7. Schlüsselwörter: Fixes #114 und Fixes #40. Beide werden von dieser PR vollständig erledigt.

Das kehrt um, was auf diesem Issue mehrfach stand — „kann nicht geschlossen werden, solange #51 offen ist". Diese Abhängigkeit bestand, weil rss-bridge durch #51 für Änderungen eingefroren war. Der Maintainer hat den Freeze aufgehoben, damit entfällt sie. #51 bleibt davon unberührt offen: der Runner-Fehler ist dadurch nicht behoben, nur nicht länger ein Hindernis für diese Umstellung.

Der Install-Test bleibt rot, und das ist die Entscheidung

Der Install-Test dieses Charts scheitert auf dem Gitea-Runner (#51, dort mit PR #62 auf dem neuen Image belegt). Entscheidung des Maintainers: rot mergen, kein Ausschluss in ci/excluded-charts.txt.

Begründung, die den Ausschlag gab: an dem Tag, an dem der Runner repariert wird, wird dieser Test von selbst grün und man erfährt es. Ein Ausschluss würde dieses Signal stilllegen.

Zwei Folgen, die im PR-Rumpf stehen müssen:

  • Die Gateway-Umstellung dieses Charts ist durch keine Installation belegt, nur auf Render-Ebene. Für alle anderen 21 Charts gab es wenigstens einen erfolgreichen Install-Test im Ingress-Modus; hier nicht.
  • Zu unterscheiden ist die erwartete Röte von einer neuen. Rot sein dürfen ausschließlich Install-test / Install-test rss-bridge und der Sammelkontext Validate Helm Charts / Install-test. Jeder andere rote Kontext ist ein echter Fehler und kein bekannter Umgebungsdefekt.

Unverändert unbeweisbar

In CI läuft kein Gateway-Controller, keine HTTPRoute erreicht Accepted: True — „es routet" steht auch in diesem PR nicht. Für freesailarr ist der Gateway-Modus inzwischen in Produktion gemessen (Kommentar oben); das ist ein Beleg für die Form, nicht für diesen Chart.

# Genehmigter Plan: `rss-bridge` auf die Gateway-API — der letzte Chart dieses Issues `rss-bridge` ist nachgewiesen der letzte: 22 Charts tragen ein Ingress-Template, 21 ein HTTPRoute-Template, und die Differenz ist genau dieser. Der Maintainer hat entschieden, ihn **trotz #51** umzustellen. ## Gemessene Grundlage | | | | --- | --- | | `main` | `version: 2.0.0+up2026.09.30`, `appVersion: "2026-09-30"` | | Cluster | dasselbe Image, `Ready=True`, 0 Restarts | | neuester Datums-Tag der Registry | `2026-09-30` — alles Neuere sind `sha-*` und `latest` | | nginx-Annotationen auf der laufenden Ingress | **keine** | | Chart-Form | `ingress.hosts` ist eine **required Liste** mit Helfer `rss-bridge.tlsGroups`; live drei Hosts, drei TLS-Secrets | ## Umfang **1. Eine HTTPRoute mit allen drei Hostnamen.** Anders als bei den Keycloak-Realms (#122) unterscheidet sich hier nichts je Host: alle drei liefern denselben Service auf `/`. `spec.hostnames` ist eine Liste, also genügt ein Objekt. Dabei wird `rss-bridge.tlsGroups` im Gateway-Modus **gegenstandslos** — der Helfer existiert nur, um Hosts nach TLS-Secret zu gruppieren, und TLS sitzt dort am Gateway-Listener. Das ist eine Vereinfachung und gehört als solche benannt, nicht bloß übersetzt. **2. `httpRoute.hostnames` als eigener Wert**, `ingress.hosts` wird **bedingt** verlangt. Heute steht dort `required "At least one ingress host must be provided (ingress.hosts)"` — im Gateway-Modus ein verlangter Wert ohne Wirkung, also „Folge 1" dieses Issues. Eigener Wert statt Wiederverwendung von `ingress.hosts`: diese Liste trägt **TLS-Secret-Namen je Host**, die im Gateway-Modus bedeutungslos sind. Sie wiederzuverwenden würde fremde Struktur in den neuen Modus schleppen. (Zum Vergleich: bei `freesailarr` wurde `hostnames` im Schema aktiv **abgelehnt**, weil eine chart-globale Liste nicht sagen könnte, zu welcher der zehn Apps sie gehört. Hier gehört sie zum einen Dienst, ist also sinnvoll.) **3. Der Annotations-Schirm ist sauber.** Die laufende Ingress trägt keine einzige nginx-Annotation. `rss-bridge` wäre damit der erste Chart des Sweeps, dessen Gateway-Zweig in `NOTES.txt` **keinen Verlust** zu erklären hat — zu bestätigen, nicht zu unterstellen. **4. #40 fährt mit.** `rss-bridge/templates/_helpers.tpl` ist die **letzte** Datei im Repository mit dem veralteten Satz („charts in this repo deliberately have no…"), geprüft per `git grep` über `origin/main`. #51 sieht das in seinem Umfang ausdrücklich so vor. **5. Keine appVersion-Änderung** — gemessen, es gibt nichts Neueres. **6. Version Minor `2.1.0+up2026.09.30`** — additiv mit unveränderten Vorgaben, und die Lockerung eines `required` ist keine Verschärfung. Zu belegen mit einem leeren `helm template`-Diff gegen `origin/main` für die Vorgaben. **7. Schlüsselwörter: `Fixes #114` **und** `Fixes #40`.** Beide werden von dieser PR vollständig erledigt. Das kehrt um, was auf diesem Issue mehrfach stand — „kann nicht geschlossen werden, solange #51 offen ist". Diese Abhängigkeit bestand, weil `rss-bridge` durch #51 für Änderungen eingefroren war. Der Maintainer hat den Freeze aufgehoben, damit entfällt sie. **#51 bleibt davon unberührt offen**: der Runner-Fehler ist dadurch nicht behoben, nur nicht länger ein Hindernis für diese Umstellung. ## Der Install-Test bleibt rot, und das ist die Entscheidung Der Install-Test dieses Charts scheitert auf dem Gitea-Runner (#51, dort mit PR #62 auf dem **neuen** Image belegt). Entscheidung des Maintainers: **rot mergen, kein Ausschluss in `ci/excluded-charts.txt`.** Begründung, die den Ausschlag gab: an dem Tag, an dem der Runner repariert wird, wird dieser Test von selbst grün und man erfährt es. Ein Ausschluss würde dieses Signal stilllegen. Zwei Folgen, die im PR-Rumpf stehen müssen: - **Die Gateway-Umstellung dieses Charts ist durch keine Installation belegt**, nur auf Render-Ebene. Für alle anderen 21 Charts gab es wenigstens einen erfolgreichen Install-Test im Ingress-Modus; hier nicht. - **Zu unterscheiden ist die erwartete Röte von einer neuen.** Rot sein dürfen ausschließlich `Install-test / Install-test rss-bridge` und der Sammelkontext `Validate Helm Charts / Install-test`. Jeder andere rote Kontext ist ein echter Fehler und kein bekannter Umgebungsdefekt. ## Unverändert unbeweisbar In CI läuft kein Gateway-Controller, keine `HTTPRoute` erreicht `Accepted: True` — „es routet" steht auch in diesem PR nicht. Für `freesailarr` ist der Gateway-Modus inzwischen in Produktion gemessen (Kommentar oben); das ist ein Beleg für die Form, nicht für diesen Chart.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: jlab-cluster/helm-charts#114