Kai Ole Hartwig
8 Min. Lesezeit
Niedrig

Das TYPO3-Backend bekommt einen eigenen Pod

Für alle, die TYPO3 auf Kubernetes betreiben und bei denen Redaktion und Besucher denselben Pod teilen. Die Idee ist älter als jeder Sparplan: Die Last der Redaktion sollte die Website nicht ausbremsen, und umgekehrt. Jetzt hat das Backend ein eigenes Deployment, und beide Seiten antworten schneller. Diese Feldnotiz zeigt den Umbau, die Reihenfolge der Umstellung und die ersten Messwerte. Möglich wurde er durch den schnellen Pod-Start aus der Feldnotiz zum Pod-Start in zwölf Sekunden.

01 — Ein Pod für alles

Bisher bediente ein einziges Deployment alle Hosts eines Mandanten. Dazu gehörte auch der Backend-Host, auf dem die Redaktion arbeitet. Er hat einen eigenen Namen und eine IP-Allowlist im Edge-Proxy, landete aber im selben Pod wie die Website. FrankenPHP bedient die Website im Worker-Modus und das Backend klassisch. Beide teilten sich trotzdem denselben CPU-Request und dieselben PHP-Threads.

Die beiden Seiten belasten einen Pod sehr unterschiedlich. Die Website bekommt viele kurze Anfragen, und ein großer Teil davon kommt ohnehin aus dem Edge-Cache. Das Backend bekommt weniger Anfragen, aber schwere: Listenansichten, Module, AJAX und die MCP-Aufrufe eines KI-Assistenten. Klickt sich die Redaktion durch das Backend, während Besucher und Crawler die Website abrufen, warten beide aufeinander.

Genau das soll die Trennung lösen. Die Idee dahinter ist schlicht: Wer unterschiedlich lädt, bekommt einen eigenen Pod.

02 — Ein zweites Deployment aus demselben Template

Das Backend braucht keinen eigenen Code und kein eigenes Image. Das Chart rendert die Pod-Vorlage der App jetzt zweimal: einmal als app und, wenn ein Schalter gesetzt ist, ein zweites Mal als app-backend. Die Kopien unterscheiden sich in genau drei Dingen. Name, Komponenten-Label und Zahl der Replicas.

 

app:
  backend:
    split: true
    scaleToZero:
      enabled: false   # erst nach einer Woche im Betrieb

 

Beide Deployments laufen unter demselben ServiceAccount und haben damit dieselbe Pod-Identität. Das Zertifikat trägt weiter den Namen app, und der Edge-Proxy prüft gegen diesen Namen oder den Host der Anfrage, nie gegen die Adresse, die er wählt. Keine Freigabe musste den Besitzer wechseln.

Mehr Arbeit machten die Netzwerkregeln. Im Namespace dürfen Komponenten nur so miteinander reden, wie es eine Regel erlaubt. app-backend braucht exakt die Wege der App: zur Datenbank, zum Cache, vom Edge-Proxy. Das Chart leitet sie aus der Liste der App ab, statt sie ein zweites Mal aufzuschreiben. Eine Prüfung in der CI vergleicht beide Seiten Regel für Regel und ist nachweislich rot, sobald eine einzige Regel fehlt.

Bleibt die Quota des Namespace. Ein zweiter Pod in App-Größe und sein Surge-Pod im Rollout passten nicht mehr in 8 GiB Speicher-Limits. Gerechnet auf den ungünstigsten Fall sind es jetzt 10 GiB, mit einer begründeten Abweichung im Mandanten.

03 — Der Edge-Proxy schaltet um

Welcher Pod den Backend-Host bedient, entscheidet der Edge-Proxy. Sein Caddyfile bekam dafür ein eigenes Upstream für diesen Host. Jede Variable darin fällt auf den Wert zurück, den der Rest schon benutzt. Ein Image mit dieser Änderung verhält sich deshalb genau wie eins ohne, bis das Chart die Variablen setzt.

 

(backend-upstream) {
    reverse_proxy {$BACKEND_UPSTREAM_HOST:app}:443 {
        dynamic a {
            name {$BACKEND_UPSTREAM_DYNAMIC_HOST:app-headless}
            port 8443
            refresh 10s
        }
        lb_try_duration {$BACKEND_LB_TRY_DURATION:5s}
        lb_try_interval 250ms
    }
}

 

Das erlaubte eine Reihenfolge ohne Risiko. Zuerst kam das Chart: app-backend lief, bekam aber noch keinen Verkehr, weil das alte Proxy-Image die neuen Variablen ignorierte. In dieser Zeit ließ sich der Pod direkt prüfen. Login-Seite, Stylesheets und Skripte antworteten wie in der App. Erst dann kam das neue Proxy-Image, und mit seinem Neustart ging der Backend-Host an app-backend. Die Plattform folgt dabei derselben Regel wie bei den Pod-Zertifikaten: erst freigeben, dann umschalten.

lb_try_duration ist heute noch kurz. Steht das Backend später auf null Pods, hält der Proxy mit genau diesem Wert eine Anfrage fest, bis ein Pod bereit ist, statt mit einem Fehler zu antworten.

04 — Was die Trennung bringt

Der erste Eindruck nach der Umstellung war deutlich: Das Backend fühlte sich schneller an als je zuvor, die Website ebenfalls. Der Edge-Proxy misst die Antwortzeit je Host, und die erste Stunde bestätigt den Eindruck.

Mittlere Antwortzeit je AnfrageBackend-HostWebsite
Zwei Tage vorher257 ms277 ms
Am Vortag64 ms115 ms
Die Stunde vor der Umstellung160 ms104 ms
Die Stunde danach25 ms79 ms

