unix
July 31, 2023

Виртуальные истории. Часть 2 OpenBSD и VMM

Статья про вещи, которые вы точно не хотите знать и в операционной системе, которую вы никогда не увидите вживую. Короче описанное будет актуально лишь для поехавших или скучающих.

Я предупредил.

У нас всегда лучшая дичь!

Традиционный саундрек к посту:

Вводная

OpenBSD это такая операционная система, по идее «общего назначения», но с особенностями.

Примерно как самка человека и самка дельфина — общего назначения лишь на том основании что им обоим можно присунуть.

Вообщем вы поняли.

В этой замечательной системе с недавних пор появилась виртуализация уровня ядра — свой аналог KVM.

Называется эта штука VMM и позволяет запускать другие ОС в виртуализированном окружении с аппаратным ускорением. Поэтому сильно быстрее чем какой-нибудь Qemu или (прости Господи) Bochs.

Короче мы снова будем творить дичь и вещи, выходящие за рамки мышления ИТ-обывателей.

Сама возможность запуска Skype под OpenBSD до сих пор проходит по категории «невозможно» на Stackoverflow.com, впрочем как и половина моих технических статей в этом блоге — держу марку.

Что именно мы делаем

Мы установим и настроим гипервизор в OpenBSD, развернем внутри контейнера Ubuntu 18 20 22, поставим внутри Skype For Linux и пробросим его интерфейс в Xorg-сервер работающий на хосте (те на OpenBSD).

Как тебе такое Элон Маск?

За основу я взял несколько статей по теме: вот, вот и вот. Но к сожалению часть информации устарело, часть шагов не сработало, а часть пришлось выдумывать самому, поэтому получилась первоклассная дичь уникальный материал.

Поехали.

Шаг 1. Подготовка

Сам VMM присутствует в системе начиная с 6й версии, я буду производить все действия на OpenBSD 7.3, на моем боевом Lenovo T440, прошедшим две войны, пандемию и десятки апгрейдов.

Создаем виртуальный диск (от root):

vmctl create -s 30G ubuntu.img -f qcow2

QCow2 это более современный формат, образ займет меньше места на физическом диске.

Так много места нужно из-за необходимости последующего апгрейда устанавливаемой Убунты, плюс ради скайпа придется поднимать практически полное графическое окружение пользователя — вот такой это скотский софт.

После этого создаем файл /etc/vm.conf и вставляем в него вот такую настройку:

vm "ubuntu" {
    memory 2G 
    cdrom "/path/to/mini.iso"
    disk "/path/to/ubuntu.img"
    interfaces 1
    local interface tap
    owner alex   # this is your user
    disable
}

Если вы до этого не крутили VMM на текущей машине то такого файла не будет. Запускаем и включаем сервис управления гипервизором:

doas rcctl -f start vmd
doas rcctl enable vmd

doas это местный sudo — способ запустить команду из-под root будучи обычным пользователем.

Если вы вчера увидели OpenBSD то бегите отсюда эта штука у вас настроена не будет, поэтому запускайте после перехода в root через su безо всяких doas:

rcctl -f start vmd
rcctl enable vmd

После выполнения второй команды и если вы не ошиблись с настройкой — будет сообщение vmd (ok) и vmd появится в списке процессов:

Если же нет, то запускаете демон вручную и смотрите вывод:

vmd -dvvv

Скорее всего ошибка будет про пути до образа диска и ISO с установщиком.

Волшебный образ ISO

Из-за того что VMM максимально прост и ограничен, оочень небольшое количество установщиков получится из него запустить.

Проблема заключается в использовании TTY для общения с виртуалкой — его поддержка должна быть и ее еще необходимо включить.

Первое с чего я начал был Alpine Linux «Virtual», как раз заточенный под такое применение. Он заработал сразу, сходу и без каких-либо дополнительных шагов.

Поэтому перед тем как лезть в Убунту крайне советую проверить работу на Alpine — хотя-бы отладить сеть, с которой все тоже непросто.

Вот тут максимально отбитые товарищи разворачивают кластер Kubenetes на VMM.

Осталось только венду завести для полного счастья и все - коммунизм наконец победит.

Вообщем едем дальше.

Обычный установочный ISO убунты не подойдет, нужно нечто под названием «Minimal CD», причем версии 18 LTS, которую затем еще придется обновлять до текущей 20 22й.

На образе наша сказочная #бля приключения лишь начинаются, потому что дальше нужно будет передать специальную строку в параметры загружаемого ядра, но сначала попробуем настроить сеть.

Волшебная сеть

С сетью вариант по-простому не получился, поэтому ниже будет опять жесть, треш и угар, но работающий.

Для понимания, вариант «по-простому» это вот так:

Option 2 - NAT for the VMs

This setup builds upon the previous and allows VMs to connect outside the host. IP forwarding is required for it to work.

