dail: запускаю сервисы во freebsd jail как в docker

Я новичок во FreeBSD. Основной опыт у меня с Linux, но в какой-то момент приглянулась философия FreeBSD: стабильность, целостность системы и то, что многие вещи там были сделаны давно — сильно раньше, чем в Linux. Например, jail — они появились ещё в 2000 году. Так я решил сделать себе домашний сервер на FreeBSD.

Сразу возник вопрос: как изолированно запускать сервисы? В Linux для этого есть Docker — описал и запустил. Хотелось так же: чтобы не засорять хост и без лишней возни.

Почему своё, а не что-то готовое

Во FreeBSD уже есть jail — изоляция прямо в системе. Не хватало только удобного способа ими пользоваться.

Я посмотрел существующие инструменты, но ни один не понравился. Bastille выглядел прилично, но, как и большинство других, это набор скриптов вокруг jail. А мне близка идея статического бинаря: скачал и запустил.

Ну и, конечно, хотелось сделать своё (куда ж без велосипедостроения).

Так появился dail — daily jail management (github).

Ожидаемое поведение по умолчанию

Я перенёс то, что нравилось в Docker, но с упором на то, чтобы почти ничего не нужно было указывать. Если что-то можно разумно угадать — dail угадывает.

Например, вот целиком файл для моего домашнего OIDC сервера zid:

FROM 15.0-RELEASE

SERVICE zid

EXPOSE 5555

COPY target/release/zid /usr/local/bin/zid
COPY .env /usr/local/etc/zid/zid.env

И запуск:

doas dail run zid.dail --ip 10.100.0.4 --rebuild

Что здесь не пришлось писать:

  • имя jail — берётся из имени файла
  • команду запуска — SERVICE zid по умолчанию запускает /usr/local/bin/zid
  • пользователя, группу, rc.conf — SERVICE делает это сам

IP по умолчанию выдаётся сам, но zid держу на фиксированном — на него завязаны другие сервисы.

Умолчания появлялись из практики. У меня в основном сервисы, поэтому первой появилась директива SERVICE. Вместе с ней понадобилось заводить внутри jail пользователя — и я каждый раз называл его так же, как сервис. Раз так, вынес это в поведение по умолчанию.

Как я пользуюсь каждый день

Обычный цикл выглядит так:

# правлю код
cargo build --release
doas dail run zid.dail --ip 10.100.0.4 --rebuild
doas dail logs zid

Хотя в названии и есть daily, на деле я пользуюсь dail не часто. Зашёл, собрал сервис, пересобрал jail одной командой — и забыл. Дальше оно просто стабильно работает:

$ dail ls
NAME          STATUS   JID  IP              PORTS                           BASE          TYPE  UPTIME
--------------------------------------------------------------------------------------------------------
valkey        running  2    10.100.0.6/24   6379->6379/tcp                  15.0-RELEASE  thin  44d 4h
pg            running  1    10.100.0.2/24                                   15.0-RELEASE  thin  44d 4h
filest        running  6    10.100.0.5/24   8090->8090/tcp, 8090->8090/udp  15.0-RELEASE  thin  44d 4h
zid-pg        running  7    10.100.0.3/24                                   15.0-RELEASE  thin  44d 4h
cfgy-pg       running  9    10.100.0.7/24                                   15.0-RELEASE  thin  44d 4h
cfgy          running  22   10.100.0.8/24   8080->8080/tcp                  15.0-RELEASE  thin  21d 0h
aurora        running  72   inherit         4000->4000/tcp                  15.1-RELEASE  thin  9d 0h
zid           running  78   10.100.0.4/24   5555->5555/tcp                  15.0-RELEASE  thin  5d 7h
domdev        running  148  10.100.0.12/24  8300->8080/tcp                  15.0-RELEASE  thin  4d 0h

Часть jail не перезапускалась больше 44 дней.

Считаю это успехом. И в этом, кстати, видна та самая философия FreeBSD: настроил, запустил и забыл.

Что у меня крутится

Сейчас в jail живут:

  • zid — identity provider (OIDC)
  • cfgy — управление конфигурацией
  • aurora — домашний медиацентр
  • filest — простой REST файл-сервер
  • domdev — блог
  • pg, zid-pg, cfgy-pg — отдельный postgres на каждый сервис
  • valkey — кеш для сервисов

Каждый сервис в своём jail, хост остаётся чистым.

Чего пока не хватает

Не всё идеально:

  • Автозапуск. Если перезагрузить сервер, все jail приходится поднимать руками. В планах режим автозапуска — скорее всего, для этого понадобится что-то вроде демона.
  • Сеть. По умолчанию jail получает IP-алиас на lo0, а проброс портов dail сам прописывает в PF. Но выход наружу (NAT) и bridge для VNET пока настраиваются руками — хочется, чтобы dail делал это сам.

Итог

dail — это мой способ запускать сервисы на FreeBSD так же просто, как в Docker. Один бинарь, короткий .dail файл и одна команда на пересборку.

Если вы тоже пришли во FreeBSD из мира Linux и Docker — попробуйте, буду рад обратной связи: github.com/zeslava/dail