LXC: Lightweight-Virtualisierung als Docker-Alternative
$
/etc
Linux · LXC · LXD · Systemcontainer
LXC: Lightweight-Virtualisierung als Docker-Alternative
Vollständige Systemumgebungen statt einzelner Prozesse

LXC bietet echte Systemcontainer mit vollständigem Userspace, eigenem Init-System und mehreren parallelen Diensten, während Docker einen einzelnen Anwendungsprozess kapselt. Für Admins, die eine leichtgewichtige Alternative zu virtuellen Maschinen suchen, liefert der LXD-Workflow von Installation über Netzwerk und Storage bis zu Snapshots eine praxisnahe Grundlage für produktive Umgebungen, in denen ein vollwertiges Betriebssystem statt eines einzelnen Prozesses benötigt wird.

16 Min. Lesezeit LXC · LXD · System-Container · Namespaces Ubuntu 24.04 · Debian 12 · ZFS

1. Was LXC ist und warum es anders tickt als Docker

LXC (Linux Containers) ist die älteste produktionsreife Container-Technologie unter Linux, entstanden 2008, lange bevor Docker existierte. LXC nutzt exakt dieselben Kernel-Mechanismen wie Docker: Namespaces (PID, Network, Mount, UTS, IPC, User) und Control Groups (cgroups) zur Ressourcenbegrenzung. Der fundamentale Unterschied liegt nicht in der Kernel-Technik, sondern im Designziel. Docker wurde entwickelt, um eine einzelne Anwendung reproduzierbar zu verpacken und auszuliefern. LXC wurde entwickelt, um ein komplettes Betriebssystem-Userspace leichtgewichtig zu isolieren, so wie man es von einer virtuellen Maschine kennt, nur ohne eigenen Kernel und ohne Hypervisor.

In der Praxis bedeutet das: Ein LXC-Container startet systemd (oder ein anderes Init-System) als PID 1, verwaltet darin mehrere Dienste parallel, hat einen eigenen SSH-Daemon, eigene Cronjobs und eigene Logrotation, genau wie ein physischer oder virtueller Server. Ein Docker-Container dagegen kapselt in der Regel genau einen Prozess. Endet dieser Prozess, endet der Container. Wer aus der Docker-Welt kommt und einen LXC-Container startet, ist oft überrascht, wie sehr sich das anfühlt wie ein SSH-Login auf einen frisch installierten Server, nicht wie ein docker exec in einen minimalen Anwendungscontainer.

2. System-Container vs. Application-Container

Der Unterschied zwischen System-Containern und Application-Containern zeigt sich am deutlichsten am Lebenszyklus und am Image-Konzept. Ein Docker-Image ist ein geschichtetes Dateisystem aus Anwendung, Laufzeitumgebung und Abhängigkeiten, das als unveränderliches Artefakt gebaut, versioniert und deployt wird. Updates bedeuten in der Regel: neues Image bauen, alten Container wegwerfen, neuen Container starten. Ein LXC- beziehungsweise LXD-Image ist dagegen ein vollständiges Root-Dateisystem einer Linux-Distribution, das man wie eine gewöhnliche Serverinstallation administriert: apt update, apt upgrade, Konfigurationsdateien anpassen, Dienste neu starten, alles direkt im laufenden Container.

Historisch gibt es zwei LXC-Ausprägungen: das klassische LXC mit den lxc-*-Kommandozeilenwerkzeugen und textbasierten Konfigurationsdateien, sowie LXD, der modernere Daemon von Canonical, der LXC als Backend nutzt, aber eine REST-API, eine einheitliche lxc-Kommandozeile und Cluster-Fähigkeiten hinzufügt. Für neue Projekte ist LXD heute der Standardweg, klassisches LXC findet man noch in älteren Setups oder wenn direkter Zugriff auf die Low-Level-Konfiguration nötig ist. Die folgende klassische Konfigurationsdatei zeigt, wie granular sich einzelne Namespaces und Ressourcenlimits pro Container definieren lassen.


