Паравиртуализация в Xen: без загрузчика никуда

в 1:35, , рубрики: grub, linux, xen, виртуализация, загрузка, загрузчик, ядро, метки: , , , , , ,

Xen mascot PV-GRUB (не путать с заведомо костыльным pygrub) является основанным на GRUB 0.9x загрузчиком для паравиртуальных машин Xen, позволяющим загружать ядро ОС непосредственно из DomU (гостевого) окружения, что добавляет процессу запуска гостевой системы существенной независимости от хост-системы. Одним на наиболее крупных внедрений можно считать облачный хостинг Amazon EC2, также использующий гипервизор Xen и предоставляющий клиентам возможность с помощью PV-GRUB загружать любые кастомизированые ядра (Use your own kernel with Amazon EC2) для паравиртуальных систем.

В данном вопросе всё было бы исключительно позитивно, если бы не вполне обычная для свободного ПО проблема: разработка данной ветки GRUB уже как несколько лет полностью остановлена в пользу GRUB2, а сообщество разработчиков Xen, судя по всему, в ближайшие годы основанной на актуальной версии GRUB замены PV загрузчику предоставить не готово. Сам PV-GRUB, несмотря на то, что является, в общем-то, частью официального дистрибутива Xen, в настоящее время уже исключён как минимум из соответствующих пакетов в репозиториях Debian и Ubuntu, а пользователи, привыкшие к удобствам, между тем требуют (Debian bug #588839: Include pv-grub to securely boot guest kernels) и требуют (Ubuntu bug #798583: xen-utils-4.1 does not have pvgrub)… Хотя лично для меня не очень понятна мотивация мейнтейнеров Xen пакетов, ссылающихся на некие невнятные проблемы с зависимостями, в то время как пакеты с GRUB 0.97 всё ещё доступны и работоспособны, да и к существующему функционалу претензий нет.

Здесь я постараюсь описать, пожалуй, наиболее приемлемое в настоящий момент решение насущной проблемы — самостоятельную сборку PV-GRUB и необходимую настройку DomU для его использования, благо никаких сверхъестественных усилий для этого не требуется.

Для заинтересованных в понимании подноготной реализации для паравиртуальной среды Xen почти традиционного загрузчика будет уместно сразу подбросить некоторых материалов про появившийся ещё в Xen 3.3 функционал stub domains. Краткое введение есть в блоге Xen.org (Xen 3.3 Feature: Stub Domains, Xen 3.3 Feature: HVM Device Model Domain). В остальном стоит полистать презентацию (PDF) и послушать доклад «Stub domains: A step towards Dom0 disaggregation», представленный на Xen Summit North America.

Для сборки загрузчика понадобится исходный код Xen. Лучше всего взять ту версию, которая уже применяется на вашей хост-системе. Поскольку я использую Debian GNU/Linux «Wheezy», для меня это будет Xen 4.1.4. Собирать можно на любой системе с минимальным девелоперским набором (gcc+binutils+make). С официального сайта Xen (Xen 4.1 series, Xen 4.2 series) скачиваем и распаковываем tarball с исходниками:

$ wget http://bits.xensource.com/oss-xen/release/4.1.4/xen-4.1.4.tar.gz
$ tar xzf xen-4.1.4.tar.gz

Переходим в директорию stubdom. Запускаем сборку загрузчика:

$ make grub

Если необходимо собрать загрузчик под архитектуру, отличную от системной, то её можно задать через переменную XEN_TARGET_ARCH:

$ XEN_TARGET_ARCH=x86_32 make grub

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

In file included from xc_core.c:69:0:
xc_core.h:26:35: fatal error: xen/libelf/elfstructs.h: Нет такого файла или каталога
compilation terminated.

Ищем виновника:

$ find .. -type f -name xc_core.h
../tools/libxc/xc_core.h

Заменяем в нём строку

#include "xen/libelf/elfstructs.h"

на

#include "xen/elfstructs.h"

При повторном выполнении make grub следует ещё несколько подобных:

xc_dom.h:17:31: fatal error: xen/libelf/libelf.h: Нет такого файла или каталога
xc_hvm_build.c:34:31: fatal error: xen/libelf/libelf.h: Нет такого файла или каталога
../../xen/common/libelf/libelf-private.h:70:31: fatal error: xen/libelf/libelf.h: Нет такого файла или каталога

Все решаются заменой

#include <xen/libelf/libelf.h>

на

#include <xen/libelf.h>

Теперь сборка должна завершиться успешно. Последние строки вывода, которые вы скорее всего увидите, будут:

gzip -f -9 -c /home/user/xen-4.1.4/stubdom/mini-os-x86_64-grub/mini-os >/home/user/xen-4.1.4/stubdom/mini-os-x86_64-grub/mini-os.gz
make[1]: Leaving directory `/home/user/xen-4.1.4/extras/mini-os'

Полученный уже сжатый файл mini-os-x86_64-grub/mini-os.gz пожно переименовать в более понятное pv-grub-x86_64.gz (или pv-grub-x86_32.gz если собирали под x86_32), а затем положить в директорию /usr/lib/xen-4.1/boot вашего Dom0, где ему самое место (справедливо для Debian при установленном пакете xen-utils-4.1, там же находится hvmloader).

Перед непосредственным переключением на использование загрузчика стоит проделать некоторые подготовительные процедуры для вашей гостевой системы.
Стоит отметить, что старый GRUB непосредственным образом не дружит с современными файловыми системами вроде Ext4, не говоря уже о менее распространённых. Поэтому предварительно стоит убедиться, что раздел, где у вас будет размещаться образ ядра, initrd и конфигурационные файлы GRUB (по умолчанию всё хранится в директории /boot), будет доступен загрузчику для чтения. Я в процессе прохождения описываемого здесь квеста уже наступил на грабли: несмотря на теоретически существующую обратную совместимость Ext4 с Ext2, существует немало различных расширений (features), которые эту совместимость полностью исключают, особенно если при создании вашего Ext4 раздела вы специально об этом не задумывались. Прежде создавать отдельный раздел под /boot у меня не возникало особой необходимости. Сейчас же решением может быть как раз вынос вышеотмеченной стартовой троицы на микро-раздел (думаю, двойного объёма от текущего содержимого /boot будет вполне достаточно), отформатированный в Ext2. Не забудьте также отредактировать /etc/fstab вашего DomU, добавив туда /boot раздел и изменив наименования блочных устройств остальных разделов, если это необходимо. Это же касается и конфигурации дисков самой виртуальной машины.
Проверить насколько существующий раздел годится для монтирования в режиме обратной совместимости с Ext2 можно элементарно через mount -t ext2.

На самой виртуальной машине необходимо установить старую версию GRUB (пакет grub-legacy в Debian или максимально кастрированный grub-legacy-ec2 в Ubuntu). На запросы об установке GRUB в загрузочный сектор какого-либо раздела стоит отвечать отрицательно — это не имеет смысла.
После установки убедимся, что директория для хранения конфигурации GRUB существует и доступна для записи. Запуск update-grub создаст файл меню загрузчика, добавив в список загрузки установленные в системе ядра.

$ mkdir /boot/grub
$ update-grub
Searching for GRUB installation directory ... found: /boot/grub
Probing devices to guess BIOS drives. This may take a long time.
Searching for default file ... Generating /boot/grub/default file and setting the default boot entry to 0
Searching for GRUB installation directory ... found: /boot/grub
Testing for an existing GRUB menu.lst file ...

Generating /boot/grub/menu.lst
Searching for splash image ... none found, skipping ...
Found kernel: /vmlinuz-3.2.0-4-amd64
Updating /boot/grub/menu.lst ... done

Заглянем в созданный /boot/grub/menu.lst:

title       Debian GNU/Linux, kernel 3.2.0-4-amd64
root        (/dev/xvda1)
kernel      /vmlinuz-3.2.0-4-amd64 root=UUID=f5731cf7-420a-4094-acf7-bec5976a0b62 ro
initrd      /initrd.img-3.2.0-4-amd64

title       Debian GNU/Linux, kernel 3.2.0-4-amd64 (single-user mode)
root        (/dev/xvda1)
kernel      /vmlinuz-3.2.0-4-amd64 root=UUID=f5731cf7-420a-4094-acf7-bec5976a0b62 ro single
initrd      /initrd.img-3.2.0-4-amd64

Здесь бросается в глаза, что конфигуратор неверно заполнил опцию root, подставив вместо понятного GRUB обозначения диска и раздела имя файла блочного устройства. При выборе данных пунктов меню GRUB попросту будет ругаться на неверное значение опции.
Чтобы исправить ситуацию, немного модифицируем сгенерированный /boot/grub/menu.lst добавив опцию groot с явным указанием порядкового номера загрузочного «диска», который впоследствие монтируется как /boot (поскольку полноценных дисков с таблицей разделов в паравиртуальной среде не существует):

groot=(hd0)

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

## timeout sec
# Set a timeout, in SEC seconds, before automatically booting the default entry
# (normally the first entry defined).
timeout 1

Чтобы значение groot корректно воспринималось генератором конфигурации update-grub, дополнительно создадим файл /boot/grub/device.map, куда впишем единственную строку, касающуюся упомянутого загрузочного раздела:

(hd0) /dev/xvda1

Теперь update-grub должен сгенерировать корректный файл меню, работоспособность которого к тому же не будет нарушена, если вы захотите обновить версию основного ядра или добавить дополнительные.

title       Debian GNU/Linux, kernel 3.2.0-4-amd64
root        (hd0)
kernel      /vmlinuz-3.2.0-4-amd64 root=UUID=f5731cf7-420a-4094-acf7-bec5976a0b62 ro
initrd      /initrd.img-3.2.0-4-amd64

title       Debian GNU/Linux, kernel 3.2.0-4-amd64 (single-user mode)
root        (hd0)
kernel      /vmlinuz-3.2.0-4-amd64 root=UUID=f5731cf7-420a-4094-acf7-bec5976a0b62 ro single
initrd      /initrd.img-3.2.0-4-amd64

Если необходимо передавать ядру какие-либо дополнительные параметры, которые прежде задавались непосредственно в конфигурации виртуальной машины через опцию extra, то это можно сделать путём модификации kopt в том же /boot/grub/menu.lst.

В качестве финального аккорда остаётся переконфигурировать процесс запуска DomU: имя файла загрузчика необходимо указать в опции kernel. Если образ загрузчика лежит в директории по умолчанию (там же, где и hvmloader), то полный путь указывать не обязательно. В опции extra указывается раздел и путь к файлу меню GRUB.

kernel = 'pv-grub-x86_64.gz'
extra  = '(hd0)/grub/menu.lst'

От прежних опций ramdisk и root необходимо избавиться.
Чтобы убедиться в полной работоспособности новой конфигурации, первый запуск DomU стоит производить в режиме автоподключения к консоли (xm start -c). Если всё проделано верно, то вы увидите меню GRUB и последующий процесс загрузки ядра с монтированием корневого раздела.

Автор: Lux_In_Tenebris

Источник

Поделиться

* - обязательные к заполнению поля