- PVSM.RU - https://www.pvsm.ru -

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

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

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

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

Для заинтересованных в понимании подноготной реализации для паравиртуальной среды Xen почти традиционного загрузчика будет уместно сразу подбросить некоторых материалов про появившийся ещё в Xen 3.3 функционал stub domains. Краткое введение есть в блоге Xen.org (Xen 3.3 Feature: Stub Domains [8], Xen 3.3 Feature: HVM Device Model Domain [9]). В остальном стоит полистать презентацию [10] (PDF [11]) и послушать [12] доклад «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 [13], Xen 4.2 series [14]) скачиваем и распаковываем 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 [15], там же находится hvmloader).

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

На самой виртуальной машине необходимо установить старую версию GRUB (пакет grub-legacy [16] в Debian или максимально кастрированный grub-legacy-ec2 [17] в 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 обозначения диска и раздела [18] имя файла блочного устройства. При выборе данных пунктов меню 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

Источник [19]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/linux/33474

Ссылки в тексте:

[1] PV-GRUB: http://wiki.xen.org/wiki/PvGrub

[2] pygrub: http://xgu.ru/wiki/xen/pygrub

[3] GRUB: http://www.gnu.org/software/grub/

[4] хостинг: https://www.reg.ru/?rlink=reflink-717

[5] Use your own kernel with Amazon EC2: http://aws.typepad.com/aws/2010/07/use-your-own-kernel-with-amazon-ec2.html

[6] Include pv-grub to securely boot guest kernels: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=588839

[7] xen-utils-4.1 does not have pvgrub: https://bugs.launchpad.net/ubuntu/+source/xen/+bug/798583

[8] Xen 3.3 Feature: Stub Domains: http://blog.xen.org/index.php/2008/08/28/xen-33-feature-stub-domains/

[9] Xen 3.3 Feature: HVM Device Model Domain: http://blog.xen.org/index.php/2008/08/28/xen-33-feature-hvm-device-model-domain/

[10] полистать презентацию: http://www.slideshare.net/xen_com_mgr/xs-boston-2008-stub-domains

[11] PDF: http://www.xen.org/files/xensummitboston08/SamThibault_XenSummit.pdf

[12] послушать: http://vimeo.com/12847666

[13] Xen 4.1 series: http://www.xenproject.org/downloads/xen-archives/supported-xen-41-series.html

[14] Xen 4.2 series: http://www.xenproject.org/downloads/xen-archives/supported-xen-42-series.html

[15] xen-utils-4.1: http://packages.debian.org/wheezy/xen-utils-4.1

[16] grub-legacy: http://packages.debian.org/wheezy/grub-legacy

[17] grub-legacy-ec2: http://packages.ubuntu.com/raring/grub-legacy-ec2

[18] понятного GRUB обозначения диска и раздела: http://www.gnu.org/software/grub/manual/legacy/grub.html#Naming-convention

[19] Источник: http://habrahabr.ru/post/178581/