Running Services in Alpine Containers (Artikel 214)
Beherrschung von Dienst-Prozessen in Alpine-Containern. Erfahren Sie alles über das PID 1 Problem, Signal-Handling mit Tini und den Verzicht auf schwere Init-Systeme.
# Alpine Container: Dienste sicher und sauber ausführen
TL;DR / Management Summary Ein Container ist kein virtueller Server. Während wir auf einem SLES-Host (Artikel 138) ein Init-System wie systemd oder OpenRC haben, läuft im Container meist nur ein einziger Prozess als PID 1. Dies führt oft zu Problemen bei der Signal-Verarbeitung (z.B. SIGTERM) und hinterlässt Zombie-Prozesse. In diesem Modul lernen wir, wie wir Alpine-Container mit Tini stabilisieren und warum wir niemals ein volles OpenRC innerhalb eines Docker-Containers starten sollten.
# 1. Einführung & Architektur
Das PID 1 Dilemma.
In Linux übernimmt der Prozess mit der ID 1 (Init) zwei Aufgaben:
- Signal Forwarding: Signale (wie
docker stop) an Kind-Prozesse weitergeben. - Zombie Reaping: Beendete Prozesse sauber aus der Prozesstabelle entfernen.
Die meisten Applikationen (Java, Python, Node) sind nicht darauf ausgelegt, PID 1 zu sein. Sie ignorieren Signale und erzeugen Zombies.
# Die Architektur-Lösung (Mermaid)
graph LR
subgraph "Standard Docker"
A[Docker Engine] -->|Sends SIGTERM| B[App: PID 1]
B -->|Ignores Signal| B
A -->|Timeout 10s| C[Docker Engine: SIGKILL]
end
subgraph "Alpine with Tini"
D[Docker Engine] -->|Sends SIGTERM| E[Tini: PID 1]
E -->|Forwards Signal| F[App: PID 7]
F -->|Graceful Shutdown| G[Exit]
E -->|Reaps Zombies| E
end
# 2. Implementierung von Tini
Der minimalistische Init-Wächter.
Alpine bietet tini als offizielles Paket an.
# Nutzung im Dockerfile
FROM alpine:3.18
RUN apk add --no-cache tini
# Starten Sie die Applikation über Tini
ENTRYPOINT ["/sbin/tini", "--"]
CMD ["/usr/local/bin/myapp"]
# 3. Services ohne OpenRC
Container-native Ausführung.
Vermeiden Sie es, rc-service oder rc-update im Dockerfile zu nutzen. Container-Dienste sollten im Vordergrund laufen.
# Beispiel: Nginx in Alpine
FROM alpine:3.18
RUN apk add --no-cache nginx tini
# Nginx muss im Vordergrund bleiben (daemon off)
ENTRYPOINT ["/sbin/tini", "--"]
CMD ["nginx", "-g", "daemon off;"]
# 4. Day-2 Operations: Mehrere Prozesse?
Wenn ‘One Process per Container’ nicht reicht.
Manchmal muss ein Sidecar-Prozess (z.B. ein Log-Shipper) im gleichen Container laufen. Nutzen Sie hierfür kein systemd!
# Die Lösung: s6-overlay
Für Alpine gibt es das s6-overlay, ein extrem leichtgewichtiges Prozess-Management-System für Container.
- Es startet als PID 1.
- Es überwacht mehrere Dienste.
- Es beendet den gesamten Container, wenn ein kritischer Dienst stirbt.
# 5. Troubleshooting & “War Stories”
Wenn der Container hängen bleibt.
# Story 1: “Der unendliche Shutdown”
Symptom: docker stop dauert immer genau 10 Sekunden, danach wird der Container gewaltsam beendet.
Ursache: Die Applikation (z.B. ein Python-Skript) läuft als PID 1 und hat keinen Signal-Handler für SIGTERM. Sie “hört” den Stopp-Befehl nicht.
Lösung: Schalten Sie tini davor (siehe Punkt 2). Tini nimmt das Signal entgegen und beendet den Prozess sofort.
# Story 2: “Die Zombie-Invasion”
Symptom: Ein Cron-Job innerhalb des Containers startet alle 5 Minuten ein Skript. Nach 24 Stunden meldet das System fork: resource temporarily unavailable. ps aux zeigt tausende Einträge mit <defunct>.
Ursache: Die Kind-Prozesse werden beendet, aber niemand (PID 1) räumt sie weg.
Lösung: Auch hier ist tini die Lösung. Es übernimmt die Adoption von verwaisten Prozessen und löscht sie aus der Tabelle.
# 6. Fazit & Empfehlung
- Pflicht: Nutzen Sie
tinifür jeden Alpine-Container, der nicht nur ein statisches Binary (Go/Rust) ausführt. - Vermeidung: Installieren Sie keine Init-Systeme wie OpenRC oder systemd in Containern. Es widerspricht dem Container-Konzept und bläht das Image unnötig auf.
- Signale: Testen Sie Ihre Applikationen mit
docker stop. Wenn es länger als 2 Sekunden dauert, stimmt Ihr Signal-Handling nicht.
# Anhang: Cheatsheet
| Aufgabe | Tool / Parameter |
|---|---|
| Tini installieren | apk add --no-cache tini |
| Zombies finden | `ps aux |
| Signal an PID 1 | docker kill --signal=SIGTERM <id> |
| Multi-Process | s6-overlay |
| Entrypoint Test | docker run --rm -it <image> /bin/sh |
| PID Liste sehen | docker top <id> |