FreeBSD-Jails vs. Docker-Container: Die Unterschiede
FreeBSD-Jails starten ein vollständiges Userland, Docker-Container einen Prozess aus einem geschichteten Registry-Image. Unterschiede bei Software, Zustand, Netzwerk und Limits.
FreeBSD-Jails vs. 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 gemeinsamen Kernel aus. Daher ist keines von beiden eine virtuelle Maschine. Der Unterschied liegt darin, was innerhalb der Isolation ausgeführt wird. Ein Docker-Container führt einen Prozess aus einem geschichteten Image aus, das Sie aus einer Registry geladen haben. Ein Jail führt ein vollständiges FreeBSD-Userland aus: mit eigenem /etc, eigenen rc-Startskripten, eigener pkg-Datenbank und beliebig vielen Prozessen. Fast jeder andere Unterschied auf dieser Seite ergibt sich aus diesem einen Punkt.
SSD Nodes bietet keine FreeBSD-Images an. Sie können auf dieser Plattform keinen FreeBSD-Server mieten. Der folgende Text 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 eine Workload tatsächlich benötigt, und Ihnen ermöglichen, die Konfiguration eines FreeBSD-Teams zu verstehen, ohne raten zu müssen.
Was ein Jail tatsächlich ist
Jails wurden im März 2000 mit FreeBSD 4.0 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 zugewiesenen 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. Er kann keine Dateisysteme mounten oder aushängen, keine Kernel-Module laden und nicht an Netzwerkadressen binden, die dem Jail nicht zugewiesen wurden. Es gibt keinen separaten Namespace-Typ, den Sie erlernen müssen, und keine Funktion, die Sie einzeln aktivieren müssen. Die Einschränkungen werden als Einheit angewendet und über Parameter in der Jail-Konfiguration angepasst.
Auf dem Host listet jls die laufenden Jails auf. Mit jexec web sh öffnen Sie eine Shell in dem Jail mit dem Namen web.
Sie erstellen ein Jail, indem Sie ein FreeBSD-Userland in ein Verzeichnis legen. Das Basissystem übernimmt diesen Schritt für Sie:
sudo bsdinstall jail /usr/local/jails/containers/webDer Befehl lädt das Basis-Distributionsset für Ihr Release und führt die meisten üblichen Schritte nach der Installation aus. Sie legen daher ein root-Passwort fest, wählen Dienste aus und fügen Benutzer hinzu, wie bei einem neuen Server. Nach einer Zeitzone werden Sie nicht gefragt. Das Installationsprogramm kopiert /etc/localtime des Hosts in das Jail. Das Jail übernimmt daher die Zeitzone des Hosts. 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 jetzt 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. Dadurch bleibt der Fehler nicht nur in der Dienstausgabe 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 seiner eigenen /etc/rc.conf aktiviert ist. Für einen Docker-Container gibt es keinen entsprechenden Schritt. Er führt den Entrypoint-Prozess des Images aus und wird beendet, sobald dieser Prozess beendet wird.
Wie Sie Software erhalten: Images und Registries im Vergleich zu einem selbst befüllten Userland
Diesen Unterschied bemerken Sie bereits am ersten Tag.
Bei Docker geben Sie den Namen der Software an und erhalten sie. docker pull nginx ruft ein geschichtetes, inhaltsadressiertes Image ab, das jemand anderes erstellt und getestet hat, und docker compose up -d startet es mit seinen eingebundenen Volumes und seinem verbundenen Netzwerk. Die Registry ist das Produkt. Der größte Teil des Nutzens eines Docker-Workflows besteht darin, dass Tausende Projekte ein funktionierendes Image veröffentlichen. Dadurch wird Docker auf einem VPS auszuführen zu einer kurzen Aufgabe statt zu einem eigenen Projekt.
FreeBSD liefert keine standardmäßige öffentliche Registry für Jail-Images aus. Sie erstellen ein leeres Userland 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 derselben Paketquelle, die auch der Host verwendet.
Die Werkzeuge verkürzen den Vorgang. BastilleBSD ist der verbreitete Jail-Manager und ein Paket:
sudo pkg install bastille
sudo sysrc bastille_enable=YES
sudo bastille setup
sudo bastille bootstrap 15.1-RELEASEbastille setup konfiguriert das Netzwerk, den Speicher und die Firewall für Sie. bastille bootstrap lädt ein Release einmal herunter. Jede danach erstellte Jail verwendet dieses Release erneut. 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 dann ein Befehl. Sie zu befüllen, erfordert einen weiteren:
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, was auf dem Host vorhanden ist. Für reproduzierbare Builds enthalten Bastille-Templates die einzelnen Schritte in einer Datei und wenden sie auf eine Jail an. Das kommt einem Dockerfile in dieser Umgebung am nächsten. Ein Template wird auf jede Jail erneut angewendet. Nichts wird fertig vorkonfiguriert bereitgestellt.
Die kurze, sachliche Zusammenfassung lautet daher: Docker stellt Builds anderer Personen bereit. Jails enthalten Ihre eigenen Installationen. Wenn die Software auf Ihrer Auswahlliste als Container-Image und in keiner anderen Form ausgeliefert wird, ist die Frage bereits entschieden, bevor andere Kriterien berücksichtigt werden.
Status und Upgrades: der Teil, den ZFS verändert
Docker trennt den Status absichtlich. Das Container-Dateisystem ist wegwerfbar. 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 danach weg. Das ist ein Vorteil, wenn Sie diese Regel einhalten, und ein Datenverlustvorfall, wenn Sie sie vergessen. Deshalb ist die Wahl zwischen Bind-Mounts und benannten Volumes in einem Compose-Stack so wichtig.
Ein Jail trennt den Status 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 den tatsächlichen Dataset-Namen mit zfs list, bevor Sie diesen Befehl ausführen. Der Pfad oben entspricht dem Layout im Handbuch. Der Snapshot ist nach ungefähr einer Sekunde erstellt und benötigt 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-Bestand auf den vorherigen Stand zurück. Das umfasst auch die Paketdatenbank und die Konfigurationsdateien, die Sie um 2am manuell bearbeitet haben. Docker bietet dafür kein integriertes Gegenstück, weil sein Modell davon ausgeht, dass Sie keinen solchen Mechanismus benötigen.
zfs clone ist die andere Hälfte. Ein Clone eines Snapshots ist ein neues beschreibbares Jail, das unveränderte Blöcke mit seinem übergeordneten Dataset teilt. Eine Staging-Kopie eines 3 GB großen Jails benötigt daher auf dem Datenträger fast keinen zusätzlichen Speicher, bis Sie Änderungen vornehmen. So erstellt ein FreeBSD-Administrator ein Jail mit dem Zustand „wie in der Produktion“, um ein Upgrade zu testen.
Das Upgrade des Basissystems ist von den Paketen getrennt. Für ein Jail, das eine eigene Kopie des Userlands enthält:
sudo freebsd-update -b /usr/local/jails/containers/web fetch installThin Jails vermeiden diese Arbeit. Sie mounten eine gemeinsame schreibgeschützte Basis über nullfs und erhalten jeweils eine eigene kleine beschreibbare Schicht. Dadurch patchen Sie die Basis einmal, und jedes Jail sieht das Ergebnis. Bastille erstellt standardmäßig Thin Jails.
Netzwerk: veröffentlichte Ports gegenüber einer Adressierungsentscheidung
Docker legt die Netzwerkkonfiguration für Sie fest und fordert Sie auf, Ausnahmen zu veröffentlichen. Container werden mit einer Bridge verbunden, erreichen sich in einem benutzerdefinierten Netzwerk über den Dienstnamen, und -p 8080:80 stellt einen von ihnen für den Host bereit. Docker schreibt eigene Paketfilterregeln, damit das funktioniert. Auf diese Weise umgeht auch ein veröffentlichter Container-Port ufw direkt.
Bei einem Jail müssen Sie das Modell im Voraus auswählen. Es gibt zwei Modelle.
Gemeinsame IP-Adresse. ip4.addr = "10.0.0.10" beschränkt das Jail auf diese Adresse. Allein dadurch werden die Interfaces des Hosts nicht verändert. Die Adresse muss daher bereits auf einem dieser Interfaces konfiguriert sein. Damit jail(8) die Adresse beim Erstellen des Jails als Alias hinzufügt, geben Sie das Interface an: Setzen Sie interface = "em0"; im Block des Jails oder stellen Sie es der Adresse als ip4.addr = "em0|10.0.0.10"; voran. Das Jail besitzt keinen eigenen Netzwerk-Stack und kann daher keine eigene Firewall betreiben. Es kann außerdem nicht tatsächlich an jede Adresse gebunden werden: 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 an derselben Adresse überwachen. Sie müssen daher jedem Jail eine eigene Adresse geben oder einen Reverse Proxy davorschalten.
VNET. Fügen Sie dem Jail vnet; hinzu. Dadurch erhält es einen vollständigen Netzwerk-Stack mit eigenen Interfaces, 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 je einem Ende auf beiden Seiten. Das Host-Ende wird an eine Bridge angeschlossen. Dies entspricht am ehesten der Netzwerkkonfiguration von Docker und ist der Modus hinter den Bastille-Jail-Typen -V und -B.
Das Weiterleiten eines Host-Ports in ein Jail erfolgt über eine pf-Redirect-Regel. Bastille kapselt diese Funktion:
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 dies zulässt. Der Start ist dadurch aufwendiger, die Firewall bleibt jedoch deutlich übersichtlicher.
Ressourcenlimits: cgroups gegenüber rctl
Docker begrenzt einen Container mit cgroups. Die Limits werden dort festgelegt, wo der Container definiert ist: über --memory=1g --cpus=1.5 in der Befehlszeile oder über 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 Dienst, für den es gilt, und wird zusammen mit ihm in git versioniert.
FreeBSD verwendet rctl. Dieses Subsystem müssen Sie zunächst aktivieren. Der GENERIC-Kernel kompiliert die Ressourcenabrechnung zwar ein, liefert sie aber über die Kernel-Option RACCT_DEFAULT_TO_DISABLED deaktiviert aus. Fügen Sie den Tunable zu /boot/loader.conf hinzu und starten Sie das System neu:
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 Auslastung des Jails in menschenlesbaren Einheiten aus. So sehen Sie, wie nahe das Jail dem Limit bereits kommt, bevor ein Fehler auftritt. Die Aktion deny lässt eine Allokation innerhalb des Jails fehlschlagen, sobald das Limit überschritten wird. Dadurch sehen Sie den eigenen Allokationsfehler der Anwendung und keine 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 erneut. Schreiben Sie die Regel daher in diese Datei und aktivieren Sie den Dienst:
sudo sysrc rctl_enable=YESIn diesem Punkt ist Docker eindeutig komfortabler. Ein Limit in einer Compose-Datei wird zusammen mit dem Dienst geprüft, den es begrenzt. Eine rctl-Regel ist dagegen eine Zeile in einer separaten Datei und verweist auf ein Jail, das an anderer Stelle definiert ist.
Wenn die Antwort eine virtuelle Maschine ist: bhyve
Ein Jail verwendet den Kernel des Hosts gemeinsam. Daher sind einige Funktionen dauerhaft nicht verfügbar. Es kann keine andere Kernelversion ausführen, kein Kernelmodul laden und keine Linux-Binärdateien wie ein Linux-Container ausführen. FreeBSD verfügt mit dem linuxulator über eine Linux-Kompatibilitätsschicht. Diese 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. Er ist das geeignete Werkzeug, wenn Sie eine echte Maschinengrenze benötigen: ein anderes Betriebssystem, einen anderen Kernel oder einen Mandanten, mit dem Sie den Kernel nicht gemeinsam verwenden möchten. Dafür benötigen Sie reservierten statt gemeinsam genutztem Arbeitsspeicher und müssen einen zweiten Kernel patchen. Diese Entscheidung entspricht der Wahl zwischen Containern und vollständigen virtuellen Maschinen unter Linux. Sie bestimmt auch, ob Sie darunter einen VPS mit Unterstützung für verschachtelte Virtualisierung benötigen.
Das Ökosystem als eigentlicher Grund, warum die meisten Teams Docker verwenden
Bisher ging es um das Modell. Für die meisten Teams entscheidet jedoch der Umfang des Ökosystems rund um die jeweilige Technologie.
Docker bietet Docker Hub und GHCR, docker compose, Kubernetes, sobald ein einzelner Rechner nicht mehr ausreicht, CI-Runner mit bereits eingerichteter Container-Unterstützung und in fast jeder README eines Projekts einen Schnellstart mit einem einzigen Befehl. Jails bieten den FreeBSD-Ports-Tree, der umfangreich und sorgfältig gepflegt ist, sowie eine deutlich kleinere Auswahl an sofort einsetzbaren 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 benötigten Komponenten selbst zusammenzustellen.
Jails sind die andere Seite dieses Kompromisses. Sie sind sinnvoll, wenn Sie bereits ZFS einsetzen und Snapshots sowie Rollbacks eines vollständigen Dienstes benötigen, wenn Ihre Dienste FreeBSD nativ unterstützen, wenn Sie pro Mandant eine vollständige Userland-Umgebung statt nur eines einzelnen Prozesses wünschen 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. Ausführlicher behandelt wird er in dem umfassenderen Vergleich von Linux und FreeBSD als Serverplattformen sowie in den Änderungen von FreeBSD 15 für den Serverbetrieb.
Zum Abschluss eine Einschätzung: Wenn Ihr Team Docker bereits kennt, sind die Umstellungskosten real, und der Nutzen muss konkret sein. Wechseln Sie nicht wegen der Isolierungsqualität. Die beiden Modelle sind sich ausreichend ähnlich, sodass Ihre Konfiguration stärker ins Gewicht fällt. Wechseln Sie, wenn Sie ZFS-gestützte Rollbacks vollständiger Dienste benötigen oder FreeBSD bereits einsetzen.
FAQ
Kann ich Docker-Images unter FreeBSD ausführen?
Nicht Linux-Images und nicht als unterstützten Betriebsweg. FreeBSD unterstützt OCI-Container: sudo pkg install -y podman-suite installiert Podman, das Container über ocijail ausführt, eine Laufzeitumgebung, die darunter echte Jails erstellt. Für die Containerüberwachung muss fdescfs unter /dev/fd eingehängt sein, für das Container-NAT (Network Address Translation) pf. OCI-Images für FreeBSD funktionieren am besten. Linux-Images benötigen zusätzlich die Linux-Kompatibilitätsschicht. Außerdem beschreibt die FreeBSD-Portierung von Podman ihre eigene Installationsmeldung im Oktober 2026 weiterhin als experimentell und für Evaluierung und Tests vorgesehen. Wenn Ihre Bereitstellung aus einem Stack von Linux-Images besteht, sollten Sie ihn unter Linux ausführen. In der RHEL-Familie bedeutet das Docker unter Rocky Linux oder AlmaLinux installieren. Dort taucht Podman ein zweites Mal auf: als Paket, das den Befehl docker bereits bereitstellt, bevor Sie etwas installiert haben.
Sind FreeBSD-Jails sicherer als Docker-Container?
Beide verwenden denselben Kernel des Hosts. Ein Kernel-Fehler stellt daher für beide ein Risiko dar. Keine der beiden Technologien ist die Grenze, die Sie für wirklich nicht vertrauenswürdigen Code wählen würden. Der Unterschied liegt in der Ausgangskonfiguration. Ein Jail verweigert zunächst eine umfangreiche Gruppe von Vorgängen. Sie aktivieren diese dann einzeln über Parameter wieder. Ein Docker-Container startet als root innerhalb einer Gruppe von Namespaces, wobei einige Capabilities entfernt sind. Eine weitere Absicherung müssen Sie ausdrücklich konfigurieren. 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 in einen anderen Pool oder in eine Datei, die Sie vom Host kopieren. Da ein Jail sein vollständiges Userland in einem Dataset speichert, erfasst der Snapshot die installierten Pakete und die Daten zu einem konsistenten 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 Rest aus dem Image neu.
Benötige ich BastilleBSD, oder reicht das Basissystem aus?
Das Basissystem reicht aus. Es ist außerdem 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 verstehen, ohne zuerst die Werkzeuge dieses Hosts erlernen zu müssen. Bastille ist eine Komfortschicht darüber. Das Tool initialisiert Releases, erstellt schlanke Jails, wendet Templates an und schreibt pf-Redirect-Regeln für Sie. Lernen Sie zuerst die grundlegenden Befehle. Fügen Sie Bastille anschließend hinzu, wenn die Anzahl der Jails die manuelle Eingabe aufwendig macht.