keyvalue-store
Redis/Valkey-basiertes Caching, Session-Storage und Locking für TYPO3 mit Sentinel-Support, TLS/mTLS und PHPRedis 6.3+.
TYPO3-Datei-Caches sicher über mehrere Kubernetes-Pods betreiben — ohne RWX-Volume. cluster-file-backend hält Cache-Payloads pod-lokal und Cache-Gültigkeit cluster-weit. Es ersetzt TYPO3s FileBackend und SimpleFileBackend für Cache-Workloads, unterstützt tag-basierte Invalidierung und entkoppelt Multi-Pod-Deployments vom Shared-Filesystem.
moselwal/cluster-file-backend:^2.3cluster_file_backendFileBackend oder SimpleFileBackend ersetzen möchtestFileBackend reicht dannEinmaliges Setup: Metadaten-Cache registrieren, Cache-Konfigurationen umschreiben, emptyDir mounten. Keine TYPO3-Core-Änderungen, kein Code-Eingriff in die Applikation.
Produktion: moselwal/keyvalue-store mit KeyValueBackend (Valkey/Redis, sub-ms Latenz, taggable). Einstieg ohne extra Dependency: TYPO3-Cores Typo3DatabaseBackend.
Seit v2.2 implementiert ClusterFileBackend auch PhpCapableBackendInterface — damit bedient ein Backend sowohl VariableFrontend-Caches (pages, extbase, …) als auch PhpFrontend-Caches (typoscript, fluid_template). Der Payload-Store hängt bei PhpFrontend-Caches ein .php-Suffix an, damit OPcache die Dateien direkt ingestet. Kompression wird für PHP-Code erzwungen auf none. Cluster-Kohärenz kommt aus dem BackendVersion-gefalteten Hash-Pfad — jedes Deploy ergibt einen neuen Pfad, OPcache kühlt automatisch ab, kein opcache_invalidate() nötig.
0x00 = unkomprimiert, 0x01 = zstd, 0x02 = gzip. Der Leser wählt den Dekompressor anhand des Markers — der Schreiber kann Codecs mischen (z. B. kein Komprimieren bei kleinen Payloads, zstd für den Rest).
Option minCompressedBytes (Default 1024): Payloads unterhalb dieser Schwelle werden unkomprimiert gespeichert. Vermeidet den Fixed-Cost von gzdeflate/zstd_compress bei winzigen Werten. 0 = immer komprimieren.
has() / get() / remove() treffen eine In-Memory-Map der jüngsten CacheMetadata-Lookups. Identische Identifier im selben Request überspringen den Valkey/DB-Roundtrip — ca. 200× schneller bei wiederholten has()-Aufrufen.
Vollständig dekodierte Payloads werden per LRU im RAM gecacht (Default: 32 Einträge / 4 MB). Wiederholte get()-Aufrufe auf ein heißes Identifier fallen von ca. 90 µs auf ca. 0,5 µs — 9–20× schneller als SimpleFileBackend auf jedem wiederholten Lesevorgang. Steuerbar über payloadL1MaxEntries und payloadL1MaxBytes. PhpFrontend-Caches überspringen den Payload-L1 (OPcache ist die bessere In-Memory-Repräsentation).
cache_l1_hit_total (v2.3)Neben cache_hit_total und cache_miss_total ermöglicht der neue Counter cache_l1_hit_total die Sichtbarkeit der drei-Schichten-Hit-Verteilung im Betrieb. Alert auf cache_miss_total{reason=metadata-error} für Frühwarnung bei Ausfall des Metadaten-Cache.
┌─ FrankenPHP-Worker RAM ─────────────────────────────────────────┐
│ OPcache (kompilierter PHP-Code) → PhpFrontend .php-Dateien │
│ Payload-L1 (dekomprimierte Bytes) → VariableFrontend-Caches │
│ Metadata-L1 (CacheMetadata-Objekte) → alle Caches │
└─────────────────────────────────────────────────────────────────┘
▲
┌─ Pod-lokales emptyDir ──────────────────────────────────────────┐
│ /<localPath>/<shard>/<sha256>[.php] │
│ • VariableFrontend: 1-Byte-Marker + komprimierte Bytes │
│ • PhpFrontend: Klartext-PHP mit .php-Suffix │
│ → Source of Truth für die Payload-Bytes │
└─────────────────────────────────────────────────────────────────┘
▲
┌─ Metadaten-Cache (Valkey / DB) ─────────────────────────────────┐
│ ~300-Byte-Records: { hash, checksum, lifetime, tags, state } │
│ → Source of Truth für cluster-weite Cache-Gültigkeit │
│ → kein PHP-Code, keine Payload-Bytes │
└─────────────────────────────────────────────────────────────────┘Dieses Paket weiß nichts über Redis/Valkey/KV-Stores. Es spricht ausschließlich mit der TYPO3-Cache-API und delegiert die Cluster-Persistenz an ein vom Anwender gewähltes TYPO3-Cache-Backend.
TYPO3 Cache API → ClusterFileBackend
│
├─► Metadata-Cache (zweites TYPO3-Cache-Frontend,
│ Backend frei wählbar: Typo3DatabaseBackend,
│ KeyValueBackend, MemcachedBackend, …)
│
└─► Local Payload Store (pod-lokal, emptyDir)
TaggableBackendInterface)clusterfilebackend:gc), delegiert ans Metadata-Cache-Backendclusterfilebackend:warmup) plus Event-Listener auf TYPO3s CacheWarmupEventvar/cache/code/core bleibt im Container-Image), keinen Session-Store, keinen generischen Blob-Store, kein Distributed FilesystemKeyValueBackend aus moselwal/keyvalue-store) und verweist ClusterFileBackend per metadataCacheIdentifier daraufext_emconf.php, kein Classic-Mode)moselwal/cluster-file-backend ab ^2.3, Extension-Key cluster_file_backend, Namespace Moselwal\Typo3ClusterCache\TYPO3-Kubernetes-Migration geplant oder bereits im Betrieb? Ich helfe bei Architektur-Review, Cache- und Storage-Design, Migration und Plattform-Setup. Anfragen →
Das Paket registriert die Caches bewusst nicht automatisch. Hostnamen, Ports, TLS, Pfade sind grundsätzlich site-spezifisch. Die folgenden Schritte sind ein einmaliges Setup.
composer require moselwal/cluster-file-backend:^2.3Typo3DatabaseBackend — funktioniert ohne zusätzliche Dependency, solange die Datenbank von allen Pods erreichbar ist (Galera, RDS Multi-AZ, …). Für höhere Performance moselwal/keyvalue-store installieren und dessen KeyValueBackend nutzen.cluster_meta) für die Metadaten registrieren.pages, pagesection, rootline, imagesizes, assets, hash) auf ClusterFileBackend umstellen und per metadataCacheIdentifier auf cluster_meta verweisen.emptyDir unter /app/var/cache/cluster/ (oder dem konfigurierten localPath) mounten.| Artefakt | Pfad | Zweck |
|---|---|---|
| Default-Config (ohne Extra-Deps) | Configuration/Example/cache-configurations.example.php | Datenbank-basierte Metadaten plus Cluster-File-Caches — läuft auf jeder TYPO3-Installation |
| Redis/Valkey-Config (optional) | Configuration/Example/cache-configurations-redis.example.php | Performance-Variante mit moselwal/keyvalue-store |
| JSON-Schema | Configuration/Backend/ClusterFileBackend.options.schema.json | Wird beim Backend-Konstruktor validiert — fehlerhafte Konfiguration führt zu InvalidCacheException mit Feldname |
| CLI-Kommandos | Configuration/Commands.php | clusterfilebackend:gc, clusterfilebackend:warmup |
| Event-Listener | Configuration/Services.yaml | Hängt sich in TYPO3s CacheWarmupEvent — bin/typo3 cache:warmup triggert die Cluster-Warmup mit |
| DI-Bindings | Configuration/Services.yaml | Auto-Discovery für MetricsPort, ClockPort, CompressorPort |
Der ClusterFileBackend-Konstruktor validiert seine Optionen gegen ein JSON-Schema. Pflichtfelder (sonst InvalidCacheException): localPath (absoluter Pfad), metadataCacheIdentifier (Name des Metadata-Cache-Frontends), namespace.environment (prod, staging, testing oder development) und namespace.instance (Slug [a-z0-9-]{1,64}). Wenn der konfigurierte metadataCacheIdentifier nicht als TYPO3-Cache registriert ist, scheitert der Konstruktor sofort mit einer Nachricht, die den Config-Pfad benennt — kein stilles Fehlschlagen beim ersten set().
| Optionsfeld | Default | Bedeutung |
|---|---|---|
compression | zstd | zstd | gzip | none. Bei PhpFrontend-Caches immer auf none erzwungen. |
serializer | igbinary | igbinary | php. Wechsel invalidiert bestehende Einträge. |
defaultLifetimeSeconds | 3600 | TTL wenn der Caller null übergibt. Minimum 1 (Schema lehnt 0 ab). |
maxPayloadBytes | 10485760 (10 MB) | Schreibvorgänge darüber werden mit InvalidDataException abgelehnt. Obere Grenze für unkomprimierte Reads (zstd-Bomb-Mitigierung). |
minCompressedBytes | 1024 | Payloads unterhalb dieser Schwelle werden unkomprimiert gespeichert (1-Byte-Marker 0x00). Spart den Fixed-Cost von zstd_compress/gzdeflate bei winzigen Werten. 0 = immer komprimieren. |
payloadL1MaxEntries | 32 | Maximale Einträge im request-scoped Payload-L1. 0 deaktiviert den Payload-L1 (Metadata-L1 bleibt aktiv). LRU-Eviction. |
payloadL1MaxBytes | 4194304 (4 MB) | Soft-Memory-Budget für den Payload-L1. Einträge, die das Budget überschreiten würden, werden in Insertionsreihenfolge evictet. Ein einzelner Payload größer als dieses Budget umgeht den L1 komplett. 0 = kein Byte-Budget. |
backendVersionEnvVar | IMAGE_TAG | Env-Variable mit dem Deploy-Identifier. Wird in jeden Payload-Hash gefaltet — jedes Deploy bekommt einen frischen Pfad-Baum. Überschreiben für CI-Konventionen wie CI_COMMIT_SHA. |
Den Inhalt von vendor/moselwal/cluster-file-backend/Configuration/Example/cache-configurations.example.php in die config/system/settings.php (oder additional.php) kopieren und environment, instance und localPath auf das Deployment anpassen. Dieses Beispiel nutzt TYPO3-Cores Typo3DatabaseBackend für den Metadaten-Cache — cluster-sicher, sobald die Datenbank cluster-betrieben ist.
Für Sub-Millisekunden-Latenz auf den Metadaten Configuration/Example/cache-configurations-redis.example.php nehmen. Verwendet den KeyValueBackend aus moselwal/keyvalue-store mit optionaler TLS- und Sentinel-Unterstützung.
Schritt 1: Ein TYPO3-Cache-Frontend für die Metadaten definieren. Jedes Backend, das TaggableBackendInterface implementiert (für flushByTag), funktioniert.
$GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['cluster_meta'] = [
'frontend' => \TYPO3\CMS\Core\Cache\Frontend\VariableFrontend::class,
'backend' => \TYPO3\CMS\Core\Cache\Backend\Typo3DatabaseBackend::class,
'options' => [],
'groups' => ['system'],
];
Schritt 2:ClusterFileBackend auf den Metadaten-Cache verweisen — für alle dateibasierten Caches gleichzeitig.
foreach (['pages', 'pagesection', 'rootline'] as $cacheName) {
$GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations'][$cacheName] = [
'frontend' => \TYPO3\CMS\Core\Cache\Frontend\VariableFrontend::class,
'backend' => \Moselwal\Typo3ClusterCache\Infrastructure\Cache\Backend\ClusterFileBackend::class,
'options' => [
'localPath' => '/app/var/cache/cluster/' . $cacheName,
'metadataCacheIdentifier' => 'cluster_meta',
'namespace' => [
'environment' => 'prod',
'instance' => 'website-a',
],
],
'groups' => ['pages'],
];
}
volumes:
- name: cluster-cache
emptyDir: { sizeLimit: 2Gi }
volumeMounts:
- name: cluster-cache
mountPath: /app/var/cache/cluster
Nach einem Rolling-Deploy sollen neue Pods typischerweise erst prüfen, ob sie den Metadaten-Cache erreichen und ob localPath beschreibbar ist, bevor sie Traffic annehmen. Der Warmup lässt sich explizit triggern:
./vendor/bin/typo3 clusterfilebackend:warmup \
--namespace=cfb:prod:website-a:pages \
--namespace=cfb:prod:website-a:pagesection \
--namespace=cfb:prod:website-a:rootline
Das Kommando emittiert eine JSON-Zeile pro Namespace und beendet sich mit Exit-Code ≠ 0, wenn irgendein Namespace die Health-Checks nicht besteht. Damit lässt es sich in Readiness-/Startup-Probes oder Post-Deploy-Jobs einbinden.
Alternativ den TYPO3-Standard-Warmup nutzen — der Event-Listener hängt sich automatisch ein:
./vendor/bin/typo3 cache:warmup
apiVersion: batch/v1
kind: CronJob
metadata:
name: clusterfilebackend-gc-pages
spec:
schedule: "*/15 * * * *"
concurrencyPolicy: Forbid
jobTemplate:
spec:
template:
spec:
containers:
- name: typo3-cli
args: ["clusterfilebackend:gc", "--namespace=cfb:prod:website-a:pages"]
DDD-4-Layer (Domain → Application → Infrastructure → Presentation), enforced via deptrac. Die einzige Außenschnittstelle für „zentrale Wahrheit" ist der MetadataCachePort, implementiert vom Typo3MetadataCache-Adapter, der jeden beliebigen TYPO3-FrontendInterface annimmt.
Häufige Frage: „Wenn ein Redakteur im TYPO3-Backend auf Alle Caches löschen klickt, woher wissen alle Pods davon?"
Kurze Antwort: Der Pod, der den Klick verarbeitet, löscht den zentralen Metadaten-Cache. Alle anderen Pods sehen das beim nächsten get(), weil sie den zentralen Metadaten-Cache abfragen und nicht ihr lokales Filesystem. Kein Pod-zu-Pod-Sync nötig, weil die Metadaten-Wahrheit nie auf einem Pod liegt.
Pod A: TYPO3-Backend „Alle Caches löschen" / Editor speichert Page /
`bin/typo3 cache:flush`
│
▼
ClusterFileBackend::flush() auf Pod A
│
▼ delegiert an Metadaten-Cache-Frontend (z. B. cluster_meta)
$metadataCache->flush()
│
▼ TYPO3-Cache-API ruft das konfigurierte Backend
KeyValueBackend / DatabaseBackend / MemcachedBackend → flush()
│
▼ passiert SERVER-SEITIG (Redis FLUSHDB, SQL TRUNCATE, Memcached flush_all)
Alle Pods sehen die leeren Metadaten sofort
Beim nächsten get(id) auf irgendeinem Pod:
$metadata = $this->metadataCache->get($identifier); // → null (Cache geflushed)
if ($metadata === null) {
// cache_miss_total{reason=no-metadata}++
return null; // ← Pod konsultiert sein lokales FS gar nicht erst
}
Tests/Unit/Deployment/CrossPodFlushTest.php enthält fünf Tests, die das belegen: flush() propagiert ohne Sync sofort zu Pod B; flushByTag() invalidiert nur passende Einträge; lokale Files überleben den Flush als harmlose Waisen; Re-Write nach Flush stellt Konsistenz wieder her; Flush funktioniert für beliebige Pod-Anzahlen (keine Skalierungs-Annahme).
Sei C die Menge aller Cache-Einträge und Ct ⊆ C die Teilmenge der Einträge mit Tag t. Wir schreiben n := |C| für die Gesamtanzahl und m := |Ct| für die Anzahl der mit t getaggten Einträge — es gilt m ≤ n. Damit lässt sich der Unterschied sauber benennen: ClusterFileBackend liegt nicht nur bei kleinerem Argument, sondern in einer anderen Komplexitätsklasse, weil es Backend-native Algorithmen nutzt und keinen Pod-Faktor multipliziert.
Sei zusätzlich P die Anzahl der Pods und e ≤ n die Anzahl der TTL-abgelaufenen Einträge.
| Operation | TYPO3-Core-FileBackend | ClusterFileBackend | Speedup |
|---|---|---|---|
flushByTag | Θ(n) pro Pod — DirectoryIterator über jede Cache-Datei, 2× file_get_contents pro Datei | Θ(m) — Backend liest Tag-Index direkt | Andere Komplexitätsklasse plus Tag-Indizes |
findIdentifiersByTag | Θ(n) pro Pod | O(m) | dito |
collectGarbage | Θ(n) pro Pod, gesamt Θ(n · P) | O(1) aktiv (Redis TTL Auto-Expire) oder O(e) server-seitig (DB) | Backend-native plus Cluster-once |
flush | Θ(n) pro Pod, gesamt Θ(n · P) | Θ(n) einmal server-seitig | Pod-Faktor entfällt, Konstanten ~100–1000× kleiner |
n = 10 000 Cache-Einträge, davon m = 100 mit Tag site_1, P = 5 Pods.
| Setup | File-Reads | unlink-Calls | Round-Trips |
|---|---|---|---|
Core-FileBackend bei flushByTag('site_1') | 2 · n = 20 000 | m = 100 | ≈ 2 n + m = 20 100 lokale FS-I/O pro Pod |
| ClusterFileBackend (Redis) | 0 | 0 | 2 (SMEMBERS + Pipeline DEL) einmal cluster-weit |
Während eines Rolling-Deploys liefern alte und neue Pods gleichzeitig Traffic aus. ClusterFileBackend bewahrt in jedem Skew-Szenario die Korrektheit, aber zwei Fälle ändern das Performance-Profil während des Deploy-Fensters — die sollte man verstehen.
Wenn das neue Image für denselben Cache-Identifier eine andere Payload-Struktur schreibt (zusätzliche Felder, geänderte serialisierte Klassen, anders aufgebaute Value-Objects) und du nicht explizit invalidierst, passiert Folgendes:
Das größere Risiko ist stiller Layout-Drift: kann Pod-neu die Bytes von Pod-alt zwar technisch deserialisieren, das resultierende Objekt ist aber falsch (fehlende Felder, alte Enum-Cases, entfernte Properties), sieht der User stale oder korrupten Content. PHPs unserialize verifiziert die Klassen-Shape jenseits des Klassennamens nicht.
Damit jedes Release automatisch eine neue BackendVersion bekommt und stale Einträge unerreichbar werden, liest ClusterFileBackend eine Environment-Variable — per Default IMAGE_TAG — und faltet ihren Wert via crc32 in den Payload-Hash. Im Deployment-Manifest:
# Helm-Values, Kustomize-Patch oder plain Pod-Spec
env:
- name: IMAGE_TAG
value: "{{ .Values.image.tag }}" # oder $CI_COMMIT_SHA, Release-Semver, ...
Pro Cache lässt sich der Variablenname überschreiben, falls die CI-Konvention anders heißt:
'options' => [
'localPath' => '/app/var/cache/cluster/pages',
'metadataCacheIdentifier' => 'cluster_meta',
'namespace' => ['environment' => 'prod', 'instance' => 'site'],
'backendVersionEnvVar' => 'CI_COMMIT_SHA',
],
Ist die Variable unset oder leer, fällt das Backend auf die package-interne BackendVersion::current() zurück — sicher für lokale Entwicklung, in Production solltest du die Variable aber explizit verdrahten, um deploy-scoped Invalidierung zu bekommen.
clusterfilebackend:warmup in der Deploy-Pipeline — dränt stale Einträge ab, bevor das neue Image Traffic annimmt.pages → pages_v2 in den cacheConfigurations). Schwerer Hammer, nur für größere Schema-Umbauten.Bei nicht-brechenden Layout-Änderungen (additiv, vom alten Code ignoriert) kann man das temporäre Thrashing akzeptieren — die Korrektheit bleibt erhalten.
Der Identity-Hash enthält PHP_MAJOR.PHP_MINOR (Classes/Application/Hash/ComputePayloadHash.php). PHP 8.4 ↔ 8.5 (oder jeder andere Major/Minor-Sprung) erzeugt automatisch divergente Hashes — keine manuelle Aktion nötig. Korrektheit garantiert. Die Kosten sind dasselbe Thrashing wie in (A) für die Dauer des Rollouts. blob_miss_total in Prometheus beobachten; ein anhaltender Spike über das Deploy-Fenster hinaus deutet darauf hin, dass die Version-Skew nicht konvergiert (z. B. ein Pod im alten Image hängen geblieben).
PHP-Patch-Updates (8.5.4 → 8.5.5) invalidieren nicht — nur Major und Minor sind im Hash.
Recreate-Strategie oder einen Pre-Flush via Warmup-Kommando fahren.Cache-Lifetimes werden gegen die lokale Uhr jedes Pods ausgewertet. Weichen Pods in der Wanduhrzeit um mehr als ein paar Sekunden ab, behandelt ein Pod mit vorausgehender Uhr Einträge als abgelaufen, bevor Peers das tun — Korrektheit bleibt erhalten, Performance leidet. In Kubernetes ist das normalerweise kein Problem (Nodes synchronisieren per chrony/systemd-timesyncd gegen Cluster-NTP). Sanity-Check bei Incidents:
kubectl exec deploy/typo3 -- date -u
Ein Skew >30 Sekunden über Pods hinweg ist die Schwelle, ab der blob_miss_total und cache_miss_total{reason=expired} in Prometheus sichtbar auseinanderdriften.
Der Metadaten-Cache (Redis/Valkey/DB) ist die einzige Source of Truth. Ist er nicht erreichbar:
Der Metadaten-Cache muss ein TaggableBackendInterface-Backend nutzen, sonst wird flushByTag zur No-Op. Geprüfte Backends:
| Backend | Taggable | Hinweis |
|---|---|---|
Typo3DatabaseBackend | ✅ | Zero-Dependency-Default |
KeyValueBackend (moselwal/keyvalue-store) | ✅ | Redis/Valkey, empfohlen für hohen Traffic |
MemcachedBackend (TYPO3 Core) | ❌ | Unterstützt keine Tags — inkompatibel |
RedisBackend (TYPO3 Core) | ❌ | Nicht taggable — stattdessen moselwal/keyvalue-store verwenden |
Jeder Container, der auf denselben Metadaten-Cache zeigt, muss denselben IMAGE_TAG (oder die konfigurierte backendVersionEnvVar) sehen. Läuft der Web-Pod mit IMAGE_TAG=1.2.3 und ein Worker/Cron-Pod noch mit IMAGE_TAG=1.2.2, berechnen beide unterschiedliche BackendVersion-Werte und behandeln gegenseitige Writes als Blob-Misses. Symptom: persistentes Thrashing in gemischten Deployments. Helm/Kustomize-Tipp: Tag in einen einzigen Value extrahieren und von jeder Pod-Spec aus referenzieren.
Lifetime::unlimited() mappt auf expiresAt = 2147483647 (spiegelt TYPO3-Cores Typo3DatabaseBackend::FAKED_UNLIMITED_EXPIRE). Am 2038-01-19 03:14:07 UTC wird dieser Timestamp zu „jetzt“ und als unbegrenzt gespeicherte Einträge gelten als abgelaufen. Praktische Auswirkung bis dahin: keine.
BackendVersion::fromString(…) faltet den Deploy-Identifier via crc32 auf ein 32-Bit-Integer. Geburtstags-Kollisionen treten bei ca. 77 000 eindeutigen Deploy-Identifiern auf — bei realistischer Release-Kadenz (einige Deploys pro Tag über die Laufzeit eines Projekts) bleibt die Kollisionswahrscheinlichkeit unter 1:10⁵. Wer regelmäßig Tausende unterschiedliche Identifier durchläuft, sollte auf einen stabilen, menschenlesbaren Semver-String statt rohen Commit-SHAs setzen.
localPath muss schreibbar sein. Bei read-only /app-Image ein emptyDir oder tmpfs an diesem Pfad mounten.IMAGE_TAG (oder dein Äquivalent) in Production verdrahten. Ohne diese Variable nutzt das Backend eine package-interne Versions-Konstante, die sich über Deploys NICHT ändert — brechende Cache-Layout-Änderungen können dann stillschweigend stale oder korrupten Content ausliefern. Siehe „Rolling-Deploys mit Version-Skew".metadataCacheIdentifier muss vor jedem Cache registriert sein, der ClusterFileBackend nutzt. TYPO3 lädt cacheConfigurations in Array-Insertion-Order — also cluster_meta zuerst definieren.ext_emconf.php, kein Classic-Mode.TYPO3 unter Kubernetes betreiben?
Wenn du TYPO3 in einem K8s-Cluster ohne RWX-Volume betreibst oder ein bestehendes FileBackend-Setup für Multi-Pod auslegst, hilft cluster-file-backend. Sprich mich für Architektur-Beratung, Migration oder Plattform-Setup an.
Oder direkt schreiben: kontakt@moselwal.de
Dieses Paket übernimmt die dateibasierte Cache-Schicht in TYPO3 Kubernetes — eine der Voraussetzungen für Multi-Pod-Cluster, die unter Open Source & Digitale Souveränität beschrieben sind. In der betreuten Variante: AI-Ready CMS as a Service.