⚡ HomelabVergleich

Docker-Container vs. VM: Wann welcher Virtualisierungstyp das Richtige ist

Die häufigste Frage in Homelab-Forums und bei BsN-Beratungsgesprächen klingt so: „Soll ich das in Docker oder in einer VM machen?" Die Frage beruht auf einem grundlegenden Irrtum: Container und VMs seien austauschbare Begriffe für dasselbe Prinzip. Sie sind es nicht.

Ein Container teilt sich den Kernel des Host-Systems und virtualisiert nur die Userspace-Umgebung – Bibliotheken, Dateisystem, Prozessisolation. Eine Virtuelle Maschine virtualisiert die gesamte Hardware, inklusive eigenem Kernel und eigenem Betriebssystem. Das ist der wichtigste Unterschied, und er bestimmt fast alle nachfolgenden Praktikabilitätsfragen.

Vergleichstabelle

| Kriterium | Docker-Container | Virtuelle Maschine |

|---|---|---|

| Isolation | Prozess- und Dateisystemebene; selber Kernel wie Host | Vollständige Hardware-Isolation; eigener Kernel; gegenseitige Beeinflussung praktisch unmöglich |

| Speicherbedarf (Idle) | Einige Megabyte (Basis-Image); oft < 100 MB pro Container | 1–4 GB je VM (OS-Image, zugewiesener RAM, Swap) |

| Startzeit | Sekunden (Prozessstart) | Minuten (OS-Boot, Services starten) |

| Backup | docker commit / Volume-Snapshots / Compose-Dateien als Code | VM-Image-Snapshot (z.B. Proxmox qm backup, vzdump) oder ganze Platte |

| GUI-Programme | Nur indirekt (X11/VDI-Forwarding möglich, aber umständlich) | Direkt, vollständiges grafisches OS |

| Hardware-Durchreichen | Möglich für GPU (--gpus), USB (linuxserver/letsencrypt bypass) und Netzwerk, aber Host-Kernel-abhängig | Einfacher: PCI/USB/Netzwerk passthrough in Hypervisor config (Proxmox: qm set --hostpci0, usb0) |

| Sicherheitsrisiko | Kernel-Shared = Kernel-Exploit betrifft alle Container; kein eigener Kernel-Schutz | Geringeres Risiko; Kernel-Isolierung; bei gehackter VM bleibt Host normalerweise unberührt |

Entscheidungshilfe: Die Regelform

In einen Container gehört …

1. Dienste ohne GUI, die nur TCP/HTTP/Liste socken – Webserver, Datenbanken, Messaging (PostgreSQL, Redis, MQTT, Nextcloud, Vaultwarden). Beispiel: docker run -d -p 80:80 nginx.

2. Stateless- oder leicht stateful-Dienste, deren Daten auf Volumes ausgelagert sind: docker compose mit volumes: Block und einem definierten docker-entrypoint.sh. Das Backup-Szenario ist dann meist ein Volume-Snapshot oder ein docker cp.

3. Apps, die einen spezifischen Linux-Kernel nicht brauchen – also Python/Node/Java-Apps, die auf einem aktuellen Debian- oder Alpine-Kernel laufen würden, gleich wie der Host.

4. Skalierbare, replizierbare Dienste, bei denen man ohnehin mehrere Instanzen starten will: Docker Compose oder Kubernetes-ähnliche Orchestrierung ist der natürliche Rahmen.

Konkretes Signal: Wenn du eine Dockerfile schreiben kannst, die nur Pakete installiert, einen Binärstart ausführt und Ports expose – der Dienst gehört fast immer in einen Container.

Auf eine VM gehört …

1. Anwendungen, die ein eigenes, festes Betriebssystem voraussetzen – Windows-Server, ältere Linux-Versionen mit anderem Kernel als dem Host, BSD.

2. Dienste, die Hardware-Durchreichen in der Hypervisor-Sprache voraussetzen – z.B. eine VM mit direkt zugewiesenem GPU-PCI, einer IDE/SATA-Platte oder einem USB-Schnittstellen-Gerät, das der Host-Kernel nicht selbst behandeln soll. In Proxmox: qm set <VMID> --hostpci0 <PCI-Addr> oder USB-Add: qm set <VMID> --usb0 host=....

3. Sicherheitskritische, isolierte Dienste, bei denen ein gemeinsamer Kernel ein unakzeptables Risiko ist – z.B. ein öffentlich zugängener Dienst auf einem Multi-Tenant-Host, oder Testumgebungen für Kernel-Exploits.

4. Anwendungen, die Bare-Metal-nahe Performance für I/O brauchen und deren Container-Laufzeitumgebung zu viel Overhead oder zu viele Kernel-Abhängigkeiten einführt.

Konkretes Signal: Wenn du ein ISO-Image mounten, einen eigenen Kernel booten oder Geräte von der VM aus mit eigenen Treibern initialisieren willst – das ist eine VM.

Auf den Bare Metal (Host ohne Container, ohne VM) gehört …

Sonderfälle, bei denen die Regeln nicht greifen

GPU-Container

Ein Container, der eine GPU benötigt (Machine-Learning, transcodes, Rendering), ist eigentlich ein Container – aber mit Hardware-Passthrough: docker run --gpus all ... (NVidia Runtime) oder --device /dev/dri/renderD128 für VA-API. Das funktioniert nur, wenn der Host-Kernel die GPU als Device bereitstellt und kein Kernel-Modul (wie vfio-pci) sie bereits für eine VM eingesogen hat. Bei einer FC-Passthrough (Full Container) mit GPU und einem gleichzeitigen GPU-Passthrough für eine VM entsteht ein Konflikt: GPU kann nur einem Gast zur Zeit zugeordnet sein. Entscheidungshilfe: ML-Inference im Container (kürzere Laufzeiten), dedizierte GPU-Workloads (Training) eher VM, wenn auch andere Hardware-Isolierungen nötig sind.

