Container-Ressourcen begrenzen - RAM und CPU-Limits setzen

Container-Ressourcen begrenzen - RAM und CPU-Limits setzen

Ohne Ressourcen-Limits kann ein einziger Container den Host lahmlegen — RAM und CPU-Limits sind kein Luxus, sondern Pflicht.

Das Problem

Standardmäßig darf jeder Container beliebig viel RAM und CPU des Hosts verbrauchen. Eine Memory-Leak-App oder ein außer Kontrolle geratener Worker kann alle anderen Dienste auf demselben Host zum Erliegen bringen.

RAM begrenzen

docker run --memory="512m" --memory-swap="512m" nginx
  • --memory="512m": Maximaler RAM
  • --memory-swap="512m": Swap auf denselben Wert setzen = kein Swap (Swap = Memory − RAM-Limit)

Swap auf gleichen Wert setzen ist in der Regel die richtige Wahl: Container sollen schnell fehlschlagen statt langsam auf Disk auslagern.

Gültige Einheiten: b, k, m, g

Was passiert bei Überschreitung?

Der Linux OOM-Killer beendet den Prozess. Exit-Code des Containers: 137 (128 + SIGKILL).

docker ps -a   # STATUS: Exited (137)
docker inspect --format='{{.State.OOMKilled}}' <container>   # true

CPU begrenzen

docker run --cpus="0.5" nginx    # Maximal halbe CPU
docker run --cpus="2.0" nginx    # Maximal 2 CPUs

--cpus entspricht dem Bruchteil eines CPU-Kerns — auf einem 4-Kern-System bedeutet --cpus="2.0" maximal 50% Gesamtauslastung.

Alternativ mit CPU-Shares (relativ, kein hartes Limit):

docker run --cpu-shares=512 nginx   # Halb so viel Priorität wie Standard (1024)

In Docker Compose

Hier gibt es eine wichtige Unterscheidung:

Mit --compatibility-Flag (Einzelhost):

services:
  app:
    image: myapp
    deploy:
      resources:
        limits:
          memory: 512m
          cpus: '0.5'
        reservations:
          memory: 256m
          cpus: '0.25'
docker compose --compatibility up   # Ohne dieses Flag werden deploy.resources ignoriert

Oder direkt (ältere Syntax, breiter unterstützt):

services:
  app:
    image: myapp
    mem_limit: 512m
    memswap_limit: 512m
    cpus: 0.5

Ressourcenverbrauch überwachen

docker stats                          # Live-Ansicht aller Container
docker stats --no-stream              # Einmalige Momentaufnahme
docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.MemPerc}}"

Empfehlungen für die Praxis

Datenbank (z.B. Postgres):

mem_limit: 2g
memswap_limit: 2g
cpus: 1.0

Web-App:

mem_limit: 512m
memswap_limit: 512m
cpus: 0.5

Background-Worker:

mem_limit: 256m
memswap_limit: 256m
cpus: 0.25

Limits finden

Zu niedrige Limits schaden. Zunächst ohne Limits starten, docker stats im Normalbetrieb beobachten, Spitzenwerte mit 20–30 % Puffer als Limit setzen.

# Aktuellen Limit eines laufenden Containers prüfen
docker inspect --format='{{.HostConfig.Memory}}' <container>   # Bytes, 0 = kein Limit

Ressourcen-Limits sind eine der wenigen Maßnahmen, die gleichzeitig Stabilität und Sicherheit verbessern — kein Grund, sie wegzulassen.