Запускаем 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, работающий намного медленнее.
Настройка сети для виртуальных машин
Для реального применения лучше всего подходят два варианта:
- базовая система предоставляет гостевым прозрачный доступ во внешнюю сеть через т.н. сетевой мост («network bridge»),
- базовая система работает как маршрутизатор между внешней и гостевой сетью («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 направляет в создаваемую консоль собственный диагностический мусор и делает её использование неудобным.
По умолчанию 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 установлен.
Куда смотреть, что делать?