FreeBSD-Jails oder Docker-Container: Unterschiede
FreeBSD-Jails kapseln ein vollständiges Userland, Docker nutzt geschichtete Images aus einer Registry. Vergleichen Sie Software, Zustand, Netzwerk und Limits.
FreeBSD-Jails und Docker-Container in einem Absatz
FreeBSD-Jails und Docker-Container lösen dasselbe Problem auf zwei unterschiedliche Arten. Beide führen isolierte Userlands auf einem gemeinsam genutzten Kernel aus. Daher ist keines von beiden eine virtuelle Maschine. Der Unterschied liegt im Inhalt. Ein Docker-Container führt einen Prozess aus einem geschichteten Image aus, das Sie aus einer Registry geladen haben. Ein Jail enthält ein vollständiges FreeBSD-Userland: ein eigenes /etc, eigene rc-Startskripte, eine eigene pkg-Datenbank und beliebig viele Prozesse. Fast alle anderen Unterschiede auf dieser Seite ergeben sich daraus.
SSD Nodes bietet keine FreeBSD-Images an. Sie können auf dieser Plattform keinen FreeBSD-Server mieten. Der folgende Inhalt ist keine Installationsanleitung für eine Maschine, die Sie hier kaufen können. Es handelt sich um einen Vergleich zweier Isolationsmodelle. Er soll Ihnen zeigen, welches Modell ein Workload tatsächlich benötigt, und Ihnen ermöglichen, die Einrichtung eines FreeBSD-Teams nachzuvollziehen, ohne raten zu müssen.
Was ein Jail tatsächlich ist
Jails wurden mit FreeBSD 4.0 im März 2000 eingeführt. Damit sind sie älter als cgroups und ungefähr ein Jahrzehnt älter als Docker. Der Mechanismus besteht aus einem Kernel-Aufruf. jail(8) übernimmt einen Verzeichnisbaum und startet darin Prozesse mit einer zugeordneten Jail-ID. Der Kernel verweigert anschließend eine festgelegte Gruppe von Operationen für jeden Prozess mit dieser ID. Ein Prozess in einem Jail kann keine Prozesse außerhalb seines Jails sehen, keine Dateisysteme mounten oder unmounten, keine Kernel-Module laden und nicht an Netzwerkadressen binden, die dem Jail nicht zugewiesen wurden. Sie müssen keinen separaten Namespace-Typ erlernen. Es gibt auch keine Aktivierung einzelner Funktionen pro Feature. Die Einschränkungen gelten als Einheit und werden über Parameter in der Jail-Konfiguration angepasst.
Auf dem Host listet jls die laufenden Jails auf. jexec web sh öffnet eine Shell in dem Jail mit dem Namen web.
Sie erstellen ein Jail, indem Sie ein FreeBSD-Userspace in ein Verzeichnis legen. Das Basissystem übernimmt diesen Schritt für Sie:
sudo bsdinstall jail /usr/local/jails/containers/webDamit wird der Basissystem-Datensatz für Ihre Version abgerufen und die üblichen Schritte nach der Installation werden ausgeführt. Sie legen daher ein root-Passwort fest und wählen eine Zeitzone, genau wie bei einem neuen Server. Das Ergebnis ist eine FreeBSD-Installation in einem Verzeichnis. Anschließend beschreiben Sie sie in /etc/jail.conf:
web {
host.hostname = "web.example.internal";
path = "/usr/local/jails/containers/web";
ip4.addr = "10.0.0.10";
exec.start = "/bin/sh /etc/rc";
exec.stop = "/bin/sh /etc/rc.shutdown";
mount.devfs;
}Starten Sie das Jail und prüfen Sie es anschließend:
sudo service jail start web
jlsjls sollte nun web mit einer JID, seinem Hostnamen und seiner IP-Adresse auflisten. Wenn das Jail nicht angezeigt wird, führen Sie sudo jail -c web direkt aus. Der Befehl verwendet dieselbe Konfiguration im Vordergrund und gibt den Parameter aus, den er nicht akzeptieren konnte. Der Fehler bleibt dadurch nicht nur in der Serviceausgabe verborgen.
Die Zeile, die Sie zweimal lesen sollten, ist exec.start = "/bin/sh /etc/rc". Beim Start eines Jails wird das normale Boot-Skript von FreeBSD darin ausgeführt. Das Jail startet daher jeden Dienst, der in seinem eigenen /etc/rc.conf aktiviert ist. Ein Docker-Container hat dafür kein entsprechendes Gegenstück. Er führt den Entrypoint-Prozess des Images aus und wird beendet, sobald dieser Prozess endet.
Wie Sie Software beziehen: Images und Registries im Vergleich zu einer selbst befüllten Userland-Umgebung
Das ist der Unterschied, den Sie bereits am ersten Tag bemerken.
Bei Docker geben Sie die Software an und erhalten sie. docker pull nginx lädt ein geschichtetes, inhaltsadressiertes Image herunter, das jemand anderes erstellt und getestet hat. docker compose up -d startet es mit den eingebundenen Volumes und dem zugewiesenen Netzwerk. Die Registry ist das Produkt. Der größte Vorteil eines Docker-Workflows besteht darin, dass Tausende von Projekten funktionierende Images veröffentlichen. Dadurch wird Docker auf einem VPS auszuführen zu einer kurzen Aufgabe statt zu einem eigenen Projekt.
FreeBSD stellt keine standardmäßige öffentliche Registry für Jail-Images bereit. Sie erstellen eine leere Userland-Umgebung und installieren die Software darin, genauso wie Sie einen Bare-Metal-Server einrichten würden. Das erfordert mehr Eingaben. Es ist jedoch transparenter, weil in der Jail genau das läuft, was pkg dort installiert hat, und zwar aus demselben Paketsatz, den auch der Host verwendet.
Die Werkzeuge verkürzen diesen Prozess. BastilleBSD ist der gängige Jail-Manager und als Paket verfügbar:
sudo pkg install bastille
sudo sysrc bastille_enable=YES
sudo bastille setup
sudo bastille bootstrap 15.1-RELEASEbastille setup konfiguriert Netzwerk, Speicher und Firewall für Sie. bastille bootstrap lädt ein Release einmal herunter. Jede danach erstellte Jail verwendet es wieder. FreeBSD 15.1 ist das aktuelle Produktions-Release und wurde im Juni 2026 veröffentlicht. Ersetzen Sie es durch das Release, das Sie einsetzen.
Eine Jail zu erstellen ist anschließend ein einzelner Befehl. Sie zu befüllen ist ein weiterer:
sudo bastille create web 15.1-RELEASE 10.17.89.10/24
sudo bastille pkg web install nginx
sudo bastille service web nginx start
sudo bastille console webbastille console web öffnet eine Login-Shell innerhalb der Jail. bastille list zeigt, welche Dateien und Pakete auf dem Host vorhanden sind. Für wiederholbare Builds speichern Bastille-Templates die einzelnen Schritte in einer Datei und wenden sie auf eine Jail an. Das kommt in dieser Welt einem Dockerfile am nächsten. Ein Template wird auf jede Jail erneut angewendet. Nichts wird fertig installiert geliefert.
Die ehrliche Zusammenfassung ist daher kurz: Docker liefert Ihnen Builds anderer Personen. Jails liefern Ihnen Ihre eigenen Installationen. Wenn die Software auf Ihrer Auswahlliste als Container-Image und in keiner anderen Form verfügbar ist, ist die Frage damit entschieden, bevor andere Kriterien berücksichtigt werden.
Zustand und Upgrades: der Teil, den ZFS verändert
Docker trennt den Zustand absichtlich. Das Container-Dateisystem ist entbehrlich. Ihre Daten liegen in einem benannten Volume oder einem Bind-Mount. Ein Upgrade besteht aus docker compose pull gefolgt von docker compose up -d. Der Container wird ersetzt. Alles, was Sie nicht in einem Volume abgelegt haben, ist verloren. Das ist ein Vorteil, wenn Sie diese Regel befolgen. Wenn Sie sie vergessen, kommt es zu Datenverlust. Deshalb ist die Wahl zwischen Bind-Mounts und benannten Volumes in einem Compose-Stack so wichtig.
Ein Jail trennt den Zustand nicht. ZFS macht dieses Modell möglich. Das gesamte Jail ist ein Dataset:
sudo zfs snapshot zroot/jails/containers/web@pre-upgrade
sudo pkg -j web upgrade
sudo zfs rollback zroot/jails/containers/web@pre-upgradePrüfen Sie mit zfs list den tatsächlichen Dataset-Namen, bevor Sie diesen Befehl ausführen. Der oben gezeigte Pfad entspricht dem im Handbuch verwendeten Aufbau. Der Snapshot wird in etwa einer Sekunde erstellt und belegt fast keinen zusätzlichen Speicher, solange sich der Inhalt des Jails nicht ändert. Wenn das Upgrade den Dienst beschädigt, stellt der Rollback den gesamten Userland-Zustand wieder her. Dazu gehören auch die Paketdatenbank und die Konfigurationsdateien, die Sie um 2 Uhr morgens manuell bearbeitet haben. Docker bietet dafür kein integriertes Gegenstück. Sein Modell geht davon aus, dass Sie eine solche Funktion nie benötigen.
zfs clone ist die andere Hälfte. Ein Clone eines Snapshots ist ein neues beschreibbares Jail. Es verwendet unveränderte Blöcke gemeinsam mit dem übergeordneten Dataset. Deshalb belegt eine Staging-Kopie eines 3 GB großen Jails auf der Festplatte zunächst fast keinen zusätzlichen Speicher. Erst Änderungen führen zu zusätzlichem Speicherbedarf. So erstellt ein FreeBSD-Administrator ein Jail mit dem Zustand „identisch mit der Produktion“, um ein Upgrade zunächst zu testen.
Das Upgrade des Basissystems ist von den Paketen getrennt. Für ein Jail mit einer eigenen Kopie des Userland:
sudo freebsd-update -b /usr/local/jails/containers/web fetch installThin Jails vermeiden diese wiederholte Arbeit. Sie mounten über nullfs eine gemeinsame, schreibgeschützte Basis und geben jedem Jail eine eigene kleine beschreibbare Schicht. Dadurch patchen Sie die Basis einmal, und jedes Jail verwendet anschließend den aktualisierten Stand. Bastille erstellt standardmäßig Thin Jails.
Netzwerk: veröffentlichte Ports im Vergleich zu einer Adressierungsentscheidung
Docker legt die Netzwerkkonfiguration für Sie fest und verlangt, dass Sie Ausnahmen veröffentlichen. Container werden an ein Bridge-Netzwerk angeschlossen, erreichen sich in einem benutzerdefinierten Netzwerk über den Servicenamen, und -p 8080:80 macht einen davon für den Host erreichbar. Docker schreibt dafür eigene Paketfilterregeln. Auf diese Weise kann auch ein veröffentlichter Container-Port ufw direkt umgehen.
Bei einem Jail müssen Sie das Modell vorher festlegen. Es gibt zwei Modelle.
Gemeinsam genutzte IP-Adresse. ip4.addr = "10.0.0.10" fügt diese Adresse einer vorhandenen Host-Schnittstelle hinzu und beschränkt das Jail auf diese Adresse. Das Jail hat keinen eigenen Netzwerk-Stack und kann deshalb keine eigene Firewall ausführen. Es kann auch nicht tatsächlich an jede Adresse binden: Ein Jail-Socket, der 0.0.0.0 anfordert, wird vom Kernel auf die eigene Adresse des Jails umgeschrieben. Zwei Jails können nicht beide Port 80 auf derselben Adresse überwachen. Sie weisen daher jedem Jail eine eigene Adresse zu oder schalten einen Reverse Proxy davor.
VNET. Fügen Sie vnet; zum Jail hinzu. Dadurch erhält es einen vollständigen Netzwerk-Stack mit eigenen Schnittstellen, einer eigenen Routing-Tabelle und eigenen Firewall-Regeln. Sie verbinden es über ein epair mit dem Host. Dabei handelt es sich um ein virtuelles Kabel mit jeweils einem Ende auf jeder Seite. Das Host-Ende wird an eine Bridge angeschlossen. Dies entspricht am ehesten dem Netzwerkmodell von Docker und ist der Modus hinter Bastilles Jail-Typen -V und -B.
Das Weiterleiten eines Host-Ports an ein Jail erfolgt über eine pf-Redirect-Regel. Bastille kapselt diese Regel:
sudo bastille rdr web tcp 80 80Es gibt kein EXPOSE und keine automatische Veröffentlichung. Ein Jail ist nur erreichbar, wenn seine Adresse oder eine Redirect-Regel den Zugriff erlaubt. Der Startaufwand ist höher, dafür bleibt die Firewall deutlich ruhiger.
Ressourcenlimits: cgroups im Vergleich zu rctl
Docker begrenzt einen Container mit cgroups. Die Limits stehen dort, wo der Container definiert ist: --memory=1g --cpus=1.5 in der Befehlszeile oder die entsprechenden Schlüssel in einer Compose-Datei. Wenn Sie Ihren Stack bereits in einer Docker-Compose-Datei auf einem VPS verwalten, steht das Limit neben dem zugehörigen Dienst und wird zusammen mit ihm in git versioniert.
FreeBSD verwendet rctl. Dieses Subsystem müssen Sie zunächst aktivieren. Die Ressourcenabrechnung ist standardmäßig deaktiviert, weil sie bei jeder Speicherzuweisung einen geringen zusätzlichen Aufwand verursacht. Fügen Sie den Tuning-Parameter zu /boot/loader.conf hinzu und führen Sie einen Reboot durch:
kern.racct.enable=1Legen Sie anschließend eine Regel fest und überwachen Sie sie:
sudo rctl -a jail:web:vmemoryuse:deny=1g
rctl -hu jail:webrctl -hu jail:web gibt die aktuelle Nutzung des Jails in lesbaren Einheiten aus. So sehen Sie, wie nahe die Nutzung am Limit liegt, bevor ein Fehler auftritt. Die Aktion deny lässt eine Speicherzuweisung innerhalb des Jails fehlschlagen, sobald das Limit überschritten wird. Dadurch sehen Sie den eigenen Allokationsfehler der Anwendung statt einer Kill-Meldung auf dem Host.
Mit rctl -a hinzugefügte Regeln gehen beim nächsten Reboot verloren. Der FreeBSD-Dienst rctl lädt die Regeln aus /etc/rctl.conf neu. Schreiben Sie die Regel daher in diese Datei und aktivieren Sie den Dienst:
sudo sysrc rctl_enable=YESIn diesem Punkt ist Docker deutlich komfortabler. Ein Limit in einer Compose-Datei wird zusammen mit dem Dienst überprüft, für den es gilt. Eine rctl-Regel steht dagegen als Zeile in einer separaten Datei und verweist auf ein Jail, das an anderer Stelle definiert ist.
Wenn die Antwort eine virtuelle Maschine lautet: bhyve
Ein Jail verwendet den Kernel des Hosts gemeinsam mit dem Host. Daher bleiben bestimmte Funktionen grundsätzlich unerreichbar. Es kann keine andere Kernel-Version ausführen, kein Kernel-Modul laden und Linux-Binärdateien nicht so ausführen wie ein Linux-Container. FreeBSD verfügt über eine Linux-Kompatibilitätsschicht namens linuxulator. Sie implementiert jedoch nur eine Teilmenge der Linux-Systemaufrufe und ist keine allgemeine Lösung für beliebige Linux-Images.
bhyve ist der Hypervisor von FreeBSD. Es ist das richtige Werkzeug, wenn Sie eine echte Systemgrenze benötigen: ein anderes Betriebssystem, einen anderen Kernel oder einen Mandanten, mit dem Sie den Kernel nicht gemeinsam nutzen möchten. Dafür benötigen Sie zusätzlichen reservierten statt gemeinsam genutzten Arbeitsspeicher und müssen einen zweiten Kernel aktualisieren. Unter Linux treffen Sie dieselbe Entscheidung zwischen Containern und vollständigen virtuellen Maschinen. Sie entscheidet auch, ob Sie darunter einen VPS mit Unterstützung für verschachtelte Virtualisierung benötigen.
Das Ökosystem ist der wichtigste Grund, warum die meisten Teams Docker verwenden
Bei der bisherigen Betrachtung geht es um das Modell. Für die meisten Teams entscheidet jedoch die Größe des Umfelds, das jedes Modell mitbringt.
Docker bietet Docker Hub und GHCR, docker compose, Kubernetes, sobald ein einzelner Server nicht mehr ausreicht, sowie CI-Runner mit bereits eingerichteter Container-Unterstützung. Außerdem enthält die README fast jedes Projekts einen Quickstart mit einem einzigen Befehl. Jails bieten den FreeBSD-Ports-Tree, der umfangreich und sorgfältig gepflegt ist, sowie eine deutlich kleinere Auswahl an fertigen Anwendungspaketen. Wenn ein Projekt nur ein Container-Image und nichts anderes veröffentlicht, besteht der Weg mit FreeBSD darin, die Dokumentation zu lesen und die einzelnen Komponenten selbst zusammenzustellen.
Jails rechtfertigen sich auf der anderen Seite dieses Zielkonflikts. Sie sind sinnvoll, wenn Sie bereits ZFS einsetzen und Snapshots sowie Rollbacks eines vollständigen Dienstes benötigen, wenn Ihre Dienste nativ unter FreeBSD laufen, wenn Sie pro Mandant einen vollständigen Userland statt nur eines einzelnen Prozesses benötigen oder wenn Kernel, Paketfilter, Dateisystem und Dokumentation gemeinsam als ein System gepflegt werden sollen. Dieser letzte Punkt ist gemeint, wenn FreeBSD als kohärent bezeichnet wird. Er wird in dem umfassenderen Vergleich von Linux und FreeBSD als Serverplattformen und in den Änderungen von FreeBSD 15 für den Serverbetrieb ausführlicher behandelt.
Zum Abschluss eine Einschätzung. Wenn Ihr Team Docker bereits beherrscht, sind die Kosten eines Wechsels real, und der Nutzen muss konkret sein. Wechseln Sie nicht wegen einer besseren Isolation. Die beiden Modelle liegen nahe genug beieinander, dass Ihre Konfiguration wichtiger ist. Wechseln Sie, wenn Sie ZFS-gestützte Rollbacks vollständiger Dienste benötigen oder bereits FreeBSD einsetzen.
FAQ
Kann ich Docker-Images unter FreeBSD ausführen?
Nicht Linux-Images und nicht auf einem unterstützten Weg. FreeBSD unterstützt OCI-Container: sudo pkg install -y podman-suite installiert Podman. Podman führt Container über ocijail aus, eine Laufzeitumgebung, die darunter echte Jails erstellt. Für den Container-Monitor muss fdescfs unter /dev/fd eingehängt sein. Für das Container-NAT (Network Address Translation) wird pf benötigt. OCI-Images für FreeBSD funktionieren am zuverlässigsten. Linux-Images benötigen zusätzlich die Linux-Kompatibilitätsschicht. Im August 2026 wird der FreeBSD-Podman-Port weiterhin als experimentell beschrieben. Wenn Ihre Bereitstellung aus einem Stack von Linux-Images besteht, führen Sie ihn unter Linux aus.
Sind FreeBSD-Jails sicherer als Docker-Container?
Beide verwenden denselben Kernel des Hosts. Eine Kernel-Schwachstelle stellt daher für beide ein Risiko dar. Keines von beiden ist die geeignete Grenze für tatsächlich nicht vertrauenswürdigen Code. Der Unterschied liegt in der Ausgangskonfiguration. Ein Jail verweigert zunächst eine große Anzahl von Operationen. Sie aktivieren diese dann einzeln über Parameter wieder. Ein Docker-Container startet als root innerhalb einer Gruppe von Namespaces, wobei einige Capabilities entfernt wurden. Weitere Härtung müssen Sie ausdrücklich aktivieren. In der Praxis ist die Konfiguration wichtiger als das Modell: Ein Jail mit aktiviertem allow.mount und allow.raw_sockets ist nicht sicherer als ein sorgfältig konfigurierter Container.
Wie sichere ich ein Jail?
Erstellen Sie einen Snapshot des Datasets und übertragen Sie ihn. sudo zfs snapshot zroot/jails/containers/web@backup erstellt den Snapshot. Anschließend übertragen Sie ihn mit zfs send auf einen anderen Pool oder in eine Datei, die Sie vom Host kopieren. Da ein Jail sein gesamtes Userland in einem Dataset enthält, erfasst der Snapshot die installierten Pakete und die Daten zu einem einheitlichen Zeitpunkt. Er enthält außerdem jede Konfigurationsdatei, die Sie manuell bearbeitet haben. Das ist das Gegenteil der Docker-Praxis. Dort sichern Sie die benannten Volumes und die Compose-Datei und erstellen den übrigen Inhalt aus dem Image neu.
Benötige ich BastilleBSD, oder reicht das Basissystem aus?
Das Basissystem reicht aus und ist der bessere Ausgangspunkt. jail.conf, jls, jexec und service jail start decken das gesamte Modell ab. Wenn Sie diese Befehle kennen, können Sie jeden FreeBSD-Host verwalten, ohne zuerst dessen spezifische Werkzeuge lernen zu müssen. Bastille ist eine Komfortschicht darüber. Das Tool richtet Releases ein, erstellt Thin Jails, wendet Templates an und schreibt pf-Redirect-Regeln für Sie. Lernen Sie zuerst die Basisbefehle. Fügen Sie Bastille anschließend hinzu, wenn die Anzahl der Jails die manuelle Eingabe zu aufwendig macht.