KVM — FreeBSD в виртуальной машине под Linux

FreeBSD 9.1 в KVMЗапускаем FreeBSD под Linux KVM.

Для KVM гипервизора можно использовать любой дистрибутив Linux, мы будем использовать Ubuntu 12.10 x64.

В виртуальной машине будем использовать FreeBSD 9.1 i386. 32-битная архитектура выбрана из-за меньшего потребления памяти 32-битными программами по сравнению с 64-битными.

Настройка Linux системы для запуска KVM

Пусть все нужные образы дисков и файлы настроек хранятся в домашнем каталоге в подкаталоге virt:

Устанавливаем в Linux необходимое для запуска KVM ПО:

apt-get update && apt-get -y install kvm

За виртуализацию отвечает модуль в составе ядра, но при этом нам нужны  управляющие и вспомогательные утилиты, KVM-специфичные настройки для основных Linux-сервисов, находящиеся в пакетах, которые apt-get установит по зависимостям.

Проверяем наличие аппаратной поддержки

kvm-ok

Для запуска виртуальных машин с использованием KVM нам нужна аппаратная виртуализация, которая поддерживается процессором и разрешена в BIOS’e.

Если виртуализация не поддерживается аппаратно, KVM будет переключаться в режим программной виртуализации на базе QEMU, работающий намного медленнее.

Настройка сети для виртуальных машин

Для реального применения лучше всего подходят два варианта:

  1. базовая система предоставляет гостевым прозрачный доступ во внешнюю сеть через т.н. сетевой мост («network bridge»),
  2. базовая система работает как маршрутизатор между внешней и гостевой сетью («router»).

Оба требуют суперпользовательских привилегий, имеют в нашем случае одинаковый набор параметров для»-net …», но отличаются набором действий в сценарии «-net …,script=…«, который KVM вызывает при старте контейнера для настройки сетевого интерфейса, созданного в базовой системе. Вариант с мостом несколько проще, поэтому наш сценарий ~/virt/kvm-ifup-bridge.sh будет делать следующее:

  • если мост отсутствует — создаёт его и добавляет в него внешний физический интерфейс,
  • назначает мосту такой же IP, как у физического интерфейса,
  • перемещает все маршруты с физического интерфейса на мост,
  • подключает в мост виртуальный интерфейс для связи с гостевой системой.
#!/bin/sh

# Constants
BRIDGE_IFACE="br0"

# Variables
iface="$1"

gwdev="$(ip route get 8.8.8.8 | grep ' via ' | sed -e 's,.* dev ,,' -e 's, .*,,' | head -1)"
my_ip="$(ip addr list dev $gwdev | grep ' inet ' | sed -e 's,.* inet ,,' -e 's, .*,,' | head -1)"

# Create and configure bridge
if ! ip link list "$BRIDGE_IFACE" >/dev/null 2>&1
then
        echo "Create bridge $BRIDGE_IFACE..."
        brctl addbr "$BRIDGE_IFACE"
        brctl addif "$BRIDGE_IFACE" "$gwdev"
        ip link set "$BRIDGE_IFACE" up
        ip addr add "$my_ip" dev "$BRIDGE_IFACE"
fi

# Move routes from physical iface to bridge
if test "$gwdev" != "$BRIDGE_IFACE"
then
        ip route list dev "$gwdev" | grep -v 'scope link' \
        | while read line; do
                ip route delete $line dev "$gwdev"
                ip route add    $line dev "$BRIDGE_IFACE"
        done
fi

# Add virtual iface to bridge
ip link set "$iface" up
brctl addif "$BRIDGE_IFACE" "$iface"

В различных руководствах рекомендуется настраивать мост заранее, редактируя /etc/network/interfaces, но для тестовых целей на рабочей станции проще создавать его в тот момент, когда он становится действительно нужен, т.е. в момент первого запуска первого контейнера.