# /var/lib/lxc/webserver/config: classic LXC container config
lxc.uts.name = webserver

# Rootfs and template origin
lxc.rootfs.path = dir:/var/lib/lxc/webserver/rootfs

# Network: veth pair attached to the host bridge
lxc.net.0.type = veth
lxc.net.0.link = lxcbr0
lxc.net.0.flags = up
lxc.net.0.hwaddr = 00:16:3e:xx:xx:xx

# Resource limits via cgroups
lxc.cgroup2.memory.max = 2G
lxc.cgroup2.cpu.max = 200000 100000

# Unprivileged container: map container UID/GID to unprivileged host range
lxc.idmap = u 0 100000 65536
lxc.idmap = g 0 100000 65536

# Apparmor confinement profile
lxc.apparmor.profile = generated

3. LXD installieren und initialisieren

LXD wird auf den meisten Distributionen über Snap oder das native Paketrepository installiert, unter Ubuntu ist es standardmäßig vorinstalliert oder per apt install snapd && snap install lxd verfügbar. Nach der Installation folgt der obligatorische Setup-Schritt lxd init, ein interaktiver Assistent, der Storage-Backend, Netzwerk-Bridge und Remote-API-Zugriff abfragt. Für Produktionsserver empfiehlt sich ZFS oder Btrfs als Storage-Backend, weil beide Copy-on-Write-Snapshots nativ unterstützen und Container-Klone in Sekunden statt Minuten erzeugen, ohne Daten vollständig zu kopieren.

Der nicht-interaktive Modus lxd init --auto eignet sich für Automatisierung mit Ansible oder Terraform, verwendet dann aber Standardwerte, die man in Konfigurationsmanagement-Skripten meist explizit überschreiben will. Nach der Initialisierung legt LXD automatisch die Bridge lxdbr0 an, über die neue Container per NAT ins Netzwerk gelangen. Ein Blick mit lxc network list und lxc storage list bestätigt, dass Netzwerk und Storage-Pool korrekt angelegt wurden, bevor der erste Container gestartet wird.


#!/usr/bin/env bash
# Install LXD and run a non-interactive initialization
sudo apt update
sudo apt install -y snapd
sudo snap install lxd

# Non-interactive init: ZFS storage pool + default bridge network
sudo lxd init --auto \
  --storage-backend=zfs \
  --storage-pool=default \
  --storage-create-loop=20 \
  --network-address=auto \
  --network-port=8443

# Verify the resulting network and storage configuration
lxc network list
lxc storage list

4. Der erste Container: lxc launch, exec, list

Der Befehl lxc launch lädt ein Image und startet sofort einen laufenden Container, in einem Schritt, was bei Docker den zwei getrennten Befehlen docker pull und docker run entspricht. Images referenziert man über Aliase wie ubuntu:24.04 oder images:debian/12, LXD lädt sie bei Bedarf automatisch aus dem konfigurierten Image-Server nach und cached sie lokal. lxc list zeigt danach alle Container mit Status, IPv4/IPv6-Adresse und verwendetem Image-Alias in einer übersichtlichen Tabelle, vergleichbar mit docker ps, aber mit mehr Netzwerkdetails direkt sichtbar.

Für den Zugriff auf einen laufenden Container dient lxc exec, das im Gegensatz zu docker exec keine spezielle Vorbereitung der Anwendung braucht, weil ohnehin eine vollständige Shell-Umgebung mit bash, systemctl und den gewohnten Linux-Werkzeugen vorhanden ist. lxc stop, lxc start und lxc delete verwalten den Lebenszyklus, wobei lxc delete standardmäßig nur gestoppte Container löscht, ein sinnvoller Schutz gegen versehentliches Löschen laufender Systeme. Mit dem Flag --force lässt sich dieser Schutz bei Bedarf gezielt umgehen.


