Через эмуляцию не получилось - требуются cgroupfs. Через bhyve тоже не особо получилось - потребовалась реальная машина. Получится ли через VirtualBox?..

Предполагается, что FreeBSD применяется без окружения рабочего стола, иными словами, сама является гостевой системой. Для этого гипервизором должна поддерживаться вложенная виртуализация, в случае VirtualBox (условного Windows) для процессоров AMD в свойствах виртуальной машины FreeBSD должен быть взведен флаг «Включить Nested VT-x/AMD-V» (или аналогичный флаг для процессоров Intel). Ну и ресурсов желательно хотя бы 2/2 (ядер/гигабайт ОЗУ).

nested_vtx.png

Короче. Есть 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, но это будет несложно поменять через командную строку после импорта.

Экспортируем:

export.png

Полученный файл скорее всего заливаем через 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. Если же нет, то тогда беда! cry

Автозапуск

Поместим машину в «автозагрузку». Сначала получим ее 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). Скорее всего нас это устраивает.

Общие папки

Понятно, что их можно реализовать через какую-нибудь Самбу-мамбу mamba, 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. Ну, сойдет наверное. unknw

Работа с Docker

Клиент во FreeBSD

Он, как говорится, старый, но полезный. Или нет?.. scratch

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, что тоже как бы…

Истинно положительного примера не будет, потому что мы тут черте-чем занимаемся. fool

Заключение

Откровенно говоря, совершенно непонятно, зачем городить такой огород, разве что у вас рабочая станция на 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. На сей раз решил, так сказать, вернуться к истокам - ведь когда-то многие веб-сервера были на фряхе, а также посмотреть, насколько она компактна сама по себе и в плане ресурсоемкости.


Комментарии, обсуждение