Если во внешней сети недопустимо засвечивать дополнительные MAC-адреса, то вместо моста можно использовать маршрутизацию и ProxyARP. Если внешняя сеть разрешает ровно один MAC и один IP, тогда в базовой системе для выхода гостевых систем во внешний мир придётся использовать маршрутизацию, IP-адрес на внутренних интерфейсах и NAT. В обоих случаях потребуется либо настраивать в гостевых системах статические IP, либо настраивать в базовой системе DHCP-сервер для конфигурирования гостей.

MAC-адреса для гостевых сетевых интерфейсов KVM способен генерировать автоматически при старте, но если планируется выпускать гостей во внешний мир через сетевой мост, лучше назначить им постоянные MAC-адреса. В частности, если во внешней сети запущен DHCP-сервер, это поможет гостевой системе получать от него одинаковый IP при каждом запуске. Сначала «сочиним» базовый MAC-адрес:

perl -e '$XEN_RESERVED = "00:16:3e"; printf "%s:%02x:%02x:%02x\n", $XEN_RESERVED, int(rand(0x7f)), int(rand(0xff)), int(rand(0xff));'

Для контейнеров будем заменять последнее число на их порядковый номер. Этот же номер будем использовать для их имён и для VNC-консолей. Например, контейнер с номером 25 будет называться «kvm_25», иметь MAC 00:16:3e:xx:xx:25 и слушать VNC-подключения на порту 5925. Чтобы не огрести геморроя с разными системами счисления не иметь лишних проблем, рекомендуется выбирать номера от 10 до 99. Разумеется, такой подход не используется в VDS-хостинге, но для личных нужд он годится.

Установка виртуальной машины

1. Загружаемся с образа CD, инсталлируем ОС на пустой образ hdd, выключаем VM.
2. Редактируем сценарий запуска (отключаем CD), загружаемся с hdd, настраиваем в гостевой ОС поддержку virtio, выключаем VM.
3. Редактируем сценарий запуска (типы диска и сети меняем с IDE и Realtek на virtio), загружаемся.

Подготовка к загрузке FreeBSD

Скачиваем ISO-образ установочного диска FreeBSD:

wget http://mirror.yandex.ru/freebsd/releases/ISO-IMAGES/9.1/FreeBSD-9.1-RELEASE-i386-disc1.iso

Создаём образ жесткого диска:

kvm-img create -f qcow2 freebsd9.img 8G
kvm-img info freebsd9.img

Формат образа выбирается ключом «-f»: raw (default), qcow2, vdi, vmdk, cloop и т.д. Raw понятен любому ПО, но предоставляет минимум возможностей и сразу занимает максимально возможное место. Qcow2 компактнее (поддерживает динамическое увеличение размера) и функциональнее (поддерживает снимки, сжатие, шифрование и т.д.), но распознаётся только системами на основе QEMU.

Первый запуск и установка FreeBSD в ВМ

Сценарий для запуска ~/virt/freebsd9.start

#!/bin/sh

MACBASE="00:16:3e:33:28"
VM_ID=10
DIR=$HOME/virt

sudo kvm \
-net "nic,model=rtl8139,macaddr=$MACBASE:$VM_ID" \
-net "tap,ifname=tap$VM_ID,script=$DIR/kvm-ifup-bridge.sh,downscript=/bin/true" \
-name "kvm_$VM_ID" \
-enable-kvm \
-m 512M \
-hda $DIR/freebsd9.img \
-cdrom "$DIR/FreeBSD-9.1-RELEASE-i386-disc1.iso" \
-boot order=d \

## END ##

В открывшемся окне должны запуститься CD Loader и установщик FreeBSD. Выполняем установку обычным образом. Почти все параметры можно оставить по умолчанию.

Пояснения к команде запуска

Sudo необходим, т.к. для создания TAP-интерфейса KVM-загрузчику требуются права суперпользователя.

Два ключа «-net» создают два соединенных друг с другом сетевых интерфейса: TAP в базовой системе и виртуальный Realtek-8139 в гостевой.

