FreeBSD jails чи Docker containers: що обрати
Порівняйте FreeBSD jails і Docker containers: повний FreeBSD userland проти layered images з registry, а також відмінності у software, state, networking і limits.
FreeBSD jails і Docker containers в одному абзаці
FreeBSD jails і Docker containers вирішують ту саму проблему, але в різних формах. Обидва запускають ізольовані userland на одному спільному kernel, тому жоден із них не є віртуальною машиною. Відмінність полягає в тому, що саме міститься всередині. Docker container запускає один процес із layered image, отриманого з registry. Jail запускає повний FreeBSD userland: власний /etc, власні startup scripts rc, власну базу даних pkg і будь-яку кількість процесів. Майже всі інші відмінності на цій сторінці випливають із цього.
SSD Nodes не пропонує FreeBSD images. На цій платформі не можна орендувати FreeBSD server, і наведений нижче матеріал не є інструкцією зі встановлення для машини, яку можна придбати тут. Це порівняння двох моделей ізоляції, підготовлене для того, щоб ви могли визначити, яка з них фактично потрібна workload, і прочитати інструкції з налаштування команди FreeBSD без припущень.
Що насправді являє собою jail
Jails з’явилися у FreeBSD 4.0 у березні 2000 року. Вони старші за cgroups і приблизно на десятиліття старші за Docker. Механізм використовує один kernel call. jail(8) бере дерево каталогів і запускає в ньому процеси з прикріпленим jail ID. Після цього kernel забороняє фіксований набір операцій кожному процесу з цим ID. Процес у jail не бачить процесів за межами свого jail, не може монтувати або розмонтовувати файлові системи, завантажувати kernel modules і прив’язуватися до мережевих адрес, які не були надані jail. Окремий тип namespace для вивчення не потрібен. Також немає окремого дозволу для кожної функції: обмеження застосовуються як один набір і налаштовуються параметрами в конфігурації jail.
На host команда jls показує запущені jails, а jexec web sh відкриває shell усередині jail з іменем web.
Jail створюють, розміщуючи userland FreeBSD у каталозі. Базова система робить це за вас:
sudo bsdinstall jail /usr/local/jails/containers/webКоманда отримує набір базової дистрибуції для вашого релізу та виконує більшість стандартних кроків після встановлення. Тому ви встановлюєте root password, вибираєте services і додаєте users так само, як на новому server. Часовий пояс команда не запитує: installer копіює /etc/localtime з host у jail, тому jail успадковує часовий пояс host. У результаті в каталозі з’являється інсталяція FreeBSD. Потім опишіть її у /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;
}Запустіть jail і перевірте його:
sudo service jail start web
jlsТепер jls має показати web з JID, hostname та IP address. Якщо jail не відображається, запустіть sudo jail -c web безпосередньо. Команда застосовує ту саму конфігурацію у foreground і виводить параметр, який не вдалося прийняти, замість того щоб залишити помилку у виводі service.
Рядок, який варто перечитати двічі, — exec.start = "/bin/sh /etc/rc". Запуск jail виконує звичайний boot script FreeBSD всередині нього. Тому jail запускає всі services, увімкнені у власному /etc/rc.conf. У Docker container немає еквівалентного кроку, оскільки він запускає entrypoint process image і зупиняється, коли цей process завершується.
Як ви отримуєте програмне забезпечення: images і registries проти userland, який ви наповнюєте
Цю різницю ви відчуєте вже в перший день.
У Docker ви вказуєте програмне забезпечення й отримуєте його. docker pull nginx завантажує багатошаровий image з адресацією за вмістом, який хтось інший зібрав і протестував, а docker compose up -d запускає його з підключеними volumes і network. Registry є основою цього підходу. Більша частина цінності Docker workflow полягає в тому, що тисячі проєктів публікують готові робочі images. Саме тому запуск Docker на VPS займає мало часу, а не перетворюється на окремий проєкт.
FreeBSD не постачається з default public registry для jail images. Ви створюєте порожній userland і встановлюєте в нього програмне забезпечення так само, як налаштовували б bare server. Це потребує більше команд. Водночас процес прозоріший, оскільки в jail працює саме те, що туди встановив pkg, з того самого набору пакетів, який використовує host.
Інструменти скорочують цей процес. BastilleBSD — поширений jail manager, доступний як package:
sudo pkg install bastille
sudo sysrc bastille_enable=YES
sudo bastille setup
sudo bastille bootstrap 15.1-RELEASEbastille setup налаштовує network, storage і firewall. bastille bootstrap завантажує release один раз, а кожен наступний jail повторно використовує його. FreeBSD 15.1 — поточний production release, випущений у June 2026; замініть його на release, який використовуєте ви.
Після цього jail створюється однією командою, а наповнюється ще однією:
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 відкриває login shell усередині jail, а bastille list показує, що існує на host. Для повторення збірки Bastille templates зберігають кроки у файлі та застосовують їх до jail. Це найближчий аналог Dockerfile у цьому середовищі. Template повторно застосовується до кожного jail. Нічого не надходить у готовому вигляді.
Отже, підсумок простий. Docker надає збірки інших користувачів. Jails надають власні інсталяції. Якщо потрібне вам програмне забезпечення постачається лише як container image, це одразу визначає вибір, ще до розгляду інших критеріїв.
Стан і оновлення: що змінює ZFS
Docker навмисно розділяє стан. Файлова система контейнера одноразова, а ваші дані зберігаються в іменованому томі або bind mount. Оновлення — це docker compose pull, після чого виконується docker compose up -d. Контейнер замінюється, а все, що не було розміщено в томі, втрачається. Це перевага, якщо дотримуватися правила, і втрата даних, якщо про нього забути. Саме тому вибір між bind mounts та іменованими томами має таке значення в стеку Compose.
Jail не розділяє стан, і саме завдяки ZFS це працює. Увесь jail є одним dataset:
sudo zfs snapshot zroot/jails/containers/web@pre-upgrade
sudo pkg -j web upgrade
sudo zfs rollback zroot/jails/containers/web@pre-upgradeПеред виконанням цієї команди перевірте фактичну назву dataset за допомогою zfs list. Наведений вище шлях відповідає структурі, яку використовує handbook. Створення snapshot займає приблизно секунду й майже не потребує додаткового місця, доки вміст jail не змінюється. Якщо після оновлення сервіс перестає працювати, rollback повертає весь userland до попереднього стану, включно з базою даних пакетів і конфігураційними файлами, які ви вручну редагували о 2am. У Docker немає вбудованого еквівалента, оскільки його модель передбачає, що він вам не знадобиться.
zfs clone — інша складова цього підходу. Clone snapshot — це новий доступний для запису jail, який використовує незмінені блоки спільно з батьківським dataset. Тому staging-копія jail розміром 3 GB майже не займає додаткового місця на диску, доки ви не почнете її змінювати. Так адміністратор FreeBSD створює jail «такий самий, як production», щоб перевірити оновлення.
Оновлення базової системи виконується окремо від оновлення пакетів. Для jail, який містить власну копію userland:
sudo freebsd-update -b /usr/local/jails/containers/web fetch installThin jail дають змогу не повторювати цю роботу. Вони монтують одну спільну базову систему лише для читання через nullfs і надають кожному jail власний невеликий шар, доступний для запису. Тому базову систему можна оновити один раз, після чого зміни побачать усі jail. Bastille за замовчуванням створює thin jail.
Мережа: опубліковані порти проти вибору схеми адресації
Docker сам визначає мережеву схему та просить вас явно опублікувати винятки. Контейнери підключаються до bridge, звертаються один до одного за іменем сервісу в user-defined network, а -p 8080:80 відкриває один із них для host. Docker додає власні правила packet filter, щоб це працювало. Саме тому опублікований порт контейнера обходить ufw напряму.
У jail модель потрібно вибрати заздалегідь. Є два варіанти.
Shared IP. ip4.addr = "10.0.0.10" додає цю адресу до наявного інтерфейсу host і обмежує jail нею. У jail немає власного network stack, тому він не може запускати власний firewall. Він також не може повноцінно прив’язатися до всіх адрес: socket у jail, який запитує 0.0.0.0, kernel переписує на власну адресу jail. Два jail не можуть одночасно слухати port 80 на одній адресі, тому кожному потрібно надати окрему адресу або розмістити reverse proxy попереду.
VNET. Додайте до jail vnet;, і він отримає повний network stack: власні інтерфейси, власну routing table та власні правила firewall. Підключіть його до host через epair — virtual cable, один кінець якого розташований з кожного боку, — і підключіть кінець host до bridge. Це найближча відповідність мережевій схемі Docker. Саме цей режим використовують типи jail Bastille -V і -B.
Переспрямування port host до jail — це правило pf redirect. Bastille спрощує його налаштування:
sudo bastille rdr web tcp 80 80Тут немає EXPOSE і автоматичної публікації. До jail не надходить жоден трафік, якщо його адреса або правило redirect явно цього не дозволяє. Початкове налаштування триває довше, зате firewall працює тихіше.
Обмеження ресурсів: cgroups проти rctl
Docker обмежує контейнер за допомогою cgroups. Обмеження зберігається там, де визначено контейнер: --memory=1g --cpus=1.5 у командному рядку або у відповідних ключах Compose-файлу. Якщо стек уже зберігається в Docker Compose-файлі на VPS, обмеження розташоване поруч із сервісом, до якого воно застосовується, і зберігається разом із ним у git.
FreeBSD використовує rctl. Це підсистема, яку потрібно ввімкнути. Облік ресурсів вимкнено за замовчуванням, оскільки він додає невеликі накладні витрати під час кожного виділення ресурсу. Додайте tunable до /boot/loader.conf і перезавантажте систему:
kern.racct.enable=1Потім задайте правило та перевірте його:
sudo rctl -a jail:web:vmemoryuse:deny=1g
rctl -hu jail:webrctl -hu jail:web виводить поточне використання ресурсів jail у зручних для читання одиницях. Так можна побачити, наскільки використання наблизилося до обмеження, перш ніж виникне помилка. Дія deny змушує виділення ресурсу понад ліміт завершитися помилкою всередині jail. Тому ви побачите власну помилку виділення ресурсу від застосунку, а не повідомлення про завершення процесу на хості.
Правила, додані за допомогою rctl -a, зникають після наступного перезавантаження. Сервіс FreeBSD rctl завантажує їх із /etc/rctl.conf. Тому запишіть правило в цей файл і ввімкніть сервіс:
sudo sysrc rctl_enable=YESСаме тут Docker помітно зручніший. Обмеження в Compose-файлі переглядається разом із сервісом, на який воно поширюється. Правило rctl — це рядок в окремому файлі, де вказано jail, визначений в іншому місці.
Коли потрібна віртуальна машина: bhyve
Jail використовує ядро хоста, тому деякі можливості для нього недоступні. Він не може запускати іншу версію ядра, завантажувати модуль ядра або запускати двійкові файли Linux так, як це робить контейнер Linux. У FreeBSD є рівень сумісності з Linux — linuxulator, але він реалізує лише підмножину системних викликів Linux і не є універсальним рішенням для довільних образів Linux.
bhyve — це гіпервізор FreeBSD. Він підходить, коли потрібна справжня межа ізоляції: інша операційна система, інше ядро або орендар, якому ви не хочете надавати спільний доступ до ядра. За це доводиться платити пам’яттю, яку резервують, а не спільно використовують, і необхідністю оновлювати ще одне ядро. Це те саме рішення, яке ви приймаєте в Linux між контейнерами та повноцінними віртуальними машинами. Воно визначає, чи потрібен вам VPS із підтримкою вкладеної віртуалізації на базовому рівні.
Екосистема — справжня причина, через яку більшість команд використовує Docker
Усе описане вище стосується моделі. Для більшості команд вибір визначає розмір екосистеми навколо кожної технології.
Docker надає Docker Hub і GHCR, docker compose, Kubernetes, коли одного сервера вже недостатньо, CI runners із готовою підтримкою контейнерів і quickstart в один рядок майже в README кожного проєкту. Jails мають дерево портів FreeBSD, яке є великим і ретельно підтримується, а також значно менший набір готових до запуску пакетів застосунків. Якщо проєкт публікує лише container image, у FreeBSD потрібно прочитати документацію та самостійно зібрати всі компоненти.
Jails виправдовують свій вибір з іншого боку цього компромісу. Вони потрібні, якщо ви вже використовуєте ZFS і цінуєте snapshot та rollback цілого сервісу, якщо ваші сервіси нативні для FreeBSD, якщо для кожного tenant потрібен повний userland замість одного процесу або якщо ви хочете, щоб kernel, packet filter, filesystem і документація підтримувалися разом як єдина система. Саме це мають на увазі, коли називають FreeBSD цілісною системою. Детальніше про це йдеться у ширшому порівнянні Linux і FreeBSD як серверних платформ та в матеріалі про зміни у FreeBSD 15 для використання на серверах.
Висновок. Якщо ваша команда вже добре знає Docker, перехід матиме реальну вартість, а переваги мають бути конкретними. Не переходьте заради якості ізоляції: ці дві моделі достатньо близькі, тому конфігурація має більше значення. Переходьте, якщо вам потрібен rollback цілих сервісів на базі ZFS або якщо ви вже використовуєте FreeBSD.
FAQ
Чи можна запускати Docker images у FreeBSD?
Не Linux images і не як підтримуваний варіант. FreeBSD підтримує OCI containers: sudo pkg install -y podman-suite встановлює Podman, який запускає containers через ocijail — runtime, що створює реальні jails під ним. Для monitor контейнерів потрібно змонтувати fdescfs у /dev/fd, а для container NAT (network address translation) — pf. Найкраще працюють OCI images, створені для FreeBSD. Для Linux images додатково потрібен Linux compatibility layer. Станом на October 2026 власне повідомлення про встановлення FreeBSD Podman port усе ще описує його як експериментальний і призначений для оцінювання та тестування. Якщо ваше розгортання складається зі stack Linux images, запускайте його в Linux. У сімействі RHEL це означає встановити Docker у Rocky Linux або AlmaLinux, де Podman з’являється вдруге як пакет, якому вже належить команда docker, ще до встановлення будь-яких компонентів.
Чи безпечніші FreeBSD jails за Docker containers?
Обидва варіанти використовують одне host kernel, тому помилка в kernel становить ризик для обох. Жоден із них не є межею ізоляції, яку варто обирати для справді ненадійного коду. Різниця полягає у вихідній конфігурації. Jail починається з широкого набору заборонених операцій, а потім ви вмикаєте їх по одному параметру. Docker container запускається як root у наборі namespaces із вилученими деякими capabilities, а подальше посилення захисту потрібно вмикати окремо. На практиці конфігурація важливіша за модель: jail із увімкненими allow.mount і allow.raw_sockets не є безпечнішим за ретельно налаштований container.
Як створити резервну копію jail?
Створіть snapshot dataset і передайте його. sudo zfs snapshot zroot/jails/containers/web@backup, потім zfs send цей snapshot до іншого pool або у файл, який ви скопіюєте із сервера. Оскільки jail зберігає весь userland в одному dataset, snapshot містить встановлені packages і дані в узгодженому стані на один момент, а також усі config files, які ви редагували вручну. Це протилежність підходу Docker, за якого ви створюєте резервні копії named volumes і Compose file, а решту відновлюєте з image.
Чи потрібен BastilleBSD, чи достатньо base system?
Base system достатньо, і саме з нього краще починати. jail.conf, jls, jexec і service jail start охоплюють усю модель. Знаючи їх, ви зможете працювати з будь-яким FreeBSD host, не вивчаючи спочатку його tooling. Bastille — це convenience layer над base system: він bootstrap-ить releases, створює thin jails, застосовує templates і сам записує pf redirect rules. Спочатку вивчіть базові команди, а потім додайте Bastille, коли кількість jails зробить ручне введення команд незручним.