Die Zahlen brauchen eine Einordnung. Es sind Mittelwerte über alle Anfragen einer Stunde, und die Mischung der Anfragen verändert sie stark. Wer sich durch das Backend klickt, erzeugt viele kleine Anfragen nach Stylesheets und AJAX, und die ziehen den Mittelwert nach unten. Die Größenordnung beim Backend ist trotzdem deutlich, bei der Website ist es etwa ein Viertel.

05 — Warum die Trennung schneller macht

Welcher Anteil auf welchen Grund entfällt, ist nicht einzeln gemessen. Plausibel sind drei Ursachen, und die erste wiegt vermutlich am meisten.

Beide Pods sind dabei kaum ausgelastet, im Ruhezustand je etwa 0,015 CPU-Kerne. Der Unterschied zeigt sich vor allem dann, wenn beide Seiten gleichzeitig arbeiten. Eine Woche Messung im Tagesvergleich wird zeigen, wie viel davon bleibt.

06 — Unabhängig skalieren, in beide Richtungen

Zwei Deployments lassen sich getrennt skalieren. Der Horizontal Pod Autoscaler der Website sieht jetzt nur noch die Last der Besucher. Eine lebhafte Redaktionssitzung löst keinen zusätzlichen Website-Pod mehr aus, und ein Ansturm auf die Website nimmt der Redaktion keine Rechenzeit weg.

Das Backend kann einen eigenen HPA bekommen, und der darf in beide Richtungen arbeiten. Nach oben, wenn viele Redakteurinnen gleichzeitig arbeiten oder ein KI-Assistent über MCP eine Serie schwerer Anfragen schickt. Heute begrenzt das Chart das Backend noch auf einen Pod. Mehr ist ein Wert, kein Umbau.

Und nach unten bis auf null. Nachts und am Wochenende arbeitet niemand im Backend, und ein Pod, der dann trotzdem läuft, hält Speicher und Angriffsfläche vor, die niemand braucht. Seit Kubernetes 1.37 kann ein Horizontal Pod Autoscaler auf null Replicas gehen. Er braucht dann eine Metrik, die auch ohne laufenden Pod existiert. Die liefert der Edge-Proxy, der immer läuft: Anfragen pro Host, über einen Prometheus Adapter als External Metric.

Zwei Messungen stecken den Rahmen ab. Der HPA ging in einem Test nach 17 Sekunden Last von null auf einen Pod, und ein Pod ist nach zwölf Sekunden bereit. Eine Redakteurin, die sich morgens als Erste anmeldet, wartet also etwa eine halbe Minute. Der Proxy hält ihre Anfrage so lange fest, statt mit einem Fehler zu antworten.

SchrittDauer
Anfrage kommt an, Metrik erreicht den HPAetwa 17 s
Pod startet und wird bereitetwa 12 s
Haltezeit im Proxybis 90 s

Die Einsparung ist eine angenehme Zugabe, nicht der Grund für die Trennung. Eingeschaltet wird sie erst, wenn die Redaktion eine Woche ohne Probleme mit dem getrennten Backend gearbeitet hat.

Häufige Fragen

Kostet ein zweites Deployment nicht mehr Ressourcen?+

Tagsüber einen Pod mehr, mit 400 MiB Speicher- und 300m CPU-Request. Die Quota des Namespace ist dafür ausdrücklich angehoben. Dafür skaliert jede Seite nur noch nach ihrer eigenen Last, und nachts kann das Backend auf null gehen. Dann bindet der Mandant weniger als vorher.

Was passiert mit Sessions und der Vorschau?+

Die Hosts bleiben dieselben, und damit auch die Cookies. Backend-Sessions liegen in Valkey, nicht im Pod, und beide Deployments lesen dieselben. Die Vorschau läuft weiter über den Host der Website.

Braucht das Backend eigenen Code oder ein eigenes Image?+

Nein. Beide Deployments hängen dasselbe signierte Image ein, festgelegt auf denselben Digest. Die Trennung passiert nur im Edge-Proxy, der den Backend-Host an einen anderen Pod schickt. FrankenPHP unterscheidet Website und Backend schon heute am Host.

Fazit

Redaktion und Besucher haben verschiedene Lastprofile. Solange sie einen Pod teilen, bremsen sie sich gegenseitig aus, und kein Autoscaler kann das auseinanderhalten. Getrennt antworten beide schneller, und jede Seite skaliert nach ihrer eigenen Last: die Website mit den Besuchern, das Backend mit der Redaktion, nachts bis auf null.

Der Umbau selbst war klein: dieselbe Pod-Vorlage zweimal, abgeleitete Netzwerkregeln, ein zweites Upstream im Edge-Proxy. Die Arbeit lag in der Reihenfolge. Der neue Pod lief und war geprüft, bevor auch nur eine Anfrage ihn erreichte.

Teilen sich Redaktion und Besucher bei dir einen Pod?

Ich sehe mir an, wie Backend und Website deiner TYPO3-Instanz die Ressourcen teilen, und trenne sie so, dass beide schneller antworten und das Backend außerhalb der Arbeitszeit keine Ressourcen mehr bindet.

Termin buchen →

Über den Autor

Foto von Kai Ole Hartwig.

Kai Ole Hartwig

Freiberuflicher DevSecOps-Berater · OnlyOle Consulting

Programmiert seit 2002 – autodidaktisch gelernt, 2012 mit KO-Web selbständig gemacht. Über 100 Projekte, Fokus auf Security, Performance, Automatisierung und Qualität. Heute freiberuflich: DevSecOps-Beratung, Schulungen und Softwareentwicklung.