Docker во FreeBSD через VirtualBox
Через эмуляцию не получилось - требуются cgroupfs. Через bhyve тоже не особо получилось - потребовалась реальная машина. Получится ли через VirtualBox?..
Предполагается, что FreeBSD применяется без окружения рабочего стола, иными словами, сама является гостевой системой. Для этого гипервизором должна поддерживаться вложенная виртуализация, в случае VirtualBox (условного Windows) для процессоров AMD в свойствах виртуальной машины FreeBSD должен быть взведен флаг «Включить Nested VT-x/AMD-V» (или аналогичный флаг для процессоров Intel). Ну и ресурсов желательно хотя бы 2/2 (ядер/гигабайт ОЗУ).
Короче. Есть Windows, на нем установлен VirtualBox, в нем виртуальная машина FreeBSD. В свою очередь, на FreeBSD накатим VirtualBox, в котором запустим Arch Linux с Docker'ом. Эту последнюю виртуальную машину (с Docker'ом) я предварительно создал в Windows. Удивительным образом вся эта конструкция работает.
Установка VirtualBox
На момент написания статьи VirtualBox работает строго во FreeBSD 14.1 (или 13.3):
The vboxdrv kernel module uses internal kernel APIs.
To avoid crashes due to kernel incompatibility, this module will only load on FreeBSD 14.1 kernels.
Устанавливаем пакет:
pkg install virtualbox-ose
Получаем, правда, 6.x, тогда как давно уже актуальный 7-й. Ну да ладно, разве что синтаксис команд VBoxManage
возможно несколько устарел.
В /boot/loader.conf добавляем загрузку модуля ядра:
vboxdrv_load="YES"
А в /etc/rc.conf – поддержку виртуальных сетей:
vboxnet_enable="YES"
Поскольку будем работать под root, выполнять инструкцию по настройке прав доступа не требуется. Настраивать FreeBSD как гостевую систему тоже не нужно. Перезагружаемся.
Виртуальная машина Docker
Подготовка
Ранее я описывал создание виртуальной машины Arch Linux с установленным Docker'ом. Там, напомню, была загрузка через UEFI и сетевой мост в качестве адаптера. Возьмем ее за основу, но именно в том виде, что получилась у меня в статье, ничего не заработает.
Во-первых, если этого не сделано, заменим конкретное имя сетевого адаптера на маску в /etc/systemd/network/10-wired.network, например:
[Match]
Name=enp0s*
Во-вторых, создадим файл /boot/startup.nsh, в котором продублируем команду запуска Linux'а относительно efibootmgr:
vmlinuz-linux root=UUID=53825132-fc65-4f88-bf79-6bf885712aae rw initrd=\initramfs-linux.img
В экспорт не попадают данные файла *.nvram, поэтому подстраховываемся, чтобы импортированная машина загружала ОС, а не оболочку UEFI. Поскольку при создании машины использовалась более новая версия VirtualBox, для надежности предлагаю занести ее во FreeBSD через экспорт и импорт. Можно заранее переключить сетевой адаптер из режима моста в NAT, но это будет несложно поменять через командную строку после импорта.
Экспортируем:
Полученный файл скорее всего заливаем через sFTP. Импортируем:
VBoxManage import Arch_Linux.ova
Прямо так загрузится в /root/VirtualBox VMs/Arch Linux. В принципе параметрами импорта можно сразу же изменить настройки, но мы сделаем это отдельными командами далее.
На всякий случай – посмотреть список машин («просто» или подробно):
VBoxManage list vms
VBoxManage list --long vms
Настройка
Если (первый) сетевой адаптер все еще в режиме моста, заменяем на NAT:
VBoxManage modifyvm 'Arch Linux' --nic1 nat
Проброс портов у меня так толком и не заработал, поэтому «по классике» сделаем два сетевых адаптера. Для этого как раз и понадобилась маска в настройках сети. Создадим виртуальную сеть хоста (точнее ее интерфейс):
VBoxManage hostonlyif create
DHCP сети хоста по идее преднастроен, поэтому первый (нулевой – vboxnet0
) интерфейс получает IP 192.168.56.1, а адреса раздает со 101 по 254. Все это можно увидеть с помощью VBoxManage list dhcpservers
.
Добавляем адаптер в виртуальную машину:
VBoxManage modifyvm 'Arch Linux' --nic2 hostonly --hostonlyadapter2 vboxnet0
Фиксируем внутренний IP-адрес виртуалки. Смотрим MAC-адрес 2-го (только что созданного) адаптера, например grep'ом «длинного» вывода:
VBoxManage list --long vms | grep MAC
NIC 1: MAC: 08002763FECB, Attachment: NAT, Cable connected: on, Trace: off (file: none), Type: 82540EM, Reported speed: 0 Mbps, Boot priority: 0, Promisc Policy: deny, Bandwidth group: none
NIC 2: MAC: 080027D4B06D, Attachment: Host-only Interface 'vboxnet0', Cable connected: on, Trace: off (file: none), Type: 82540EM, Reported speed: 0 Mbps, Boot priority: 0, Promisc Policy: deny, Bandwidth group: none
В данном случае это 080027D4B06D. Пишем:
VBoxManage dhcpserver modify --ifname vboxnet0 --mac-address 08:00:27:d4:b0:6d --fixed-address 192.168.56.10
В принципе мы ранее подстраховались по поводу загрузки ОС, но если хочется сэкономить несколько секунд, то можно скопировать файл Arch Linux.nvram с «суперхоста» (там где карту получали виртуальную машину создавали изначально) или впоследствии запустить efibootmgr
в уже загруженной системе.
Ну и как бы стартуем (без интерфейса):
VBoxManage startvm --type=headless 'Arch Linux'
Если все сделано правильно, то через некоторое время можно будет зайти по SSH на зафиксированный нами IP. Если же нет, то тогда беда!
Автозапуск
Поместим машину в «автозагрузку». Сначала получим ее UUID:
VBoxManage list vms
"Arch Linux" {d50804f1-8f00-4049-9407-ddcfecbf388e}
Далее включим и настроим сервис vboxheadless – добавим в файл /etc/rc.conf (можно без хлеба комментариев, в случае чего описание сервиса в /usr/local/etc/rc.d/vboxheadless):
# vboxheadless_enable (bool): Set to "NO" by default.
# Set it to "YES" to enable vboxheadless.
vboxheadless_enable="YES"
# vboxheadless_machines (str): Space separated list of machines
vboxheadless_machines="arch"
# vboxheadless_<machine>_name (str): Virtualbox machine name or UUID.
vboxheadless_arch_name="d50804f1-8f00-4049-9407-ddcfecbf388e"
# vboxheadless_<machine>_user (str): User account to run with.
vboxheadless_arch_user="root"
Поскольку название машины у нас содержит пробел, нужно сделать небольшую подстановку (имени в списке для сервиса и соответствующего UUID). Жестко проверяем путем перезагрузки FreeBSD.
В случае чего, есть еще vboxheadless_delay
(задержка запуска и завершения работы), но вроде бы и без нее все заработало. А еще есть параметр, отвечающий за действие при выключении/перезагрузки хоста (vboxheadless_stop
), по умолчанию происходит сохранение состояние машины (savestate). Скорее всего нас это устраивает.
Общие папки
Понятно, что их можно реализовать через какую-нибудь Самбу-мамбу , WebDAV (?!)… Но в VirtualBox есть собственная реализация, которую и хотелось бы продемонстрировать. Пробросим /srv/docker (прямо с одинаковыми путями в обоих системах) – в Arch Linux в /srv уже созданы каталоги ftp и http, так что будет неплохая компания.
Устанавливаем в Arch Linux гостевые утилиты без поддержки графики:
pacman -S virtualbox-guest-utils-nox
systemctl enable vboxservice
mkdir /srv/docker
Они, правда, уже 7.1 – посмотрим, как это все будет взаимодействовать (забегая вперед – специфически, но формально без ошибок). Выключаем машину (poweroff
), они добавляются только «на холодную».
Во FreeBSD:
mkdir -p /srv/docker
echo test > /srv/docker/test.txt
VBoxManage sharedfolder add 'Arch Linux' --name docker --hostpath /srv/docker -automount --auto-mount-point /srv/docker
Запускаем виртуальную машину (или даже перезагружаем всю FreeBSD) – вроде как-то должно заработать. По крайней мере тестовый файл в Arch Linux я увидел, правда с правами 770 root:vboxsf. А если наоборот? В Arch Linux файл создается с теми же характеристиками, во FreeBSD – 644 root:wheel. Ну, сойдет наверное.
Работа с Docker
Клиент во FreeBSD
Он, как говорится, старый, но полезный. Или нет?..
pkg install docker
Настраиваем доступ по SSH в Arch Linux по ключу, это понадобится для удаленного управления Docker'ом. Что-то ssh-copy-id
не захотел работать, поэтому чуть более сложный способ:
ssh-keygen
cat ~/.ssh/id_rsa.pub | ssh root@192.168.56.10 "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
Установим переменную окружения DOCKER_HOST
, чтобы каждый раз не указывать хост в командах. Допустим, в ~/.cshrc (при условии, что ваша оболочка csh):
setenv DOCKER_HOST ssh://root@192.168.56.10
Перезайдем и проверим:
docker info
Должен отобразиться такой же вывод, как и в самой Arch Linux.
Отрицательный пример
Спойлеры, но что поделать.
На всякий случай напоминаю, что мы находимся на хосте (во FreeBSD). Сразу внесу ясность, что с docker compose
придется работать непосредственно в Arch Linux, однако более простые команды выполнить можно.
Создадим /srv/docker/src/index.php:
<?php phpinfo(); ?>
Запускаем:
cd /srv/docker
docker run -d -p 80:80 --name web -v "$PWD/src":/var/www/html php:8.4-apache
Если вдруг FreeBSD обладает оболочкой и браузером, то для проверки заходим на 192.168.56.10. Если же нет, то можно проверить каким-нибудь curl:
curl http://192.168.56.10
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>403 Forbidden</title>
</head><body>
<h1>Forbidden</h1>
<p>You don't have permission to access this resource. Server unable to read htaccess file, denying access to be safe</p>
<hr>
<address>Apache/2.4.62 (Debian) Server at 192.168.56.10 Port 80</address>
</body></html>
Эээ, ну тоже вариант, конечно – хотя бы есть контакт. Однако причина не в отсутствующем .htaccess, а правах. Напоминаю, что для Arch Linux это 770 root:vboxsf, а Апач… Сейчас посмотрим (многие читатели, конечно, уже знают ответ, но все же)…
docker exec -it web bash
top
top - 11:01:51 up 1:09, 0 user, load average: 0.00, 0.02, 0.04
Tasks: 8 total, 1 running, 7 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.0 us, 0.0 sy, 0.0 ni, 98.7 id, 0.0 wa, 0.0 hi, 1.3 si, 0.0 st
MiB Mem : 948.3 total, 83.2 free, 316.4 used, 687.3 buff/cache
MiB Swap: 1024.0 total, 1024.0 free, 0.0 used. 631.9 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 20 0 89896 25048 16600 S 0.0 2.6 0:00.79 apache2
17 www-data 20 0 89976 11480 3016 S 0.0 1.2 0:00.01 apache2
18 www-data 20 0 89928 10948 2484 S 0.0 1.1 0:00.00 apache2
19 www-data 20 0 89928 10948 2484 S 0.0 1.1 0:00.00 apache2
20 www-data 20 0 89976 11480 3016 S 0.0 1.2 0:00.00 apache2
21 www-data 20 0 89928 10948 2484 S 0.0 1.1 0:00.00 apache2
22 root 20 0 4188 3432 2920 S 0.0 0.4 0:00.09 bash
29 root 20 0 8564 4888 2840 R 0.0 0.5 0:00.04 top
Под www-data или 33:33:
grep www-data /etc/passwd
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
Кажется, что можно сделать chmod/chown, но нет – в общей директории эти команды ни на что не влияют. С другой стороны, можно переопределить пользователя и/или группу с помощью переменных (флаг --env
), но это тоже не вариант: под root в принципе отказывается стартовать, а на gid вместо имени группы (которой, очевидно, в стандартном образе нет) ругается и тоже не запускается. Что касается изменений настроек гостевого сервиса, то их вроде как тоже не обнаружено – предполагается, что пользователь должен быть членом группы vboxsf
и точка.
Что ж, отрицательный результат – тоже результат. Зато получилось продемонстрировать некий анализ и работу с Докером прямо с хоста (FreeBSD). Кстати возвращаемся туда и прибираемся за собой:
docker stop web
docker container rm web
Ложно-положительный пример
Набросаем какой-нибудь /srv/docker/compose.yaml (пока неважно где – пути одинаковые):
services:
web:
build: ./
restart: unless-stopped
volumes:
- $PWD/src:/var/www/html
ports:
- 80:80
/srv/docker/Dockerfile (да, у нас тут уже PHP 8.4 вышел):
FROM php:8.4-apache
RUN groupadd -g 109 vboxsf
ENV APACHE_RUN_GROUP=vboxsf
И /srv/docker/src/index.php с тестом записи:
<html>
<body>
<?php
$id = uniqid('f', true);
$fn = __DIR__ . '/' . $id;
file_put_contents($fn, $id);
if (file_exists($id)) {
echo '<pre>' . file_get_contents($fn) . '</pre>';
unlink($fn);
} else {
echo '<p><strong>Error</strong></p>';
}
?>
</body>
</html>
Теперь уже строго в Arch Linux запускаем всю эту страсть:
cd /srv/docker
docker compose up -d
В зависимости от того, где вы находитесь, проверяем:
curl http://127.0.0.1
curl http://192.168.56.10
Как ни странно, работает:
<html>
<body>
<pre>f67602a64eb91d0.55464250</pre></body>
</html>
Разве что осталось проверить, запускается ли контейнер после перезагрузки. «Погасим» для пущей важности Arch Linux (poweroff
) и через некоторое время перезагрузим FreeBSD (reboot
).
A few days hours minutes later:
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b3fe127057f5 docker-web "docker-php-entrypoi…" 28 minutes ago Up About a minute 0.0.0.0:80->80/tcp, :::80->80/tcp docker-web-1
curl http://192.168.56.10
<html>
<body>
<pre>f67603074c16925.36770892</pre></body>
</html>
Все работает, но осадок остался – уж слишком специфическая получается настройка прав доступа. Ну или пусть программы в контейнерах работают под root, что тоже как бы…
Истинно положительного примера не будет, потому что мы тут черте-чем занимаемся.
Заключение
Откровенно говоря, совершенно непонятно, зачем городить такой огород, разве что у вас рабочая станция на FreeBSD. В случае же VPS/VDS лучше Linux поставить на отдельный сервер – хотя при раскладах схема может работать и в таком варианте. Скажем, у вас и так «жирный» сервер… Я даже проверил схему на одном из хостингов (правда там была вообще 12-я изначально – пришлось сначала долго и упорно обновлять), при этом машину банально scp
загрузил. Впрочем, на этом же хостинге и bhyve заработал, а на другом – ни то, ни другое.
Преимуществами VirtualBox над bhyve являются GUI «из коробки» (тем самым облегчается создание и настройка машин). bhyve же, по идее, должен выигрывать в производительности, поскольку он входит в состав ОС. К тому же при использовании VirtualBox нужно внимательно следить за версией FreeBSD.
Категория: Программирование, веб | Опубликовано 14.06.2025 | Редакция от 05.07.2025
Похожие материалы
Веб-сервер на FreeBSD с использованием клеток
Здесь вам не Докер, а клетки (jails) - будем говорить, это контейнеры FreeBSD, когда это еще не было мейнстримом (на минуточку, они появились еще во FreeBSD 4.x - 2000 год). Практический смысл в моем случае - неким образом изолированно использовать разные версии PHP, ну и чуть ближе познакомиться с технологией, с которой я уже сталкивался при обзоре TrueNAS. Основано, как говорится, на реальных событиях - я переносил сайты на Drupal 7.x и Yii с сервера на Linux.
FreeBSD на VPS
Продолжаю устанавливать что-нибудь этакое на VPS. На сей раз решил, так сказать, вернуться к истокам - ведь когда-то многие веб-сервера были на фряхе, а также посмотреть, насколько она компактна сама по себе и в плане ресурсоемкости.