Vom TYPO3 Container-Hosting zum Cluster

Herausforderungen, Architektur und Sicherheitskonzepte auf dem Weg zum hochverfügbaren TYPO3-System.

Was als einfaches Docker-Container-Hosting mit einer einzelnen TYPO3-Instanz begann, wächst in dieser Serie Schritt für Schritt zu einer produktionsreifen Cluster-Lösung. In diesem Teil bereiten wir den Container für den Produktionseinsatz vor — mit Fokus auf Sicherheit, Stabilität und Immutability.

Übersicht

Diese Artikelserie behandelt den kompletten Weg vom einfachen Container-Hosting bis zum produktionsreifen Cluster:

  1. Teil 1 — Grundlagen: Container und TYPO3
  2. Teil 2 — Dockerfile und Image-Aufbau
  3. Teil 3 — PHP-FPM Konfiguration
  4. Teil 4 — Webserver-Integration (Caddy/Nginx)
  5. Teil 5 — Datenbank und Persistenz
  6. Teil 6 — Caching mit Redis/Valkey
  7. Teil 7 — Secrets Management
  8. Teil 8 — CI/CD Pipeline
  9. Teil 9 — Monitoring und Logging
  10. Teil 10 — Cluster-Betrieb mit Kubernetes
  11. Teil 11 — Production Hardening

Container ready for Take-Off

Das zentrale Prinzip beim Übergang in die Produktion lautet: Sicherheit und Stabilität stehen an erster Stelle. Ein Container-Image, das in der Entwicklung funktioniert, ist noch lange nicht produktionsreif.

Der wichtigste Grundsatz dabei ist Immutability: Ein Container-Image darf sich nach dem Release nicht mehr verändern. Was gebaut und getestet wurde, ist exakt das, was in Produktion läuft. Keine nachträglichen Änderungen, keine manuellen Eingriffe, keine Überraschungen.

DevOps-Grundlagen

DevOps beschreibt die Zusammenarbeit von Entwicklung (Dev) und Betrieb (Ops) mit dem Ziel, Software schneller, zuverlässiger und automatisiert bereitzustellen. Es ist keine Rolle, sondern eine Kultur und Methodik, die Silos zwischen Teams aufbricht.

SRE (Site Reliability Engineering) ist Googles Implementierung von DevOps-Prinzipien. SRE behandelt den Betrieb als Software-Engineering-Problem und definiert messbare Ziele für Verfügbarkeit (SLOs), automatisierte Incident Response und systematisches Capacity Planning.

Minimalistische Systeme oder nicht?

Für Produktions-Container gelten klare Prinzipien:

Betriebssystem-Vergleich für Container

Die Wahl des Base-Images hat direkten Einfluss auf Sicherheit und Wartbarkeit:

RHEL / UBI (Red Hat Universal Base Image):

Alpine Linux:

Wolfi OS (empfohlen):

Immutability

Immutability ist der Schlüssel zu stabilen und sicheren Containern. Das Prinzip:

Wenn ein Problem auftritt, wird nicht der laufende Container repariert — es wird ein neues Image gebaut und deployed. Das eliminiert Configuration Drift und macht Rollbacks trivial.

Vorbereitung der Konfigurationsdateien

Bevor wir das Dockerfile erstellen, bereiten wir die PHP-Konfigurationsdateien vor. Diese werden beim Build in das Image kopiert.

php.ini

Die php.ini wird für Produktion optimiert:

 

[PHP]
; Fehleranzeige deaktiviert — Fehler gehören ins Log, nicht auf den Bildschirm
display_errors = Off
display_startup_errors = Off
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
log_errors = On
error_log = /proc/self/fd/2
; Sicherheitsrelevante Einstellungen
expose_php = Off
allow_url_fopen = On
allow_url_include = Off
; Performance-Einstellungen
max_execution_time = 240
max_input_time = 60
max_input_vars = 1500
memory_limit = 512M
post_max_size = 100M
upload_max_filesize = 100M
; Session-Konfiguration
session.cookie_httponly = On
session.cookie_secure = On
session.cookie_samesite = Strict
session.use_strict_mode = On
; OPcache für Produktion
opcache.enable = 1
opcache.enable_cli = 0
opcache.memory_consumption = 256
opcache.interned_strings_buffer = 32
opcache.max_accelerated_files = 20000
opcache.validate_timestamps = 0
opcache.save_comments = 1
opcache.jit = tracing
opcache.jit_buffer_size = 128M
; Zeitzone
date.timezone = Europe/Berlin
; Realpath Cache (wichtig für Symfony/TYPO3)
realpath_cache_size = 4096K
realpath_cache_ttl = 600

 