# Launch a fresh Debian 12 system container
lxc launch images:debian/12 webserver

# List all containers with status, IP address and image alias
lxc list

# Open an interactive shell inside the running container
lxc exec webserver -- bash

# Inside the container: install and manage services like on a real server
apt update && apt install -y nginx
systemctl status nginx

# Lifecycle management from the host
lxc stop webserver
lxc start webserver
lxc delete webserver --force

5. Netzwerk: Bridges, Profile und Portweiterleitung

Frisch erstellte Container hängen automatisch an der Bridge lxdbr0 und erhalten per DHCP eine private IP-Adresse, die per NAT ins restliche Netzwerk übersetzt wird, genau wie beim Standard-Bridge-Netzwerk von Docker. Für Container, die im lokalen Netzwerk wie eigenständige physische Maschinen erscheinen sollen, bietet sich ein macvlan- oder bridged-Netzwerk-Device an, das dem Container eine eigene MAC-Adresse und eine IP-Adresse aus dem gleichen Subnetz wie der Host gibt. Das ist besonders praktisch, wenn ein Container einen eigenen DHCP-Eintrag im Router oder eine feste IP aus der internen DNS-Zone bekommen soll.

Portweiterleitung von einem Host-Port auf einen Container-Port funktioniert über ein proxy-Device, das LXD direkt verwaltet, ohne iptables-Regeln manuell pflegen zu müssen. Profile fassen wiederkehrende Konfiguration wie Netzwerk-Devices, Ressourcenlimits und Storage-Zuordnungen zusammen und lassen sich auf mehrere Container gleichzeitig anwenden, vergleichbar mit einem docker-compose-Service-Template, nur containerübergreifend wiederverwendbar. Ein Container kann mehrere Profile gleichzeitig referenzieren, wobei spätere Profile frühere Einstellungen überschreiben.


# lxc profile edit webserver-profile
config:
  limits.cpu: "2"
  limits.memory: 2GB
description: Profile for public-facing web containers
devices:
  eth0:
    name: eth0
    network: lxdbr0
    type: nic
  http-proxy:
    # Forward host port 8080 to container port 80 without manual iptables
    connect: tcp:127.0.0.1:80
    listen: tcp:0.0.0.0:8080
    type: proxy
  root:
    path: /
    pool: default
    type: disk
name: webserver-profile

6. Storage Pools: ZFS, Btrfs und Copy-on-Write

LXD abstrahiert Storage über Pools, die auf unterschiedlichen Backends basieren können: dir für das einfache Verzeichnis-Backend ohne Sonderfunktionen, sowie ZFS, Btrfs und LVM für Backends mit nativem Copy-on-Write. Der praktische Vorteil von ZFS zeigt sich beim Klonen: lxc copy erstellt aus einem bestehenden Container in Sekunden eine vollständige Kopie, weil nur die Metadaten der Snapshot-Referenz kopiert werden, nicht die eigentlichen Datenblöcke. Erst wenn der Klon Daten verändert, werden die betroffenen Blöcke tatsächlich dupliziert, ein klassisches Copy-on-Write-Verhalten.

Für unterschiedliche Workloads lassen sich mehrere Storage-Pools parallel betreiben, etwa ein schneller NVMe-basierter ZFS-Pool für Datenbank-Container und ein separater HDD-Pool für Archiv-Container mit selten geänderten Daten. Storage-Volumes lassen sich zusätzlich unabhängig von einzelnen Containern anlegen und als zusätzliche Disk-Devices in mehrere Container gleichzeitig einhängen, praktisch für gemeinsam genutzte Datenverzeichnisse zwischen mehreren Diensten, ohne den Umweg über Netzwerk-Shares wie NFS.


# Create a dedicated ZFS pool for LXD on a spare block device
sudo zpool create tank-lxd /dev/sdb
sudo lxc storage create fast-zfs zfs source=tank-lxd/lxd

