Proxmox und der OOM‑Killer

Wenn plötzlich die wichtigste VM aus geht

„Ich geh nach Haus, das Licht bleibt aus…“

So ungefähr fühlte es sich an, als plötzlich meine wichtigste VM – ioBroker – verschwunden war. Keine Fehlermeldung im Webinterface, kein Absturzdialog, kein dramatischer Kernel-Panic-Screen. Die VM war einfach weg.

Der Übeltäter: der Linux OOM-Killer.

OOM steht für Out Of Memory. Wenn dem System der Arbeitsspeicher ausgeht, greift Linux zu einer letzten Notmaßnahme: Ein Prozess wird beendet, damit wieder Speicher frei wird.

Blöd nur, wenn das ausgerechnet die wichtigste VM ist.

In meinem Fall also: Licht aus.


Schnellnavigation


Was ist der OOM-Killer?

Linux versucht normalerweise alles, um ohne Totalausfall auszukommen. Wenn der RAM knapp wird, passiert zunächst Folgendes:

  1. Speicher wird freigeräumt
  2. Cache wird reduziert
  3. Swap wird verwendet

Erst wenn all das nicht mehr reicht, greift der Kernel zum letzten Mittel: Der OOM-Killer beendet Prozesse. Wer das nerdiger nachlesen will, findet in der offiziellen Linux-Dokumentation Details zum Verhalten des Speichermanagements und des OOM-Killers unter docs.kernel.org.

Der Kernel entscheidet dabei anhand verschiedener Kriterien, welcher Prozess „am ehesten entbehrlich“ ist. Leider bedeutet das oft ziemlich unromantisch:

Der Prozess mit dem größten Speicherverbrauch fliegt zuerst.

Auf einem Proxmox-Host sind das häufig die KVM-Prozesse, also laufende virtuelle Maschinen. Proxmox selbst dokumentiert die QEMU/KVM-Architektur und das Verhalten virtueller Maschinen in der offiziellen Doku unter pve.proxmox.com.


Wie erkennt man, dass der OOM-Killer zugeschlagen hat?

Der erste Hinweis findet sich im Systemlog. Auf einem Proxmox-Host kannst du einfach danach suchen:

dmesg | grep -i "out of memory"

Oder etwas ausführlicher:

journalctl -k | grep -i oom

Ein typischer Eintrag sieht zum Beispiel so aus:

Out of memory: Killed process 5003 (kvm) total-vm:11083204kB

Das bedeutet:

  • Ein Prozess (kvm) wurde beendet
  • Der Kernel hat ihn ausgewählt, um Speicher freizugeben

Wenn zusätzlich so etwas auftaucht:

task_memcg=/qemu.slice/111.scope

Dann weißt du sogar welche VM betroffen war.

In meinem Fall: VM 111 – ioBroker.

Praktisch ist dabei: Die Kernel-Dokumentation beschreibt auch, dass OOM-Ereignisse im Zusammenhang mit Speicherdruck und Auswahlkriterien protokolliert werden können. Wer tiefer graben will, kann zusätzlich in die Sysctl-Doku zu /proc/sys/vm schauen: Kernel-Dokumentation zu /proc/sys/vm.


Wie prüft man den verfügbaren RAM?

Der schnellste Überblick geht mit:

free -h

Beispielausgabe:

Mem:   8Gi total, 8Gi used, 0Gi free
Swap:  7.6G, 4.7G used

Hier siehst du sofort:

  • Gesamter RAM
  • Aktuelle Nutzung
  • Swap-Verbrauch

Wenn Swap bereits stark benutzt wird, ist das ein Hinweis darauf, dass das System dauerhaft unter Speicherdruck steht. Für solche Fälle lohnt sich oft nicht erst akademisches Herumgeeier, sondern ein echter Blick auf die RAM-Ausstattung. Falls dein Host noch mit eher knappen 8 GB oder 16 GB unterwegs ist, kann ein Upgrade auf 32 GB DDR4-Arbeitsspeicher (bezahlter Link) oder bei passenden Plattformen auf ECC-RAM für Server und NAS-Systeme (bezahlter Link) oft mehr bewirken als jede noch so heldenhafte Shell-Magie.


Welche Hardware steckt eigentlich im Proxmox-Host?

Bevor man über Upgrades nachdenkt, sollte man prüfen, was tatsächlich verbaut ist. Das geht direkt über die Konsole.

Mainboard anzeigen:

dmidecode -t baseboard

Speicher anzeigen:

dmidecode -t memory

Oder kompakt:

dmidecode -t memory | grep -E "Size:|Speed:"

Damit sieht man sofort:

  • Wie viele RAM-Module verbaut sind
  • Welche Geschwindigkeit sie haben
  • Welche Slots frei sind

Gerade bei gebrauchten Office-PCs, Mini-Servern oder alten Workstations ist das Gold wert. Sonst bestellt man im schlimmsten Fall motiviert irgendwelche Module, und das Board schaut einen anschließend an wie ein Beamter kurz vor Feierabend.


ZFS und ARC – der heimliche RAM-Verbraucher

Viele Proxmox-Installationen nutzen ZFS als Storage. Das ist extrem robust, bietet Prüfsummen, Snapshots und viele Dinge, wegen denen man sich ein bisschen fühlt, als hätte man plötzlich Enterprise-Spielzeug im Keller stehen.

Der Haken: ZFS nutzt RAM sehr aggressiv.

Der sogenannte ARC (Adaptive Replacement Cache) ist ein intelligenter Cache im Arbeitsspeicher. Je mehr RAM verfügbar ist, desto größer wird dieser Cache. Das ist grundsätzlich kein Bug, sondern genau so vorgesehen. OpenZFS dokumentiert ARC und die zugehörigen Parameter offiziell in der eigenen Doku, zum Beispiel über arcstat und die ZFS-Modulparameter.

Die aktuelle ARC-Größe lässt sich so anzeigen:

cat /proc/spl/kstat/zfs/arcstats | grep size

Bei wenig RAM kann ARC ein zusätzlicher Faktor sein, der den Speicherverbrauch erhöht. Das heißt nicht automatisch, dass ZFS „schuld“ ist – aber in kleinen Hosts mit mehreren VMs spielt es definitiv mit in derselben Speicher-Drama-AG.

Falls du ZFS produktiv im Homelab betreibst, kann auch ein Blick auf passende NVMe-SSDs für Storage und Cache-Aufgaben (bezahlter Link) sinnvoll sein. Mehr Performance ersetzt zwar keinen fehlenden RAM, aber in einem sauber geplanten Setup gehören Storage und Arbeitsspeicher nun mal zusammen wie Proxmox und „ich baue nur mal eben schnell noch eine VM“.


Mehr RAM – der einfachste Fix

In meinem Setup lief der Proxmox-Host ursprünglich mit 8 GB RAM.

Für:

  • Proxmox selbst
  • mehrere VMs
  • ZFS
  • Backups

ist das schlicht zu wenig.

Nach einem Upgrade auf 32 GB RAM sah die Lage plötzlich ganz anders aus. Genau deshalb ist zusätzlicher Arbeitsspeicher für viele Homelab-Systeme keine Luxus-Aufrüstung, sondern schlicht die vernünftigste Lösung. Wenn du gerade ohnehin nachrüstest, findest du passende Module zum Beispiel über 32-GB-DDR4-Kits (bezahlter Link) oder – falls dein System das unterstützt – über ECC-UDIMM-Module für zuverlässigere Server-Setups (bezahlter Link).

free -h

Mem:   31Gi total, 11Gi used, 18Gi free
Swap:  7.6Gi total, 0B used

Swap wird nicht mehr benutzt und der Host hat wieder ausreichend Reserven.

Und ja: Manchmal ist die beste Tuning-Methode eben nicht irgendein finsteres Kernel-Voodoo, sondern schlicht mehr RAM. Sehr unsexy. Sehr effektiv.


Wichtige VMs vor dem OOM-Killer schützen

Nicht jede VM in einem Proxmox-Homelab ist gleich wichtig. Wenn ein Testsystem abstürzt, ist das meist verschmerzbar. Wenn dagegen die zentrale Smart-Home-Instanz oder der ioBroker plötzlich verschwindet, sieht die Sache anders aus.

Linux besitzt dafür einen Mechanismus, mit dem Prozesse unterschiedlich priorisiert werden können: oom_score_adj. Dieser Wert beeinflusst, wie attraktiv ein Prozess für den OOM-Killer ist. Der Wertebereich liegt zwischen:

  • -1000 → möglichst niemals beenden
  • 0 → normale Priorität
  • +1000 → möglichst zuerst beenden

Warum systemctl set-property hier nicht funktioniert

Ein naheliegender Versuch ist, die Priorität direkt über systemd zu setzen:

systemctl set-property 111.scope OOMScoreAdjust=-900

In der Praxis funktioniert das jedoch nicht zuverlässig, weil OOMScoreAdjust keine Runtime-Property ist, die sich hier einfach so setzen lässt. Proxmox beziehungsweise systemd quittiert das dann gern mit:

Unknown assignment: OOMScoreAdjust=-900

Wichtige VM direkt schützen

Stattdessen kann der Wert direkt am laufenden QEMU-Prozess der VM gesetzt werden:

PID="$(pgrep -f 'kvm.*-id 111' | head -n1)"
echo -900 > /proc/$PID/oom_score_adj
cat /proc/$PID/oom_score_adj

Damit wird der OOM-Score der VM deutlich reduziert und der Kernel wird versuchen, andere Prozesse zuerst zu beenden.

Opfer-VMs definieren

Der umgekehrte Ansatz ist ebenfalls möglich: weniger wichtige Systeme bekommen bewusst einen höheren Wert, damit sie im Ernstfall zuerst beendet werden.

PID="$(pgrep -f 'kvm.*-id 200' | head -n1)"
echo 500 > /proc/$PID/oom_score_adj
cat /proc/$PID/oom_score_adj

Man könnte es auch so formulieren:

Wenn jemand gehen muss, dann bitte zuerst die Testmaschine.

Wichtiger Hinweis und Hookscripts

Der manuelle Weg funktioniert zwar sofort, hat aber einen Haken: Nach jedem Neustart der VM bekommt der QEMU-Prozess eine neue PID und der Wert muss erneut gesetzt werden. In Proxmox lässt sich das eleganter lösen, indem man ein sogenanntes Hookscript verwendet. Hookscripts werden in bestimmten Lebenszyklus-Phasen einer VM ausgeführt, zum Beispiel direkt nach dem Start. In der post-start-Phase könnte ein kleines Skript automatisch die PID des QEMU-Prozesses ermitteln und den gewünschten oom_score_adj-Wert setzen. Damit wird der OOM-Schutz bei jedem VM-Start automatisch wieder aktiviert. Die Hookscript-Funktion dokumentiert Proxmox offiziell sowohl im qm-Handbuch als auch im Bereich QEMU/KVM Virtual Machines.

Für den Alltag heißt das: Manuell testen ist okay. Dauerhaft sauber wird es erst mit Automatisierung. Alles andere ist technisch gesehen nur glorifiziertes „Denk dran, das nach jedem Start wieder zu machen“ – also exakt die Sorte Plan, die in Homelabs irgendwann nachts um 23:47 Uhr implodiert.


Copy & Paste: VM-Forensik-Skript für Proxmox

Wenn eine VM plötzlich ausgeht und du nicht weißt, ob jemand sie heruntergefahren hat oder ob der Proxmox OOM-Killer zugeschlagen hat, hilft ein kleines Bash-Skript. Es sammelt automatisch die wichtigsten Logs und Statusinformationen.

Das Skript

#!/usr/bin/env bash
set -euo pipefail

VMID=111
SINCE="${1:-3 days ago}"

echo "== Proxmox VM-Forensik: VMID=$VMID | since: $SINCE =="
echo

echo "## 1) Status & Konfig (onboot/startup, etc.)"
qm status "$VMID" || true
echo
qm config "$VMID" | egrep -i '^(name:|onboot:|startup:|boot:|memory:|balloon:|cores:|sockets:|scsi|sata|virtio|net|agent:|machine:|bios:|ostype:|tags:)' || true
echo

echo "## 2) QEMU-Log der VM (letzte 250 Zeilen)"
QLOG="/var/log/pve/qemu-server/${VMID}.log"
if [[ -f "$QLOG" ]]; then
  ls -lh "$QLOG"
  echo
  tail -n 250 "$QLOG"
else
  echo "Kein Log gefunden: $QLOG"
fi
echo

echo "## 3) Proxmox Task-Index: Stop/Shutdown/Reset/Start"
if [[ -f /var/log/pve/tasks/index ]]; then
  egrep -i "($VMID).*(qm (stop|shutdown|reset|start)|stop|shutdown|reset|start)" /var/log/pve/tasks/index | tail -n 300 || true
else
  echo "Kein Task-Index gefunden: /var/log/pve/tasks/index"
fi

echo

echo "## 4) journalctl: qemu/vm/shutdown/stop/reset/watchdog/oom"
journalctl --since "$SINCE" --no-pager \
  | egrep -i "(qemu|kvm|pvedaemon|pveproxy|vm|${VMID}|shutdown|poweroff|stop|reset|watchdog|oom|out of memory|killed process)" \
  | tail -n 400 || true

echo

echo "## 5) Kernel-Log: OOM-Killer / I/O Errors / watchdog"
journalctl -k --since "$SINCE" --no-pager \
  | egrep -i "(oom|out of memory|killed process|qemu|${VMID}|i/o error|blk|ext4|xfs|zfs|nvme|ata|watchdog|reset)" \
  | tail -n 400 || true

echo

echo "## 6) Reboots des Hosts"
last -x | head -n 30 || true

echo

echo "== Ende =="

Was macht das Skript?

Ein paar interessante Bestandteile:

set -euo pipefail sorgt dafür, dass das Skript sauber arbeitet:

  • -e beendet das Skript bei Fehlern
  • -u verhindert die Nutzung nicht gesetzter Variablen
  • pipefail sorgt dafür, dass Fehler in Pipes erkannt werden

VMID=111 definiert die VM, die untersucht werden soll. In meinem Fall war das die ioBroker-VM.

SINCE="${1:-3 days ago}" erlaubt optional einen Zeitraum beim Start des Skripts. Ohne Parameter werden automatisch die letzten drei Tage durchsucht.

Die einzelnen Blöcke sammeln dann gezielt Informationen:

  1. VM-Status und Konfiguration über qm status und qm config
  2. QEMU-Logdatei der VM
  3. Proxmox Task-Historie, um manuelle Stop/Start-Aktionen zu erkennen
  4. System-Journal, um Ereignisse rund um qemu, shutdown oder OOM zu finden
  5. Kernel-Logs, in denen der OOM-Killer normalerweise sehr deutlich auftaucht
  6. Host-Reboots, die ebenfalls erklären können, warum eine VM plötzlich weg ist

Damit bekommt man eine kompakte Forensik-Ausgabe, ohne sich durch mehrere Logdateien kämpfen zu müssen. Falls du dir für solche Wartungsarbeiten ohnehin noch ein bisschen Infrastruktur gönnen willst, sind USB-Sticks für Boot- oder Rettungsmedien (bezahlter Link) oder zusätzliche SSDs für Backups und Migrationen (bezahlter Link) im Homelab oft sinnvoller als der zehnte spontane Adapterkauf aus einer nächtlichen „das könnte man bestimmt mal brauchen“-Laune.


Fazit

Der OOM-Killer ist kein Fehler, sondern eine Schutzfunktion des Linux-Kernels.

Er sorgt dafür, dass ein System unter extremem Speicherdruck nicht komplett abstürzt.

Problematisch wird es erst, wenn er die falschen Prozesse erwischt.

Mit ein paar einfachen Schritten lässt sich das Verhalten deutlich verbessern:

  • Logs prüfen
  • RAM-Auslastung analysieren
  • wichtige VMs priorisieren
  • bei Bedarf Hookscripts nutzen
  • und im Zweifel schlicht aufrüsten

Und manchmal ist die simpelste Lösung tatsächlich die beste:

Mehr RAM.

Seit dem Upgrade auf 32 GB bleibt bei mir jedenfalls das Licht an.


Weitere Artikel rund um Proxmox und Homelab

Wenn du dich generell mit Proxmox im Homelab beschäftigst, könnten auch einige meiner anderen Beiträge interessant für dich sein. In meiner Proxmox Anleitung zeige ich die grundlegenden Schritte für Installation und erste Einrichtung eines eigenen Virtualisierungshosts. Wenn du Storage mit ZFS nutzt, lohnt sich außerdem ein Blick in den Artikel über das Verschieben von Proxmox-VMs und Containern auf ein ZFS-Mirror-Storage, in dem ich erkläre, wie man laufende Systeme sauber auf neuen Speicher umzieht.

Auch das Thema Backup spielt im Homelab eine große Rolle. In meinem Beitrag über den Proxmox Backup Server im Homelab beschreibe ich, wie ich mein Setup endlich vernünftig abgesichert habe und welche Vorteile ein dedizierter Backup-Server bringt. Falls du eher nach praktischen Anwendungsbeispielen suchst, findest du im Artikel zur Installation eines Teamspeak-Servers unter Proxmox eine komplette Schritt-für-Schritt-Anleitung für eine typische VM im Homelab.

Alle diese Artikel zeigen unterschiedliche Aspekte eines eigenen Virtualisierungsservers – von Storage über Backups bis zu praktischen Diensten, die auf einem Proxmox-Host laufen können.

* Affiliate-Link: Wenn du über so einen Link etwas kaufst, erhalte ich unter Umständen eine kleine Provision. Für dich ändert sich am Preis nichts.

Schreibe einen Kommentar