The following line in /etc/pf.conf will enable Network Address Translation and redirect DNS requests to the specified server:

match out on egress from 100.64.0.0/10 to any nat-to (egress)
pass in proto { udp tcp } from 100.64.0.0/10 to any port domain \
	rdr-to $dns_server port domain

Reload the pf ruleset and the VM(s) can now connect to the internet.

Красиво, четко, просто и разумеется из официального руководства. Но не работает, увы.

Поэтому начинаем жестить.

Включаем «IP forwarding» в /etc/sysctl.conf:

net.inet.ip.forwarding=1
net.inet6.ip6.forwarding=1

Чтобы не перезагружаться, включаем его же в работающей системе:

doas sysctl net.inet.ip.forwarding=1
doas sysctl net.inet6.ip6.forwarding=1

В /etc/pf.conf:

ext_if="iwm0"
vmd_if="vether0"
set skip on lo
block return
pass 
match out on $ext_if inet from $vmd_if:network to any nat-to ($ext_if)

Этим мы включаем NAT из виртуальной сети, в которой работает гостевая ОС во внешний мир.

iwm0 тут это внешний физический сетевой адаптер, дырка из которой идет интернет, если по-простому.

Поскольку вся потеха происходит на ноутбуке, iwm0 это Wireless карта с WiFi, тут все банально.

А вот с vether0 все непросто — это мост соединяющий выходной сетевой интерфейс виртуалки:

We need to create a bridge interface for the guest VMs to attach to, and bridge vether0 to it.

Задаем подсеть в /etc/hostname.vether0:

inet 10.13.37.1 255.255.255.0

Настраиваем мост в /etc/hostname.bridge0:

add vether0

Поднимаем оба интерфейса:

Bring vether0 and bridge0 online by running the following commands:

doas sh /etc/netstart vether0
doas sh /etc/netstart bridge0

Перезапускаем файлвол:

doas pfctl -f /etc/pf.conf

Чтобы считались обновленные настройки и начали применяться правила NAT
Но и это еще не все, для полноты счастья нам нужен свой DHCP - ну не вручную же ip-адрес в виртуалке задавать ей-богу:

Create a basic DHCP server configuration file that matches the vether0 configuration. I've specified 10.13.37.32-127 as the default DHCP pool range, and set 10.13.37.1 as the default route.

Добавляем в /etc/dhcpd.conf:

option domain-name "vmm.openbsd.local";
option domain-name-servers 8.8.8.8, 8.8.4.4;
subnet 10.13.37.0 netmask 255.255.255.0 {
 option routers 10.13.37.1;
 range 10.13.37.32 10.13.37.127;
 }

Добавляем в настройку гипервизора в /etc/vm.conf:

switch "local" {
 interface bridge0
}

В самый верх, вне блока vm, поскольку это отдельная настройка.

Затем указываем что хотим использовать этот мост в самой виртуалке:

interface { switch "local" }
#local interface tap

В итоге должно получиться как-то так:

bash-5.2# cat /etc/vm.conf 
switch "local" {
        interface bridge0
}
vm "ubuntu" {
    memory 2G
    cdrom "/home/alex/Downloads/mini.iso"
    disk "/opt/work/vmm/ubuntu.img"
    interfaces 1
    interface { switch "local" }
    #local interface tap
    owner alex   # this is your user
    disable
    } 
    

Включаем и запускаем наш домашний dhcpd:

doas rcctl enable dhcpd
doas rcctl set dhcpd flags vether0
doas rcctl start dhcpd

Вот это set dhcpd flags vether0 крайне важно — это указание DHCP-серверу работать только на интерфейсе виртуалки, чтобы случайно не пересечься с внешним DHCP, который выдает адреса на ваш входящий «железный» интерфейс.

Без этого флага начнутся проблемы с сетью:

We also need to set the flags on dhcpd so that it only listens on vether0. Otherwise, you'll end up with a rogue DHCP server on your primary network. Your network administrators and other users on your network will not appreciate this because it could potentially keep others from getting on the network properly.

Вообщем-то в приличном обществе за самопальный DHCP-сервер в чужой сети когда-то били по лицу — очень уж сильно оно ломает работу.

Шаг 2. Установка

Вот сейчас будет дичь — вам будет нужно отловить момент старта и успеть нажать Tab, по которому вылезет меню grub, в котором надо нажать e — перейти в режим редактирования, докрутить до низу и вписать заветную строчку:

console=ttyS0,115200

в сааамый конец, там где будет слово quiet.

Главная жесть заключается в том что делать все это придется на сбитом терминале, который будет выдавать неправильные символы при нажатии клавиш. И подобрать нормальный терминал мне так и не удалось. В одной из оригинальных статей этот момент лаконично описывают как:

Hit Tab on the bootloader screen to edit the kernel parameters. We want to force it to use the serial console for installation. This is done by adding console=ttyS0,115200 on the line shown. If there’s a quiet, delete that and add the above

Без намека на проблемы с консолью.

Существует альтернативный вариант с монтированием ISO и его пересборкой ради вписывания этой строчки в конфиг — дерзайте, но у меня оно не заработало.

Если у вас все получилось с указанием TTY то будет виден процесс загрузки убунты и появится консольный инсталлятор.

Поскольку это виртуалка — думать особо не надо, просто жать Next.

Шаг 3. Лезем внутрь

Если установка прошла успешно по в итоге будет виден процесс загрузки убунты и вот такой login screen (с поправкой на версию 18):

Входим под созданным во время инсталляции пользователем и первым делом прописываем использование TTY в настройку системного grub.

В файле /etc/default/grub:

GRUB_CMDLINE_LINUX_DEFAULT="console=ttyS0,115200"

Затем все обновляем:

apt update
apt upgrade
do-release-upgrade

Делаем это дважды, сначала обновившись до 20 LTS а затем до 22й.

Устанавливаем sshd:

 sudo apt install openssh-server

Теперь к виртуалке можно наконец цепляться с хоста, открываем консоль и пишем:

ssh -Y alex@ubuntu

ubuntu это просто прописанное имя виртуалки в файле /etc/hosts со стороны хоста.

Ключ -Y разрешает проброс X-сессии, то есть графические приложения в гостевой ОС будут отрисовываться на X-сервере у хоста:

Терминал с белым фоном запущен в виртуальной Ubuntu а рисуется в Xorg OpenBSD.

Пробуем запустить xterm, если все настроено правильно — появится графическое окно с терминалом на рабочем столе хоста, как на скриншоте выше.

Но xterm и хром со скайпом — сильно разные вещи, поэтому нужно будет настраивать дальше.

Начнем с более простого — с браузера Chrome.

Виртуальный Хром

Попытка запустить хром с пробросом X-сессии перестала работать где-то в районе 2010го, из-за усложения механизма авторизации.

Поэтому хрому нужно помочь, вводим в консоли виртуальной убунты:

export XAUTHORITY=$HOME/.Xauthority 
chromium-browser

И оно наконец запускается.

Подробнее про эту проблему можно прочитать вот тут.

Вот так это выглядит:

Самый свежий 115й хром в OpenBSD. Да, мы можем.

К сожалению для запуска Skype этого небольшого шаманства все еще недостаточно.

Skype

Теперь перейдем к самой жести — к Skype & Slack.

Во-первых оно сделано на основе фреймворка Electron — это такая дикая помесь движка браузера и окружения на Node.js.

Во-вторых по-умолчанию в убунте оно ставится через snap, т.е работает внутри контейнера.

В-третьих скайп очень активно использует DBus, причем к нему еще должны быть подцеплены сервисы вроде отрисовки оповещений, которые ставятся в desktop-систему но не на сервер.

Из-за третьего пункта придется ставить в нашу виртуальную убунту практически все графическое окружение.

Отлавливать все зависимости скайпа и электрона у меня ни времени ни желания нехватило, поэтому я поступил проще:

sudo apt install xfce

Что вытянуло и поставило все нужные зависимости.

SDDM и X-сервер естественно от этого не поднимутся, поскольку VMM не предоставляет виртуальной видеокарты — негде картинку рисовать, но вот все необходимые библиотеки в системе будут, что позволит запустить скайп.

Послесловие

Скриншот рабочего окна OpenBSD с запущенным скайпом был уже традиционно выложен на ЛОР, собрав восторги от местых обитателей.

Ниже опишу несколько добавлений по итогам обсуждения на ЛОРе.

Я не использую такую связку из OpenBSD, виртуалки и скайпа каждый день, поэтому большую часть проблем связанных с постоянной эксплуатацией просто не увидел.

Suspend/resume цикл вся эта связка тем не менее переживает успешно, без сбоев.

Еще из замеченного: есть достаточно серьезные тормоза с отрисовкой, особенно если появляются всякие анимированные смайлики или превью видео.

Пользоваться все еще можно, но разумеется не так плавно как на Windows.

Был вопрос насчет звука и видео с вебкамеры.

Звук

Скайп использует фреймворк PulseAudio, который реализован как клиент-сервер. К серверу возможно настроить удаленное подключение и передачу аудиопотока по TCP.

На хосте в OpenBSD запускается сервер pulseaudio а в виртуальной убунте указывается переменная окружения с адресом этого сервера.

Камера

Суть в том чтобы пробросить устройство с камерой внутрь виртуальной убунты, где оно естественно легко подцепится и будет доступно для использования скайпом.

К сожалению на данный момент нет официальной поддержки «device passthrough» в VMM, есть лишь набор патчей, не принятых в ядро. Последний патч вот тут.

Так что на свой страх и риск.