# Launch a container on the new pool
lxc launch images:debian/12 db-server --storage fast-zfs

# Clone via copy-on-write: near-instant, only metadata is duplicated
lxc copy db-server db-server-staging

# Create a shared data volume and attach it to two containers
lxc storage volume create fast-zfs shared-data
lxc storage volume attach fast-zfs shared-data app1 /mnt/shared
lxc storage volume attach fast-zfs shared-data app2 /mnt/shared

7. Snapshots, Backups und Live-Migration

Snapshots in LXD sind durch das Copy-on-Write-Verhalten des Storage-Backends nahezu verzögerungsfrei. lxc snapshot erstellt einen konsistenten Zustand des kompletten Root-Dateisystems, lxc restore setzt den Container exakt auf diesen Zustand zurück, was sich hervorragend für riskante Updates eignet, etwa vor einem größeren Distributions-Upgrade oder einer Konfigurationsänderung, die sich als fehlerhaft herausstellen könnte. Docker kennt dieses Konzept in dieser Form nicht, weil Container dort als zustandslos gelten und Persistenz über externe Volumes gelöst wird.

Für die Migration zwischen Hosts bietet LXD lxc copy mit dem Ziel eines Remote-Servers, was den kompletten Container inklusive aller Snapshots über das Netzwerk überträgt, optional sogar live, während der Container weiterläuft. lxc export erzeugt zusätzlich ein portables Backup-Archiv im tar-Format, das sich unabhängig von LXD auf einem anderen System wieder importieren lässt. Für regelmäßige Backups kombiniert man lxc snapshot mit einem Cronjob und einer Aufbewahrungsrichtlinie, die alte Snapshots automatisch rotiert.

8. Sicherheit: Unprivileged Containers und Isolation

LXD startet Container standardmäßig als unprivileged, das heißt, Root im Container wird über einen User-Namespace auf einen unprivilegierten UID-Bereich auf dem Host abgebildet. Ein Prozess, der im Container mit UID 0 läuft, hat auf dem Host tatsächlich eine hohe, nicht privilegierte UID wie 100000, und selbst bei einem Container-Ausbruch über eine Kernel-Schwachstelle bleibt der Schaden auf dem Host stark eingeschränkt. Diese Standardeinstellung unterscheidet sich deutlich von älteren Docker-Setups, bei denen Root im Container oft auch auf dem Host Root ist, sofern kein User-Namespace-Remapping explizit konfiguriert wurde.

Zusätzlich isolieren AppArmor-Profile und Seccomp-Filter jeden Container standardmäßig, wodurch gefährliche Syscalls wie das Mounten von Host-Dateisystemen oder das Laden von Kernel-Modulen im Container blockiert werden. Für Workloads, die tatsächlich privilegierten Zugriff brauchen, etwa verschachtelte Container oder bestimmte VPN-Setups, lässt sich ein Container gezielt als privileged markieren, was aber die Isolationsgarantien deutlich reduziert und nur für vertrauenswürdige Workloads infrage kommt. Der Grundsatz bleibt: unprivileged als Standard, privileged nur mit expliziter Begründung.

9. Einsatzszenarien und Vergleich mit Docker

LXC eignet sich besonders für Szenarien, in denen ein vollständiger, VM-ähnlicher Systemzustand gebraucht wird, aber der Overhead einer echten virtuellen Maschine mit eigenem Kernel unerwünscht ist. Typische Einsatzfälle sind Testumgebungen, die exakt wie ein Produktionsserver mit mehreren Diensten, Cronjobs und einer eigenen systemd-Instanz aussehen sollen, isolierte Entwicklungsumgebungen pro Kunde oder Projekt, sowie das Nachbilden ganzer Legacy-Serverlandschaften auf einer einzigen physischen Maschine für Schulungen oder Migrationstests.