Wichtige Hinweise zu den Einstellungen:

www.conf (PHP-FPM Pool-Konfiguration)

Die Pool-Konfiguration steuert, wie PHP-FPM Worker-Prozesse verwaltet:

 

[www]
user = www-data
group = www-data
listen = 9000
; Process Management
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35
pm.max_requests = 500
; Status und Ping für Health Checks
pm.status_path = /status
ping.path = /ping
ping.response = pong
; Logging
access.log = /proc/self/fd/2
slowlog = /proc/self/fd/2
request_slowlog_timeout = 5s
; Sicherheit
security.limit_extensions = .php
; Umgebungsvariablen durchreichen
clear_env = no

 

Wichtige Einstellungen erklärt:

php-fpm.conf

Die globale PHP-FPM-Konfiguration:

 

[global]
error_log = /proc/self/fd/2
log_limit = 1000000

 

Der log_limit wird auf 1.000.000 Zeichen gesetzt, damit auch lange Stack-Traces vollständig im Log erscheinen (der Default ist nur 1024 Zeichen).

Aufbau des Dockerfiles

Das Dockerfile nutzt Wolfi OS als Basis und folgt dem Multi-Stage-Build-Prinzip:

 

# Stage 1: Build
FROM cgr.dev/chainguard/wolfi-base AS build
# PHP und Build-Abhängigkeiten installieren
RUN apk add --no-cache \
    php-8.3 \
    php-8.3-fpm \
    php-8.3-pdo \
    php-8.3-pdo_mysql \
    php-8.3-gd \
    php-8.3-intl \
    php-8.3-opcache \
    php-8.3-zip \
    php-8.3-xml \
    php-8.3-mbstring \
    php-8.3-curl \
    php-8.3-tokenizer \
    php-8.3-fileinfo \
    php-8.3-session \
    php-8.3-ctype \
    composer
# Composer Dependencies installieren
WORKDIR /app
COPY composer.json composer.lock ./
RUN composer install --no-dev --optimize-autoloader --no-scripts
COPY . .
RUN composer dump-autoload --optimize
# Stage 2: Production
FROM cgr.dev/chainguard/wolfi-base AS production
RUN apk add --no-cache \
    php-8.3 \
    php-8.3-fpm \
    php-8.3-pdo \
    php-8.3-pdo_mysql \
    php-8.3-gd \
    php-8.3-intl \
    php-8.3-opcache \
    php-8.3-zip \
    php-8.3-xml \
    php-8.3-mbstring \
    php-8.3-curl \
    php-8.3-tokenizer \
    php-8.3-fileinfo \
    php-8.3-session \
    php-8.3-ctype
# Konfigurationsdateien kopieren
COPY docker/php/php.ini /etc/php/8.3/php.ini
COPY docker/php/www.conf /etc/php/8.3/php-fpm.d/www.conf
COPY docker/php/php-fpm.conf /etc/php/8.3/php-fpm.conf
# Anwendung aus Build-Stage kopieren
COPY --from=build /app /var/www/html
# Unprivilegierter Benutzer
RUN adduser -D -u 1000 www-data
USER www-data
WORKDIR /var/www/html
EXPOSE 9000
CMD ["php-fpm8.3", "-F"]

 

Wichtige Punkte zum Dockerfile:

Erstellen des Images

Das Image wird mit einem einfachen docker build erstellt:

 

docker build -t typo3-app:latest -f Dockerfile .

 

Für Multi-Architektur-Support (z.B. ARM64 für AWS Graviton oder Apple Silicon) kann docker buildx verwendet werden:

 

docker buildx build --platform linux/amd64,linux/arm64 -t typo3-app:latest .

 

Nach dem Build sollte das Image mit RepoDigests getaggt werden. Ein RepoDigest ist ein SHA256-Hash, der das Image eindeutig identifiziert — unabhängig vom Tag. So ist sichergestellt, dass exakt dieses Image deployed wird:

 

docker inspect --format='{{index .RepoDigests 0}}' typo3-app:latest

 

In Produktions-Deployments sollte immer der Digest statt eines Tags referenziert werden, da Tags überschrieben werden können, Digests aber unveränderlich sind.