Ключ «-enable-kvm» гарантирует, что QEMU не выберет автоматически режим программной эмуляции, если KVM не смог запуститься.

Ключ «-name» определяет заголовок консольного окна, может использоваться для поиска в списке процессов и т.д.

Загрузочным диском выбран CD («-boot order=d»). Опция имеет силу только при включении контейнера, т.е. при перезагрузке поиск системы начнётся с первого диска.

Ключ «-m» задаёт размер гостевого ОЗУ. По умолчанию — 128 мегабайт. Для работы установщика этого может быть достаточно, но уже после успешной установки первая же попытка собрать из портов большой проект при «-m 256M» и разделе подкачки на 512 мегабайт (размер автоматически выбран установщиком) вызвала kernel trap.

Загрузчик KVM работает как обычный пользовательский процесс, поэтому для выключения виртуальной машины достаточно просто нажать в консоли Ctrl+C (естественно, при запущенной гостевой ОС лучше этого не делать и пользоваться poweroff в гостевой консоли). Связь с системой виртуализации в ядре загрузчик осуществляет через символьное псевдоустройство /dev/kvm, поэтому запускать виртуальные машины может любой пользователь, имеющий право писать в него. Как правило, для таких пользователей в системе создаётся группа «kvm«.

Для запуска в фоновом режиме у загрузчика есть ключ «-daemonize«.

Второй запуск и настройка драйверов virtio

Перед запуском в сценарии freebsd9.start необходимо закомментировать строки «boot» и «cdrom«. Затем запускаем его и после завершения загрузки FreeBSD входим в её командную строку с правами суперпользователя.

Гостевые драйверы поддержки virtio для FreeBSD пока не включены в базовое ядро, а распространяются в виде порта, поэтому нам потребуется установить дерево портов:

portsnap fetch extract

Для сборки драйверам требуются исходные тексты текущего ядра:

csup -h cvsup2.ru.FreeBSD.org /usr/share/examples/cvsup/standard-supfile

После этого собираем и инсталлируем сами драйверы:

make -C /usr/ports/emulators/virtio-kmod install clean

В /boot/loader.conf обязательно должны быть добавлены следующие строки:

virtio_load="YES"
virtio_blk_load="YES"
virtio_pci_load="YES"
virtio_balloon_load="YES"
if_vtnet_load="YES"

Их можно скопировать из /var/db/pkg/virtio-kmod*/+DISPLAY. Если забудете — ядро FreeBSD вывалится при загрузке в приглашение «mountroot>», потому что не сможет увидеть дисковое устройство с корневой ФС. Потребуется перезагружаться, заходить в командную строку boot-менеджера и вручную загружать перед ядром эти модули командой «load».

В /etc/rc.conf надо вставить одну из двух строк:

ifconfig_vtnet0="DHCP"      # ..ifconfig_re0 можно удалить
ifconfig_vtnet0_name="re0"  # ..ifconfig_re0 надо оставить!

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

В /etc/fstab надо заменить все «/dev/ada» на «/dev/vtbd«. Если диск размечался установщиком автоматически, fstab станет таким:

# Device	Mountpoint	FStype	Options	Dump	Pass#
/dev/vtbd0p2	/		ufs	rw	1	1
/dev/vtbd0p3	none		swap	sw	0	0

Если забудете или неправильно отредактируете fstab — при следующей загрузке попадёте в приглашение «mountroot» и будете вынуждены вручную набирать в нём «ufs:/dev/vtbd0p2».

Что такое virtio и зачем он вообще нужен?

Если в контейнер предоставляется виртуальная копия реально существующего устройства (такого как сетевая карта Realtek или SCSI-диск), обращения к нему сначала проходят через драйвер устройства в гостевой системе. Драйвер преобразует высокоуровневые вызовы чтения-записи данных в низкоуровневые операции с прерываниями, регистрами, портами ввода-вывода и т.д. Их перехватывает система виртуализации и выполняет обратную работу — переводит в высокоуровневые вызовы для внешней системы (например, чтения-записи файла-образа диска).