Auch als leichtgewichtiger Ersatz für klassische VMs auf Hetzner-, Proxmox- oder selbstverwalteten KVM-Hosts hat LXC seinen festen Platz, wenn mehrere isolierte Linux-Systeme auf einem Host laufen sollen, ohne für jedes System einen eigenen Kernel und den entsprechenden Speicher- und CPU-Overhead eines Hypervisors zu bezahlen. Docker bleibt dagegen die richtige Wahl für zustandslose, horizontal skalierbare Anwendungscontainer in CI/CD-Pipelines und Microservice-Architekturen, wo Reproduzierbarkeit und schnelle Neuerstellung wichtiger sind als ein vollständiger Systemzustand.


{
  "name": "webserver",
  "status": "Running",
  "type": "container",
  "architecture": "x86_64",
  "config": {
    "security.privileged": "false",
    "security.nesting": "false",
    "limits.cpu": "2",
    "limits.memory": "2GB"
  },
  "state": {
    "network": {
      "eth0": {
        "addresses": [
          { "family": "inet", "address": "10.98.14.22", "netmask": "24", "scope": "global" }
        ]
      }
    },
    "pid": 48213
  }
}
Anwendungsfall Docker (Application-Container) LXC (System-Container) Ausschlaggebender Faktor
Testumgebung mit mehreren Diensten mehrere Container + Compose nötig ein Container reicht aus Weniger Orchestrierungs-Overhead
Bestehende VM 1:1 nachbilden Dockerfile-Neuaufbau nötig verhält sich wie ein echter Server Kein Applikations-Refactoring
Zustandslose Microservices in CI/CD schnell, reproduzierbar ersetzbar Systemcontainer zu schwergewichtig Reproduzierbarkeit wichtiger als Zustand
Mehrere isolierte Linux-Systeme statt VMs kein eigenes Init/systemd volle systemd-Instanz pro Container VM-ähnliches Verhalten ohne Hypervisor
Horizontale Skalierung in Kubernetes natives Container-Runtime-Ziel kein natives Kubernetes-Backend Ökosystem-Kompatibilität

In der Praxis schließen sich beide Technologien nicht aus: Viele Teams betreiben LXC-Systemcontainer für langlebige Infrastrukturdienste wie Datenbanken, VPN-Gateways oder interne Entwicklungsserver, während dieselbe Infrastruktur parallel Docker für zustandslose Anwendungsdeployments nutzt. Die Entscheidung hängt letztlich davon ab, ob ein einzelner Prozess oder ein vollständiger Systemzustand isoliert werden soll.

Mironsoft

Container-Infrastruktur, Systemvirtualisierung und Server-Automatisierung

LXC-Systemcontainer produktionsreif einrichten?

Wir bauen LXD-Infrastruktur mit ZFS-Storage, sicherem Netzwerk-Setup und automatisierten Snapshots auf, migrieren bestehende VMs verlustfrei in Systemcontainer und richten unprivilegierte, gehärtete Umgebungen für produktive Workloads ein.

LXD-Infrastruktur-Setup

ZFS-Storage-Pools, Netzwerk-Bridges und Cluster-Konfiguration für mehrere Hosts

VM-zu-Container-Migration

Bestehende virtuelle Maschinen als System-Container nachbilden, ohne Anwendungen umzubauen

Sicherheits-Hardening

Unprivileged Containers, AppArmor-Profile und Snapshot-Backup-Strategien

10. Zusammenfassung

LXC löst ein anderes Problem als Docker, auch wenn beide auf denselben Kernel-Mechanismen aufbauen. Wo Docker einen einzelnen Anwendungsprozess reproduzierbar verpackt, isoliert LXC einen vollständigen Systemzustand mit eigenem Init-System, mehreren parallelen Diensten und einer Administration, die sich anfühlt wie bei einem echten Server. Der LXD-Workflow von Installation über lxc launch und Netzwerk-Profile bis zu ZFS-basierten Snapshots liefert dafür ein leichtgewichtiges, produktionstaugliches Fundament, ohne den Overhead eines vollständigen Hypervisors.

Für Testumgebungen, Legacy-Nachbildungen und den Ersatz klassischer VMs bleibt LXC die pragmatischere Wahl, während Docker seine Stärken in zustandslosen, horizontal skalierbaren Microservice-Architekturen ausspielt. Wer beide Technologien gezielt nach Anwendungsfall einsetzt, statt sich auf eine einzige Container-Philosophie festzulegen, nutzt die jeweiligen Stärken, ohne unnötige Kompromisse bei Isolation, Betriebsaufwand oder Ressourcenverbrauch einzugehen.

LXC als Docker-Alternative: Das Wichtigste auf einen Blick

System- vs. Application-Container

LXC isoliert ein vollständiges Betriebssystem mit eigenem Init-System, Docker kapselt genau einen Anwendungsprozess.

LXD-Workflow

lxd init, lxc launch, lxc exec und lxc list genügen für den kompletten Container-Lebenszyklus.

Storage & Snapshots

ZFS oder Btrfs liefern Copy-on-Write-Klone in Sekunden und nahezu verzögerungsfreie lxc snapshot-Backups.

Sicherheit

Unprivileged Containers mit User-Namespace-Remapping sind der sichere Standard, privileged nur mit Begründung.

11. FAQ: LXC als Docker-Alternative

1Was ist der Unterschied zwischen LXC und Docker?
Docker kapselt meist einen einzelnen Prozess in einem unveränderlichen Image. LXC isoliert einen vollständigen Betriebssystem-Userspace mit eigenem Init-System und mehreren parallelen Diensten.
2Ist LXC das gleiche wie eine virtuelle Maschine?
Nein. LXC-Container teilen sich den Host-Kernel über Namespaces und cgroups, eine VM bringt einen eigenen Kernel mit. LXC ist leichter, isoliert aber schwächer als eine VM.
3Was ist der Unterschied zwischen LXC und LXD?
LXC ist die Kernel-Container-Technologie. LXD ist der modernere Daemon von Canonical mit REST-API, einheitlicher Kommandozeile und Cluster-Funktionen.
4Kann ich Docker-Container in LXC ausführen?
Ja, mit aktivierter security.nesting-Option, allerdings mit zusätzlichem Konfigurationsaufwand und leicht reduzierter Isolation gegenüber Docker direkt auf dem Host.
5Sind LXC-Container sicher genug für Produktivsysteme?
Ja, mit unprivileged Containers, User-Namespace-Remapping, AppArmor und Seccomp, standardmäßig aktiv in LXD. Privileged Containers nur mit expliziter Begründung.
6Welche Storage-Backends unterstützt LXD?
Unter anderem dir, ZFS, Btrfs, LVM und Ceph. Für Produktion empfehlen sich ZFS oder Btrfs wegen nativem Copy-on-Write für schnelle Klone und Snapshots.
7Wie greife ich von außen auf einen LXC-Container zu?
Per proxy-Device für Portweiterleitung, per macvlan/bridged-Device für eine eigene LAN-IP, oder direkt mit lxc exec vom Host aus.
8Kann ich einen LXC-Container zwischen Servern migrieren?
Ja, mit lxc copy zu einem Remote-Server, optional live. lxc export erzeugt zusätzlich ein portables Backup-Archiv unabhängig von LXD.
9Läuft systemd in einem LXC-Container?
Ja, systemd läuft standardmäßig als PID 1 und verwaltet Dienste, Cronjobs und Logrotation wie auf einem physischen oder virtuellen Server.
10Wann sollte ich LXC statt Docker verwenden?
Bei vollständigem Systemzustand mit mehreren Diensten, etwa Testumgebungen, Legacy-Nachbildungen oder als leichtgewichtiger VM-Ersatz. Für zustandslose Apps bleibt Docker passender.