USB-Durchreichen an Container

Manche Container wollen physische USB-Geräte (Zwingend z.B. für bestimmte Praxissysteme): docker run --device /dev/bus/usb/001/002 .... Das setzt voraus, dass der Host-Kernel das Gerät wie gewünscht sieht und dass udev-Regeln auf dem Host keine Konflikte verursachen. Bei komplexen USB-Geräten, die eigene Kernel-Treiber brauchen, ist eine VM mit USB-Passthrough (qm set --usb0 host=...) oft zuverlässiger.

Windows-Dienste

Windows-Dienste laufen in Docker-Containern nur eingeschränkt (Windows-Container etabliert, aber meist Windows-Server-Hosts nötig, selten im Homelab). Die Praxisentscheidung: Eine Windows-Dienst-App gehört in eine Windows-VM. Docker-Container mit Wine sind eine Grauzone und für produktive Dienste nicht empfehlenswert.

Docker-Desktop-Anwendungen auf einem Windows-PC

Docker Desktop auf Windows nutzt eine eingebettete Hyper-V-VM (WSL2 oder hyperv daemons). Du hast dort drei Schichten: Windows-Host → Docker Desktop VM (Hyper-V/WSL2) → Container. Bei Problemen mit Volume-Mounts oder Netzwerk: oft liegt es an der VM-Schicht, nicht am Container. Ein Port, der von außen nicht erreichbar ist, ist häufig ein WSL2-NAT-Problem (Windows-Subnetz 172.16.0.0/12, forwarding aus WSL2 heraus muss explizit gestattet sein).

LXC und Docker: Verwirrend ähnlich, aber unterschiedliche Garantien

Proxmox VE bringt LXC (Linux Containers) nativ mit. LXC ist ein Container-ähnliches System, das auf dem selben physikalischen Kernel läuft wie Docker (beide nutzen Linux Namespaces und cgroups). Wo sie sich unterscheiden:

Die Sicherheitsgarantie ist unterschiedlich: Ein privilegierter LXC-Container (pct unprivileged 0) teilt sich mehr Kernel-Fähigkeiten als ein Standard-Docker-Container. Ein unprivilegierter LXC-Container plus User-Namespaces ist ähnlich sicher wie Docker mit Rootless-Modus. Für reine Diensteroberflächen im Homelab sind LXC und Docker oft austauschbar; bei Bedarf an einem eigenen init-Prozess oder einem Init-System im Container ist LXC natürlicher.

Kurz: LXC ist das Werkzeug, wenn du einen ganzen (minimalen) Linux-Dienst im Container haben willst; Docker ist das Werkzeug, wenn du eine einzelne Anwendung mit definiertem Lebenszyklus willst.

FAQ

F1: Kann ich nicht einfach alles in Docker legen, um Ressourcen zu sparen?

Nein, nicht wenn der Dienst ein eigenes Kernel-Verhalten oder gerätespezifische Initialisierung braucht. Ein VM-basierter Dienst mit eigenem Kernel und eigenem Treiber-Einsatz ist nicht durch einen Container ersetzbar, ohne die Anforderungen zu verlieren. Ressourcensparnis ist ein Argument, nicht das einzige Argument.

F2: Ist Proxmox mit LXC und Docker gleichzeitig sinnvoll?

Ja. Typisches Setup: Proxmox-Host (Bare Metal) → VM für Windows oder GUI-Dienste → innerhalb einer Linux-VM (oder direkt auf dem Proxmox-Host-LXC-Container) Docker für die Diensteebene. Oder: LXC für leichte System-Container, Docker für die Anwendungs-Container auf demselben Host. Mix und Match nach den Regeln oben.

F3: Was ist das Sicherheitsrisiko, wenn ein Container gehackt wird?

Das Ausmaß hängt vom Container-Typ und von den Kernel-Fähigkeiten ab. Ein root-fähiger Docker-Container mit --privileged hat effektiv root auf dem Host – bei einem Kernel-Exploit ist der ganze Host betroffen. Ein unprivilegierter Container ohne Devices und ohne --privileged begrenzt die Schadensfläche, aber ein Kernel-Exploit im Container kann theoretisch den Host kompromittieren, weil beide denselben Kernel nutzen. Eine VM mit eigener Kernel-Isolierung begrenzt den Schaden auf die VM.

F4: Welches Backup soll ich wählen – Volume oder VM-Snapshot?

Container-Backup = Volumes kopieren (docker volume inspect zeigt den Pfad; dann rsync oder Snapshot des Host-Dateisystems) plus Compose-Konfigurationsdatei als Code sichern. VM-Backup = ganze VM-Snapshot/Backup (qm backup <VMID> <backup-storage>). Wenn du beides nutzt, sind die VM-Backups oft einfacher zu verwenden und wiederherzustellen (einheitlicher Mechanismus); Container-Backups sind im Detail genauer (nur die Daten, nicht das gesamte OS-Image). Praxis: beide parallel, je nach Wichtigkeit.


Hinweis: Konrad Konfigurationsdetails (PCI-Adressen, USB-IDs, prompte Pfade) sind jeweils systemabhängig; Beispiele zeigen Syntax. Dokumentation für Treiber und Geräte: lspci -nn, lsusb, docker volume inspect, pct config auf dem Proxmox-Host.

Hinweis: Dieser Artikel ist redaktioneller Inhalt und enthält keine Affiliate- oder Partner-Links. Alle Angaben entsprechen dem Stand 2026 und können sich ändern.