Обзор
Jails решают задачу изоляции настолько хорошо, что вопрос «а зачем здесь вообще виртуальная машина» законен. Ответ у него ровно один, зато не обходимый: jail разделяет ядро с хостом. Всё, что упирается в ядро — другая операционная система, другая версия FreeBSD, отладка драйвера, тестирование обновления, которое может это ядро уронить, — в jail не помещается принципиально, а не по недоработке.
bhyve закрывает эту нишу. Это гипервизор второго типа, живущий в базовой системе с FreeBSD 10, устроенный минималистично: никакой эмуляции legacy-железа ради совместимости, ставка на virtio и UEFI, управление обычными утилитами командной строки. Он заметно проще KVM с libvirt и заметно менее функционален — и то, и другое стоит понимать до того, как строить на нём инфраструктуру.
Статья продолжает FreeBSD: Jails и опирается на сетевую часть из FreeBSD: сеть — мосты и tap-интерфейсы там уже разобраны.
Версии-якоря: FreeBSD 15.1 (актуальный релиз на момент написания) и 14.4 в параллельно поддерживаемой ветке 14; 14.5 на начало сентября 2026 в состоянии RC, релиз назначен на 8 сентября. vm-bhyve 1.6.2. Часть возможностей, о которых пойдёт речь в разделе про непривилегированный запуск, есть только в -CURRENT — это оговорено отдельно.
Где проходит граница
Разница между jail и виртуальной машиной — не в степени изоляции, а в том, что именно изолируется.
| jail | bhyve | |
|---|---|---|
| Ядро | общее с хостом | своё |
| Гостевая ОС | только FreeBSD (плюс Linux ABI) | любая с поддержкой платформы |
| Загрузка | секунды, фактически запуск процессов | полный цикл, как у железа |
| Память | берётся из общего пула по мере надобности | резервируется целиком при старте |
| Накладные расходы CPU | практически нулевые | заметные, но небольшие благодаря virtio |
| Модули ядра, sysctl уровня ядра | нет, ядро одно | да, своё ядро |
| Плотность на хосте | сотни | десятки |
Практическое правило: если гость — FreeBSD той же мажорной версии и ему не нужно трогать ядро, это jail, и обсуждать нечего. bhyve берут, когда нужен Linux, Windows, другая версия FreeBSD, или когда гость должен иметь возможность уронить своё ядро, не задев хост.
Главная цена — память. Jail берёт столько, сколько реально использует; виртуальной машине память отдаётся при старте целиком и хосту не возвращается. Механизма вроде ballooning у bhyve нет. На машине с 8 ГБ три виртуалки по 2 ГБ — это минус 6 ГБ, независимо от того, чем они заняты, и это чаще всего и определяет реальный предел плотности.
Архитектура
Требования к железу
На amd64 нужен процессор с VT-x и EPT (Intel) либо с SVM (AMD). Проверяется через sysctl:
sysctl hw.vmm 2>/dev/null || kldload vmm
grep -o 'VMX\|SVM\|POPCNT\|EPT' /var/run/dmesg.boot | sort -u
Помимо amd64, современный bhyve умеет arm64 (загрузочный CPU должен стартовать в EL2, нужен контроллер прерываний GICv3) и riscv (требуется расширение H). Это стоит знать, но основной сценарий по-прежнему amd64.
Отдельно: проброс PCI-устройств требует VT-d и доступен только на amd64.
Модуль и утилиты
Работа держится на модуле ядра vmm.ko и трёх утилитах:
kldload vmm # либо vmm_load="YES" в /boot/loader.conf
bhyveload— загрузчик для гостевой FreeBSD: читает ядро гостя прямо из образа и передаёт управление. Работает только с FreeBSD.bhyve— собственно гипервизор, он же описание виртуального железа: устройства перечисляются флагами командной строки.bhyvectl— управление созданной машиной, в первую очередь--destroy.
Последний пункт — источник самой частой ошибки новичка. Виртуальная машина в bhyve существует как объект ядра и переживает завершение процесса bhyve. Если гость выключился, а машина не уничтожена, повторный запуск с тем же именем упрётся в занятое имя:
bhyvectl --vm=guest --destroy
Обёртки вроде vm-bhyve делают это автоматически, и именно поэтому с ними жить проще.
Загрузка гостя
Способов два, и выбор определяется гостевой системой.
Для FreeBSD — bhyveload, исторически первый механизм: он понимает загрузчик FreeBSD и не требует прошивки.
Для всего остального — UEFI: bhyve загружает прошивку из порта uefi-edk2-bhyve и дальше ведёт себя как обычная машина с UEFI.
bhyve -c 2 -m 2G \
-s 0,hostbridge \
-s 3,virtio-blk,/vm/linux/disk.img \
-s 5,virtio-net,tap0 \
-s 29,fbuf,tcp=127.0.0.1:5900,w=1024,h=768 \
-s 30,xhci,tablet \
-s 31,lpc -l com1,/dev/nmdm0A \
-l bootrom,/usr/local/share/uefi-firmware/BHYVE_UEFI.fd \
-H -P linuxvm
Читается эта строка как список слотов PCI: -s <слот>,<устройство>,<параметры>. Слот 31 занят lpc не случайно — это устройство несёт последовательный порт и должно жить именно там.
Два флага в конце заслуживают отдельного внимания, потому что их отсутствие даёт неочевидный симптом. -H заставляет виртуальный процессор отдавать управление при инструкции HLT; без него простаивающий гость будет занимать 100% ядра хоста — виртуалка ничего не делает, а top на хосте показывает полную загрузку. -P делает то же для инструкции PAUSE.
Устройства virtio
Смысл virtio в том, что гость знает о виртуализации и не притворяется, будто общается с реальным контроллером. Вместо эмуляции регистров — кольцевые буферы в разделяемой памяти, то есть на порядок меньше переходов в гипервизор.
Основные типы: virtio-blk (диски), virtio-net (сеть), virtio-scsi, virtio-9p для проброса каталога хоста внутрь гостя, virtio-rnd (энтропия для гостя — на свежеразвёрнутой машине это не мелочь), virtio-console. Для гостей без драйверов virtio есть эмуляция: ahci-hd и ahci-cd для дисков, nvme для NVMe-контроллера, e1000 для сети. Пользоваться ими стоит только там, где иначе никак, — это медленнее в разы.
Хранилище: zvol или файл
| zvol | файл-образ | |
|---|---|---|
| Производительность | выше, минус слой файловой системы | ниже на записи |
| Снепшоты | ZFS-снепшоты и клоны как есть | только снепшот всего датасета целиком |
| Перенос на другую машину | zfs send |
обычный cp/scp |
| Разреженность | -s при создании |
зависит от способа создания |
| Просмотр содержимого с хоста | сложно | легко смонтировать |
zfs create -V 20G -o volmode=dev zroot/vm/linuxvm
Рекомендация простая: на хосте с ZFS — zvol. Аргумент не столько в скорости, сколько в снепшотах: снепшот zvol перед обновлением гостя — это откат одной командой, и работает он независимо от того, что за система внутри. Файл-образ оправдан на UFS-хосте и там, где важна тривиальность переноса.
Отдельно про volmode=dev: без него zvol получает запись в /dev/zvol и хост начинает пытаться разбирать таблицу разделов гостя — на хосте появляются лишние устройства, а при неудачном стечении обстоятельств гостевой пул может быть импортирован хостом. Для дисков виртуалок это правильный режим по умолчанию.
Сеть
Схема стандартная: на каждую машину по tap-интерфейсу, все они в мосту вместе с физическим интерфейсом.
sysrc cloned_interfaces="bridge0 tap0"
sysrc ifconfig_bridge0="addm em0 addm tap0 up"
service netif restart
Подробнее про мосты и клонируемые интерфейсы — в статье про сеть FreeBSD.
Один нюанс, на котором спотыкаются регулярно: tap-интерфейс поднимается только когда его открывает процесс, и мост может не пропускать трафик до старта виртуалки. Лечится переключателем:
sysctl net.link.tap.up_on_open=1
Если виртуалки не должны быть видны в физической сети, вместо моста с em0 строится изолированный мост с адресом на хосте и NAT через PF — конструкция та же, что для jail и для домашних сервисов за NAT, и она разобрана в самохостинге за NAT.
Консоль
Для текстовых гостей — nullmodem-пара nmdm: одна её сторона отдаётся виртуалке, ко второй подключаются с хоста.
kldload nmdm
cu -l /dev/nmdm0B
Выход из cu — ~., и это стоит запомнить до, а не после подключения.
Для графических гостей — VNC через устройство fbuf. Слушать он должен на 127.0.0.1 и пробрасываться по SSH: собственного шифрования у встроенного VNC-сервера нет, и выставлять его в сеть нельзя.
ssh -L 5900:127.0.0.1:5900 user@vmhost
Полезная деталь: устройство xhci,tablet даёт абсолютное позиционирование указателя. Без него курсор в VNC-клиенте живёт своей жизнью и «уезжает» относительно реального.
vm-bhyve
Голый bhyve — это ручная сборка командной строки на два десятка аргументов, ручное создание tap-интерфейсов, ручной bhyvectl --destroy и отсутствие автозапуска. Для одной тестовой машины терпимо, для постоянной эксплуатации — нет.
vm-bhyve (1.6.2) закрывает ровно это: конфигурация машин в текстовых файлах, управление мостами, интеграция с rc, автозапуск при загрузке и корректная уборка после остановки.
pkg install vm-bhyve
zfs create zroot/vm
sysrc vm_enable="YES" vm_dir="zfs:zroot/vm"
vm init
vm switch create public
vm switch add public em0
vm create -t freebsd-zvol -s 20G guest
vm install guest FreeBSD-15.1-RELEASE-amd64-disc1.iso
vm console guest
Автозапуск задаётся списком: sysrc vm_list="guest1 guest2", порядок в списке — порядок старта.
Существуют и альтернативы: CBSD — более крупный комбайн, управляющий и jail'ами, и виртуалками; bmd и chyves — другие обёртки разной степени живости. Для типовой задачи «несколько виртуалок на сервере» vm-bhyve — разумный выбор по соотношению возможностей к сложности.
Нюансы и trade-off'ы
PCI passthrough
Устройство отдаётся гостю целиком, минуя хост. Требует VT-d, доступен только на amd64, и хост должен заранее отпустить устройство драйверу ppt:
pptdevs="2/0/0"
Ограничения жёсткие. Устройство перестаёт быть доступно хосту полностью. Проброс не работает при запуске bhyve в jail или без прав root, поскольку требует записи в /dev/pci. Группировка устройств по IOMMU может заставить пробрасывать больше, чем хотелось: если видеокарта делит группу с контроллером USB, отдавать придётся оба. И миграция машины с проброшенным устройством невозможна в принципе.
Чего нет по сравнению с KVM
Честный список, который стоит прочитать до выбора платформы:
- Живой миграции нет. Работа над ней ведётся давно, но полагаться на неё нельзя.
- Ballooning отсутствует: память отдаётся при старте и не возвращается.
- Снепшот работающей машины (suspend/resume состояния VM) — экспериментальная возможность, требующая сборки с отдельной опцией; сравнивать с
virsh saveрано. Снепшот zvol с выключенным гостем работает надёжно и закрывает большую часть потребности. - Экосистема управления несопоставима: нет libvirt и всего, что на него опирается — Terraform-провайдеров, оркестраторов, готового мониторинга.
- Windows-гости работают, но требуют драйверов virtio отдельной установкой, и «просто работает» это назвать нельзя.
Из этого следует прямой вывод, который лучше сделать заранее: если задача — кластер с миграцией и оркестрацией, честнее взять Linux с KVM. bhyve хорош там, где хост уже FreeBSD, машин единицы-десятки, и нужен именно другой гость, а не платформа виртуализации как таковая.
Непривилегированный запуск
В -CURRENT появился режим, позволяющий запускать виртуальные машины не от root: управляющее устройство переименовано в /dev/vmmctl, и доступ к нему получают члены группы vmm. В релизах 15.1 и 14.4 этого ещё нет — там создание и уничтожение машины требует привилегий суперпользователя. Если вы читаете совет про группу vmm и он не работает, дело в версии, а не в конфигурации.
Сравнение с Linux: KVM и libvirt
| bhyve | KVM + libvirt | |
|---|---|---|
| Где живёт | базовая система FreeBSD | модуль ядра Linux плюс QEMU |
| Конфигурация машины | аргументы командной строки или конфиг обёртки | XML, управляемый через virsh |
| Живая миграция | нет | да |
| Ballooning | нет | да |
| Снепшоты состояния VM | экспериментально | да |
| Проброс PCI | есть, VT-d, только amd64 | есть, зрелее по инструментарию |
| Экосистема | vm-bhyve, CBSD | libvirt и всё, что вокруг него |
| Сложность освоения | низкая: три утилиты | высокая: слоёв больше |
Архитектурно они ближе, чем кажется: и там, и там гипервизор живёт в ядре, а эмуляция устройств — в пользовательском процессе. Разница в объёме этого процесса. QEMU умеет эмулировать десятки платформ и сотни устройств, bhyve сознательно ограничивается virtio и минимумом legacy. Отсюда и обе стороны сравнения: bhyve проще понять целиком и в нём меньше нечего ломаться, а всё, что выходит за рамки «запустить современного гостя», в нём просто отсутствует.
С точки зрения FreeBSD это ровно та же линия, что и с jail против Docker (см. FreeBSD: Jails): механизм в базе, минимальный и предсказуемый, а обвязка — дело портов и администратора.
Источники
- bhyve(8) — синтаксис устройств, слоты PCI, флаги
-Hи-P, загрузка через bootrom - vmm(4) — требования к платформам, VT-d для passthrough, управление доступом
- bhyveload(8) — загрузка гостевой FreeBSD
- bhyvectl(8) — уничтожение машины после остановки гостя
- FreeBSD Handbook: Virtualization — сборка типовой конфигурации
- vm-bhyve — конфигурация машин, коммутаторы, автозапуск
Связанные заметки
- FreeBSD — Jails — уровень изоляции ниже: общее ядро, сотни экземпляров вместо десятков
- FreeBSD — сеть — мосты, tap-интерфейсы и PF, на которых держится сеть виртуалок
- FreeBSD — ZFS — zvol под диски гостей, снепшоты и клоны как механизм отката
- Linux — контейнеризация — та же граница «общее ядро против своего», со стороны Linux
- Самохостинг за NAT: VPS как точка входа — изолированный мост с NAT, если виртуалкам не нужен адрес в физической сети
- Эксплуатация локальных ИИ-сервисов — проброс видеокарты в гостевой Linux как единственный путь к CUDA на машине с FreeBSD
- Адресное пространство: зачем трансляция и какие есть альтернативы — почему изоляция unikernel'а и библиотечной ОС держится на гипервизоре
Из библиотеки института уносят только знания. Читателей здесь не считают: посещение не регистрируется, отметок в издании не остаётся, счётчиков нет ни у одного издания фонда.
Издание пополняется и пересверяется. Текст доступен на условиях CC BY-SA 4.0 — унесённое можно передавать дальше на тех же условиях.