Если в контейнер предоставляется устройство типа virtio, драйвер гостевой системы немедленно передаёт данные во внешнюю систему и обратно. Драйвер упрощается, низкоуровневая виртуализация физических ресурсов не требуется.

Пишут, что переход на virtio ускоряет в гостевой системе диск вдвое, а сеть почти на порядок.

Ещё одна интересная возможность virtio связана с динамическим выделением памяти для гостевой системы («ballooning«) и объединением блоков памяти с одинаковым содержимым (KSM, «Kernel Samepage Merging»).

VirtualBox и KVM используют совместимый механизм virtio, поэтому набор гостевых драйверов для них одинаковый. В Linux гостевые драйверы уже включены в стандартное ядро, для FreeBSD распространяются в виде порта (см.выше), для Windows написаны разработчиками KVM (см.тут).

Третий запуск

Меняем в ~/virt/freebsd9.start строки с указанием сетевого интерфейса и диска:

-net "nic,model=rtl8139,macaddr=$MACBASE:$VM_ID" \
-hda $DIR/freebsd9.img \

… на следующие:

-net "nic,model=virtio,macaddr=$MACBASE:$VM_ID" \
-drive "file=$DIR/freebsd9.img,if=virtio" \

Если загрузка FreeBSD пройдёт успешно, можете убедиться с помощью следующих команд, что виртуальные устройства теперь используются:

ifconfig
df; swapinfo
kldstat
dmesg | grep vt

Гостевая консоль

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

Для решения этой задачи KVM-контейнер может предоставлять доступ к гостевой консоли по сетевому протоколу VNC. В ~/virt/freebsd9.start вставьте в параметры запуска:

-vnc localhost:$VM_ID \

Теперь при запуске контейнера KVM откроет не графическое окно, а сетевое подключение. Увидеть его можно, например, командой «sudo netstat -ntlp | grep -w kvm«.

Установите клиентское приложение (например, tightvncviewer) и подключитесь к консоли:

apt-get install vncviewer
vncviewer :10

Примечание: если в окне VNC нет реакции на клавиатуру, кликните по нему.

VNC-соединение может быть защищено паролем, но назначить пароль непосредственно из командной строки, к сожалению, невозможно. Потребуется либо подключаться к управляющей консоли контейнера через отдельный управляющий сокет (краткое описание, как её настроить и как к ней подключиться), либо открывать её в основном VNC-окне нажатием Ctrl+Alt+Shift+2.

В дополнение к SDL и VNC, поддерживается текстовый интерфейс на базе curses (ключ «-curses» или «-display curses»). Теоретически он мог бы быть удобен для фонового запуска в screen. На практике KVM направляет в создаваемую консоль собственный диагностический мусор и делает её использование неудобным.

1 thought on “KVM — FreeBSD в виртуальной машине под Linux”

  1. По умолчанию KVM отрисовывает гостевую консоль в графическом окне с помощью библиотеки SDL.
    Помощи прошу.
    Поставил kvm на centos 7 минимальную. Создаю и запускаю виртуалку с 8 виндами:

    virt-install —connect qemu:///system —arch=x86_64
    —name VMwin81_10 -r 2048 —vcpus=2
    —boot=cdrom,hd,menu=on
    —disk path=/guest_images/vm_10.img,size=100,bus=virtio,cache=none
    —cdrom=/guest_images/distrib/ru_windows_8.1_enterprise_with_update_x86_dvd_6050840.iso
    —os-type windows
    —os-variant win8
    —network=bridge:br0,model=e1000

    Хочу, чтобы прямо тут, на локальном терминале сервера все открылось и произошло. Не происходит. Пишет:

    Domain installation still in progress. Waiting for installation to complete.

    и на этом все дело и останавливается. Виртуалка живет себе внутри где-то, наружу ни гу-гу. Пакет SDL.x86_64 установлен.

    Куда смотреть, что делать?

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *