Linux-гость под гипервизором nos
Соберите маленькое ядро Linux и initramfs на BusyBox, загрузите hv.ko в nos и запускайте, подключайте к сети и останавливайте Linux-гостей.
Гипервизор nos — это загружаемый модуль hv.ko. В итоге он будет запускать внутри nos в QEMU настоящих Linux-гостей:
- собранное вами ядро, загруженное один раз на заданное время командой
hv boot; - долгоживущих гостей (
hv start): вы вводите команды в их консоль, даёте им диск и сеть и останавливаете их; - Alpine Linux в том виде, в каком он поставляется.
Понадобится:
- x86-64. Linux-гости работают под nos только на x86-64.
- Расширение виртуализации, видимое nos. В QEMU есть два варианта:
- TCG с
-cpu maxэмулирует AMD-V с вложенной трансляцией страниц (nested paging) на любом хосте, включая Mac. Это медленно: гость эмулируется дважды, и загрузка до шелла занимает минуты. - KVM на Linux-хосте с включённой вложенной виртуализацией (
nested=1уkvm_amdилиkvm_intel).-enable-kvm -cpu hostотдаёт nos собственный AMD-V или Intel VT-x хоста и работает намного быстрее. В TCG нет VT-x, поэтому бэкенд для Intel работает только под KVM или на настоящем железе.
- TCG с
nos.isoиhv.koиз одной сборки или одного релиза. Ядро отвергает модуль, собранный под другой интерфейс ядра.- Клон репозитория nos — ради его скриптов.
- x86-64-машина или контейнер с Linux для сборки гостя и исходники Linux 6.6 или новее. Гейты проекта используют 6.18.
- QEMU 9.2 или новее для гостей с несколькими CPU под TCG.
Команды ниже рассчитаны на один рабочий каталог, в котором лежат клон nos как nos/ и исходники Linux как linux/. Рядом с ними вы создадите guest/ и rootdir/.
Как гипервизор устроен внутри, рассказано на странице гипервизора и в The hypervisor.
1. Соберите ядро гостя
Гость — это немодифицированный 64-битный bzImage Linux. Начните с tinyconfig и включите то, что предоставляет машина гипервизора. В linux/:
make ARCH=x86_64 tinyconfig
./scripts/config \
-e 64BIT -e PRINTK -e EARLY_PRINTK -e TTY -e SERIAL_8250 -e SERIAL_8250_CONSOLE \
-e BLK_DEV_INITRD -e RD_GZIP -e BINFMT_ELF -e BINFMT_SCRIPT -e PROC_FS -e SYSFS -e DEVTMPFS \
-e MULTIUSER -e POSIX_TIMERS -e FUTEX -e EPOLL -e SIGNALFD -e TIMERFD -e EVENTFD -e FILE_LOCKING \
-e SMP -e HYPERVISOR_GUEST -e X86_X2APIC -e X86_MPPARSE --set-val NR_CPUS 16 \
-e PCI -e PCI_MSI -e VIRTIO_MENU -e VIRTIO_PCI -e VIRTIO_PCI_LEGACY \
-e BLOCK -e BLK_DEV -e VIRTIO_BLK -e EXT4_FS \
-e NET -e INET -e PACKET -e UNIX -e IP_PNP -e NETDEVICES -e NET_CORE -e VIRTIO_NET
make ARCH=x86_64 olddefconfig
make ARCH=x86_64 -j"$(nproc)" bzImage
Ядро появится в linux/arch/x86/boot/bzImage. Не опускайте ARCH=x86_64: на x86-64-хосте простой make tinyconfig настраивает 32-битное ядро. В Debian или Ubuntu для сборки нужны gcc make bc flex bison libelf-dev libssl-dev python3 xz-utils.
Зачем нужны опции:
| Опции | Для чего |
|---|---|
64BIT … SERIAL_8250_CONSOLE |
64-битное ядро, которое пишет в эмулируемый последовательный порт 8250 — консоль гостя |
BLK_DEV_INITRD … DEVTMPFS |
initramfs в gzip, ELF-программы и скрипты, /proc, /sys и devtmpfs |
MULTIUSER … FILE_LOCKING |
то, на что рассчитывают апплеты BusyBox. Прежде всего POSIX_TIMERS: ping из BusyBox отмеряет интервалы через alarm() и без таймеров после первого ответа ждёт вечно |
SMP … NR_CPUS 16 |
гости с несколькими CPU (cpus=): x2APIC, которому нужен HYPERVISOR_GUEST или IRQ_REMAP, таблица MP и до 16 CPU |
PCI … EXT4_FS |
диски: legacy virtio поверх PCI, MSI-X для гостя с несколькими CPU и ext4 |
NET … VIRTIO_NET |
сеть гостей: TCP/IP, пакетные сокеты, автонастройка через ip= и virtio-net |
Это набор опций ядра, которое загружает гейт проекта для Linux-гостей. Чтобы гость слышал кнопку питания, которую нажимает hv stop, добавьте перед olddefconfig ещё -e ACPI -e ACPI_BUTTON -e X86_PM_TIMER -e INPUT -e INPUT_EVDEV. Чтобы он по этой кнопке выключался, в нём должен работать acpid из BusyBox с обработчиком, который выключает систему (ACPI). Без ACPI гость кнопку не слышит, и hv stop останавливает его сразу.
2. Соберите initramfs на BusyBox
initramfs — это статический BusyBox и скрипт /init. Какой именно BusyBox взять, важно по трём причинам:
- Его редактор строки должен спрашивать у терминала позицию курсора (
ESC [ 6 n). Модуль вводит строку в гостя только после того, как услышал этот вопрос в приглашении. - Нужен
httpd— для сетевого примера ниже. - Его
execдолжен запускать скрипт без строки#!через шелл, как требуетudhcpc -s.
Статический BusyBox 1.36.1 из Ubuntu 24.04 умеет все три. В busybox-static из Alpine нет httpd и такие скрипты он не запускает, а BusyBox из официального Docker-образа busybox позицию курсора не спрашивает.
Возьмите бинарник из Ubuntu, напишите init и упакуйте архив:
mkdir -p guest && cd guest
docker run --rm --platform linux/amd64 -v "$PWD:/out" ubuntu:24.04 sh -c \
'apt-get update -qq && apt-get install -y -qq busybox-static && cp /usr/bin/busybox /out/'
cat > init <<'EOF'
#!/bin/busybox sh
/bin/busybox --install -s /bin
mount -t proc proc /proc
mount -t sysfs sysfs /sys
echo "nos-guest: init is up"
dmesg -n 1
exec sh
EOF
cat > initramfs.list <<'EOF'
dir /dev 0755 0 0
nod /dev/console 0600 0 0 c 5 1
dir /bin 0755 0 0
dir /proc 0755 0 0
dir /sys 0755 0 0
dir /mnt 0755 0 0
file /bin/busybox busybox 0755 0 0
file /init init 0755 0 0
EOF
../linux/usr/gen_init_cpio initramfs.list | gzip -9 > initrd
cd ..
В самой Ubuntu 24.04 Docker не нужен: установите busybox-static и скопируйте /usr/bin/busybox. gen_init_cpio — собственная утилита ядра для сборки архива; она собирается вместе с bzImage и создаёт узел устройства без прав root.
Не убирайте
dmesg -n 1из init. Строка ядра, напечатанная после приглашения шелла, скрывает это приглашение от модуля, и тогда каждыйhv execзаканчивается неудачей.
3. Подготовьте корневую файловую систему nos
Соберите nos в клоне; после сборки там будут nos.iso, out/x86_64/modules/hv.ko и out/x86_64/modules/sshd.ko (Сборка nos):
cd nos && ./scripts/build-iso-docker.sh && cd ..
Вместо этого можно взять nos.iso, hv-x86_64.ko и sshd-x86_64.ko из одного релиза. Скопируйте модули как hv.ko и sshd.ko и используйте этот nos.iso в команде QEMU ниже.
Соберите всё, что нужно nos, в rootdir/ и сделайте из каталога образ ext2:
mkdir -p rootdir
cp nos/out/x86_64/modules/hv.ko nos/out/x86_64/modules/sshd.ko rootdir/
cp linux/arch/x86/boot/bzImage guest/initrd rootdir/
nos/scripts/mkrootfs.sh root.img 256 rootdir
mkrootfs.sh даёт файловой системе метку nos — именно её root=auto с ISO монтирует как / на чтение и запись. На Mac скрипт запускает mkfs.ext2 в контейнере nos-builder, который создал build-iso-docker.sh. Всё, чем будут пользоваться гости, должно лежать в rootdir/ в момент создания образа. Разделы про диск и Alpine ниже добавляют файлы: положите их в rootdir/ и перед следующей загрузкой снова запустите mkrootfs.sh. Изнутри nos файл можно и скачать — wget <url> <path>, до 20 МиБ.
4. Загрузите nos
qemu-system-x86_64 -nographic -m 2G -smp 4 -cpu max \
-cdrom nos/nos.iso \
-drive file=root.img,format=raw,id=drive0,if=none \
-device virtio-blk-pci,drive=drive0,disable-legacy=on,disable-modern=off \
-device virtio-net-pci,netdev=net0,disable-legacy=on,disable-modern=off \
-netdev user,id=net0,hostfwd=tcp::2222-:22,hostfwd=tcp::8080-:8080
На Linux-хосте с KVM и вложенной виртуализацией замените -cpu max на -enable-kvm -cpu host.
-cpu maxдаёт AMD-V из TCG с вложенной трансляцией страниц. Модель CPU QEMU по умолчанию сообщает о SVM без неё, а гипервизору она нужна.-nographicвыводит последовательную консоль nos, а с ней и шелл, в ваш терминал.Ctrl-A Xзавершает QEMU.- Два проброса портов: порт хоста 2222 — на sshd в nos, порт хоста 8080 — на порт 8080 в nos, которым ниже пользуется
hv forward.
Подробнее о запуске nos в QEMU — в руководстве Запуск nos в QEMU.
5. Загрузите гипервизор
Введите в шелле nos:
insmod /hv.ko
hv info
hv on
hv info перечисляет, что предлагает расширение процессора, — по одной возможности на строку. hv on включает расширение на всех работающих CPU; hv on 2 включил бы его на одном. Строка hv спрашивает у самих процессоров, на каких из них оно включено:
$ insmod /hv.ko
module: hv loaded at 0xFFFF800031000000
$ hv on
hv: turned on for cpu 0-3
hv: AMD-V (SVM) on for cpu 0-3 of 0-3
hv help перечисляет все подкоманды. hv off снова выключает расширение, но отказывается, пока на указанном CPU работает запущенный гость. rmmod hv сначала останавливает всех гостей, а затем выключает расширение на всех CPU.
6. Гость на минуту: hv boot
hv boot /bzImage initrd=/initrd secs=60 input=id\n cmdline=console=ttyS0 nolapic
bzImage и initrd потоком читаются из файлов nos в память гостя, и гость secs секунд работает на vCPU. Текст из input= вводится в его шелл, как только шелл появится (\n — перевод строки). Затем hv boot печатает консоль гостя и то, чем всё закончилось. Под TCG отчёт выглядит так (из документации проекта, с сокращениями; строки, которые печатает ваш init, будут другими):
--- ttyS0 ---
[ 0.000000] Linux version 6.18.53 ...
[ 0.000000] NX (Execute Disable) protection: active
...
[ 0.540000] Run /init as init process
...
BusyBox v1.36.1 built-in shell (ash)
~ # id
uid=0 gid=0
~ #
--- end ttyS0 ---
Опции hv boot и hv start:
| Опция | Что делает |
|---|---|
mem=MiB |
Память гостя; по умолчанию 256, минимум 64. |
secs=N |
Сколько hv boot держит гостя запущенным; по умолчанию 60, максимум 600. |
initrd=path |
initramfs, файл nos. |
input=... |
Текст, который нужно ввести в шелл гостя, как только шелл появится. |
cmdline=... |
Командная строка ядра гостя. Она забирает весь остаток строки, поэтому ставьте её последней. По умолчанию — console=ttyS0 nolapic для гостя с одним CPU и console=ttyS0 для нескольких. nos добавляет частоту TSC хоста (tsc_early_khz=), если строка её ещё не задаёт и частота известна. |
Пока работает hv boot, консоль гостя построчно попадает и в лог ядра nos — строками hvguest| .... Консоль гостя, запущенного через hv start, попадает туда, только если передать log.
7. Долгоживущие гости
hv start собирает того же гостя, отдаёт его отдельной задаче vCPU и сразу возвращается. Дальше вы обращаетесь к гостю остальными командами hv — из консоли, по SSH или через UDP-шелл. В этой стенограмме команды взяты из прогона гейта проекта под TCG, где гость выходит в шелл примерно через секунду после старта:
$ hv start /bzImage initrd=/initrd cmdline=console=ttyS0 nolapic
hv: vm 0 started on cpu 3 -- /bzImage, 256 MiB, 1 cpu, cmdline "console=ttyS0 nolapic"
$ hv exec 0 secs=60 id
... the rest of its boot ...
~ # id
uid=0 gid=0
~ #
$ hv exec 0 uname -r
uname -r
6.18.53
~ #
$ hv send 0 echo nos$((6*7))nos\n
hv: vm 0: 20 bytes queued
$ hv wait 0 nos42nos
hv: vm 0 printed "nos42nos", 58 ms in
$ hv stop 0
hv: vm 0 stopped -- on request -- nothing in it listens to its power button
| Команда | Что делает |
|---|---|
hv list |
Перечисляет запущенных гостей: работает ли гость, останавливается ли или чем закончился, на каких CPU хоста он работает, его память, время работы и адрес, число перезапусков и счётчики выходов, прерываний, остановок (hlt) и «пинков» (kicks). |
hv exec <id> [secs=N] <line> |
Вводит строку и печатает ответ до приглашения, напечатанного после этой строки (по умолчанию ждёт 10 с). Строка, введённая, пока гость ещё грузится, дожидается его шелла. |
hv send <id> <text> |
Вводит текст сразу, как в терминале: \n — перевод строки. Работает и в приглашении входа, у которого exec прождал бы впустую. |
hv wait <id> [secs=N] [boot=N] <text> |
Ждёт, пока в консоли текущей загрузки появится text; с boot=N — не раньше N-го перезапуска гостя. |
hv console <id> [bytes=N] |
Печатает конец его консоли без управляющих последовательностей. |
hv restart <id> |
Заново загружает гостя из его файлов, работающего или остановленного. |
hv stop <id|all> [secs=N] |
Нажимает его кнопку питания, даёт secs секунд (по умолчанию 30; 0 — не спрашивать) на то, чтобы выключиться самому, затем останавливает и сообщает, чем всё закончилось. |
Используйте id, который напечатал hv start: пока модуль загружен, id не переиспользуются. Гость, который сам себя сбрасывает, останавливается, и причиной указывается сброс — если только он не запущен с restart. Тогда его каждый раз загружают снова, но не больше пяти раз в минуту.
Живая консоль по SSH: hv attach
hv attach — живая консоль гостя: сначала последний килобайт вывода, затем всё, что гость печатает, и каждая нажатая клавиша сразу уходит в гостя. Нужен сеанс, в котором можно печатать, а такой даёт только SSH. Запустите sshd в nos со своим ключом, в шелле nos:
insmod /sshd.ko
sshd allow ssh-ed25519 AAAA... you@host
sshd start
Затем со своей машины:
ssh -t -p 2222 root@127.0.0.1 hv attach 0
Ctrl-] отключает вас от консоли; гость продолжает работать. О входе в nos подробнее — в руководстве Подключение к работающему nos.
8. Дайте гостю диск
disk=<path> даёт гостю диск virtio поверх файла nos. Создайте образ ext4 с файлом внутри, положите его в rootdir/ и пересоздайте root.img:
mkdir -p content && echo hello > content/hello.txt
mke2fs -q -F -t ext4 -d content rootdir/disk.img 32M
nos/scripts/mkrootfs.sh root.img 256 rootdir
На Mac нет mke2fs, поэтому выполните эту строку в контейнере nos-builder. Сначала скопируйте каталог с содержимым внутрь контейнера, как это делает scripts/mkrootfs.sh: mke2fs -d читает расширенные атрибуты, которых bind mount в macOS не отдаёт:
docker run --rm --platform linux/amd64 -v "$PWD:/w" -w /w nos-builder \
bash -c 'cp -r content /tmp/content && mke2fs -q -F -t ext4 -d /tmp/content rootdir/disk.img 32M'
Снова загрузите nos и гипервизор (шаги 4 и 5), затем:
hv start /bzImage initrd=/initrd disk=/disk.img cmdline=console=ttyS0 nolapic
hv exec 0 secs=60 mount -t devtmpfs devtmpfs /dev
hv exec 0 mount /dev/vda /mnt
hv exec 0 cat /mnt/hello.txt
- Имена и размер. До четырёх опций
disk=дают гостюvda,vdbи далее по порядку. Каждый диск имеет размер своего файла: гость пишет в его пределах и никогда его не увеличивает. - Один пишет или многие читают.
disk=path:roделает диск для гостя доступным только на чтение. Образ либо пишет один гость, либо читают сколько угодно гостей, а запуск, который нарушил бы это правило, отвергается с указанием владельца:hv: vm 1 not started -- /disk.img: vm 0's disk writes it. - Сброс кэша доходит до диска. Flush гостя синхронизирует файловую систему nos, на которой лежит образ.
9. Подключите гостя к сети
net у hv start даёт гостю сетевую карту virtio на коммутаторе, общем с другими гостями и с nos. Первый порт получает 10.0.100.2, следующий — 10.0.100.3 и так далее; адрес передаётся ядру гостя через ip=. Сам nos — 10.0.100.1. Запустите двух гостей:
hv start /bzImage initrd=/initrd net cmdline=console=ttyS0 nolapic
hv start /bzImage initrd=/initrd net cmdline=console=ttyS0 nolapic
hv exec 0 secs=60 ping -c 3 10.0.100.1
hv exec 0 ping -c 3 10.0.100.3
ping 10.0.100.2
Первые два ping выполняются в госте 0 — до nos и до второго гостя. Последний — собственный ping nos через его виртуальную сетевую карту hv0.
Доступ к гостю снаружи даёт hv forward. Он ретранслирует порт nos на порт гостя. Поднимите страницу в госте 1 и пробросьте на неё порт 8080 nos:
hv exec 1 mkdir -p /www
hv exec 1 echo hello from a guest > /www/index.html
hv exec 1 httpd -p 80 -h /www
hv forward add 8080 1 80
nos ответит hv: port 8080 forwarded to vm 1, 10.0.100.3:80. QEMU пробрасывает порт хоста 8080 в nos, так что со своей машины:
curl http://127.0.0.1:8080/index.html
Во внешний мир гости выходят через NAT nos, с собственного адреса nos. На DHCP-запрос гостя коммутатор отвечает сам: адрес порта, nos как маршрутизатор и DNS-сервер nos. В initramfs на BusyBox нет /etc/resolv.conf, поэтому, чтобы имена разрешались, направьте его на DNS-сервер, который ядру передал ip=:
hv exec 0 mkdir -p /etc && ln -sf /proc/net/pnp /etc/resolv.conf
NAT не пускает гостей в частные сети, на link-local-адреса (там отвечает сервер метаданных облака), в общее пространство адресов carrier-grade NAT и в собственную подсеть аплинка nos. В user-сети QEMU под последнее попадает и хост по адресу 10.0.2.2: nat allow 10.0.2.2/32 пускает к нему гостей, а nat показывает, что делает NAT. Подробнее — в A network.
10. Несколько CPU
cpus=N даёт гостю N процессоров, до 16, и каждый — отдельная задача vCPU на своём CPU хоста. Ядру гостя нужен Linux 6.6 или новее с SMP, X86_X2APIC и X86_MPPARSE — в рецепте выше всё это есть. Командная строка по умолчанию теряет nolapic, а noapic nos добавляет сам, потому что IO-APIC у машины нет, если не передать ioapic. Из прогона на одном из серверов проекта, с сокращениями:
$ hv start /bzImage mem=256 cpus=2 initrd=/initrd cmdline=earlyprintk=serial,ttyS0,115200 console=ttyS0 no_timer_check
hv: vm 0 started on cpus 3,2 -- /bzImage, 256 MiB, 2 cpus, cmdline "earlyprintk=serial,ttyS0,115200 console=ttyS0 no_timer_check"
$ hv list
vm 0 running cpus 3,2 256 MiB 0 s exits 0 irq 0 hlt 0 kicks 0 /bzImage
$ hv exec 0 grep -e LOC -e RES -e CAL /proc/interrupts
LOC: 266 223 Local timer interrupts
RES: 11 15 Rescheduling interrupts
CAL: 125 144 Function call interrupts
- Каждому vCPU нужен свой CPU хоста. Два процессора одного гостя никогда не делят один CPU хоста, поэтому у гостя может быть не больше процессоров, чем охватывает
hv on. - Гость получает ядра целиком. По умолчанию (
hv cores own) ядра гостя принадлежат только ему, и других гостей на них нет; гость, которому понадобилось бы ядро, занятое другим гостем, отвергается с объяснением.hv cores sharedразрешает гостям делить ядра — для машины, где все гости ваши, аhv coresпоказывает, кто какие CPU занимает. - Под TCG используйте QEMU 9.2 или новее. До 9.2 TCG не пропускает обращения гостя с выключенной страничной адресацией через вложенную таблицу страниц. Второй CPU гостя стартует в реальном режиме, поэтому он работал бы прямо в памяти nos и портил бы её. KVM и настоящее железо всегда делали это правильно.
11. Дистрибутив: Alpine
ISO Alpine в варианте virt загружается как есть. Ядро и initramfs извлекаются из ISO, а сам ISO становится диском гостя, доступным только на чтение. Скачайте alpine-virt-<version>-x86_64.iso с сайта Alpine, затем извлеките и разложите файлы (xorriso есть в большинстве дистрибутивов):
mkdir -p rootdir/alpine
xorriso -osirrox on -indev alpine-virt-3.24.2-x86_64.iso -extract /boot/vmlinuz-virt rootdir/alpine/vmlinuz-virt
xorriso -osirrox on -indev alpine-virt-3.24.2-x86_64.iso -extract /boot/initramfs-virt rootdir/alpine/initramfs-virt
cp alpine-virt-3.24.2-x86_64.iso rootdir/alpine/alpine.iso
chmod 644 rootdir/alpine/*
nos/scripts/mkrootfs.sh root.img 256 rootdir
Загрузите nos и гипервизор и запустите гостя:
hv start /alpine/vmlinuz-virt mem=512 initrd=/alpine/initramfs-virt disk=/alpine/alpine.iso:ro net restart cmdline=console=ttyS0 nolapic modules=loop,squashfs,sd-mod,usb-storage
hv wait 0 secs=600 login:
hv send 0 root\n
hv exec 0 cat /etc/alpine-release; uname -r
Его initramfs загружает virtio_blk, находит ISO на vda, ставит базовую систему из пакетов ISO в tmpfs, а OpenRC доводит загрузку до приглашения входа на ttyS0. getty позицию курсора не спрашивает, поэтому входите через hv send — она вводит текст сразу. После первого send строки exec тоже уходят сразу. На коммутаторе initramfs Alpine настраивает eth0 по ip= и записывает DNS-сервер nos в resolv.conf, так что apk добирается до своих зеркал через NAT. reboot сбрасывает гостя, а restart загружает его снова; чтобы дождаться приглашения следующей загрузки, используйте hv wait 0 boot=1 login:. Загружается и облачный образ Debian: см. A distribution.
На сервере
На сервере, установленном из системного образа (Установка nos на выделенный сервер), модуль уже лежит в /lib/modules/hv.ko, поэтому шаг 5 начинается с insmod /lib/modules/hv.ko. Файлы гостя положите на раздел nos из Linux сервера до загрузки nos или скачайте их изнутри nos через wget. Серверы проекта запускают гостей под AMD-V процессора Ryzen 5 3600 и под VT-x процессора i5-13500 (On real hardware).
Если что-то пошло не так
hv: vm 0: the guest has not read the line -- it is not at a prompt; the line stays queued. Модуль так и не увидел, что шелл гостя спросил позицию курсора. Проверьте, что ваш BusyBox её спрашивает (шаг 2) и что в init есть dmesg -n 1. В приглашении входа пользуйтесь hv send.
hv exec сдаётся, пока гость ещё грузится. По умолчанию он ждёт 10 с. Под TCG дайте первой команде больше времени, например hv exec 0 secs=60 id.
hv on не срабатывает, или hv info не показывает nested paging. Запускайте QEMU с -cpu max (TCG) или с -enable-kvm -cpu host (KVM с включённой вложенной виртуализацией).
insmod /hv.ko сообщает built against another kernel interface. hv.ko должен быть из той же сборки или того же релиза, что и работающее ядро.
Гость с cpus=2 поднимается с одним CPU. Ядро гостя старше 6.6 или в нём нет SMP, X86_X2APIC, X86_MPPARSE либо достаточного NR_CPUS. Старое ядро всё равно загружается на одном CPU.
Гость с несколькими CPU отвергается. На свободных ядрах не хватает процессоров. Остановите одного из гостей, включите расширение на большем числе CPU или используйте hv cores shared.
ping в госте замолкает после первого ответа. В ядре гостя нет POSIX_TIMERS.
Гость не может достучаться до 10.0.2.2 или другого частного адреса. NAT не пускает гостей в частные сети и в собственную подсеть nos. Разрешите нужное командой nat allow <net>.
Гость, который перезагружается, вместо этого останавливается. Без restart сброс останавливает VM, а hv list показывает причину. Запустите гостя с restart или выполните hv restart <id>.
hv off отказывается. На этом CPU ещё работает запущенный гость: сначала остановите его через hv stop или выполните rmmod hv, который остановит всех.
Что дальше
- Пусть всё это сделает гейт проекта:
nos/scripts/hv-linux-test.py --bzimage linux/arch/x86/boot/bzImage --initrd guest/initrdзагружает гостя и прогоняет долгоживущие VM, а--disk,--net,--cpus Nи--attachпокрывают остальное.nos/scripts/hv-distro-test.py --iso alpine-virt-3.24.2-x86_64.isoпроверяет Alpine. Оба используютnos.isoи модули, собранные в дереве (Гейты: как проверять изменения в nos). - Гипервизор и справочник: A Linux guest, Guests that stay up, More than one CPU.
- Установка nos на выделенный сервер — чтобы запускать гостей на настоящем железе.