Статья для permlug.org (Пермской Группы Пользователей Линукс). http://www.permlug.org/node/4709/
Доброго времени суток. Вечер. 31 декабря 2008 года. Чем заняться человеку в такое время? Правильно! Начать писать статью на permlug, чтобы поделиться опытом. :)
Часть 1. Нелюбимый windows или с чего всё начиналось.
Сейчас братья-линуксоиды будут бить меня ногами и говорить, что мануалы по настройке чего-либо под win здесь не к месту. Сразу объяснюсь - пишу это для того, чтобы человек, которому приходится на работе пользоваться win, мог настроить виртуализацию и там и спокойно пользоваться одними и теми же образами виртуальных машин под различными платформами.
Преамбула: на работе стоял в стойке двухюнитовый сервер HP ML380 с четырнадцатью гигабайтами памяти и восемью скази дисками общим объёмом чуть менее терабайта (надо же, скоро эта единица измерения объёма информации станет совсем привычной, а ведь на полке где-то пылится с давних времён Seagate на 40 мегабайт :)). На этом сервере предыдущие админы догадались разместить расшаренные папки всей организации и внушительное количество всяческого барахла - дистрибутивы, драйвера и т.д.. И конечно же, на сервере стоит w2k3. Поставил snmp, подключил сервер к мониторингу и забыл о нём на какое-то время, поскольку дел было невпроворот. А потом внезапно вспомнил и решил посмотреть результаты. Результаты впечатляли. Средняя загрузка памяти - 1,6%, загрузка процессоров не поднималась выше трёх процентов. Причём гигабитным портом сервер был подключен к стомегабитному порту коммутатора, ибо больше некуда, а на гигабитный управляемый коммутатор, который можно было бы сделать центральным, начальство разоряться не хочет. В то же время, мне постоянно не хватало на работе машин, на которых можно что-то потестировать, опробовать и проверить, поэтому я решил устроить серверу размножение личности, благо, вычислительных ресурсов у него на это хватает с лихвой. Был проведён разговор с начальством и получено "добро" на использование сервера в своих целях при условии, что это не помешает пользователям работать с расшаренными документами, ибо перенести этот объём информации просто некуда. При помощи нехитрой утилитки SequoiaView (аналог встроенной в Konqueror FSView), я пошарился по папкам пользователей и конечно же, обнаружил там среди документов музыку, фильмы, игры и прочую чепуху, которая к делу не относится. Проведя разъяснительную беседу с рядом пользователей и пригрозив им введением квот, я освободил себе около 200 гигабайт места. В принципе, вполне достаточно.
Итак, приступаем к боевым действиям.
Задача: получить средство быстрого создания и дублирования виртуальных хостов, которые могли бы находиться в той же сети.
Какой эмулятор выбрать? Все вокруг пользуются VmWare или на худой конец, VirtualBox'ом, но я всеми силами поддерживаю GPL и предпочитаю открытый софт, нежели просто Freeware, даже если работа с ним окажется несколько сложнее. Поэтому для меня вопрос был решён изначально. Я выбрал qemu. Но пользоваться qemu из командной строки не всегда возможно. Скажем, если на виртуальный хост поставлена w2k3, то для того, чтобы авторизоваться в системе, надо послать ей Ctrl+Alt+Del, но это сочетание клавиш перехватывает хост-система. Поэтому нам необходима некая оболочка, которая будет выполнять эти и ряд других функций, например, возможность поставить систему на "паузу" или сохранить её состояние. Под windows выбор был не так велик и в конце-концов, я остановился на Qemu Manager (
http://www.davereyn.co.uk/). Простенько и со вкусом. Есть вариант для установки и есть в zip архиве, который можно распаковать и носить с собой на флешке, например. При установке или первом запуске лучше включить инсталляцию kqemu, это позволит несколько ускорить работу эмулятора.
На возможностях программы я особо останавливаться не буду, всё просто и понятно. Главный вопрос, с которым мне пришлось столкнуться - как вывести машины в сеть. Дело в том, что для *nix систем этой информации в сети было море, а для win - нет.
Общий принцип - для того, чтобы виртуальная машина могла общаться по сети с хост машиной, нужен так называемый tap интерфейс (Traffic Accounting Protocol). Но глупая w2k3 в своём составе не имеет средств для создания tap интерфейсов и придётся поставить эти средства отдельно. Для этого нам понадобится дистрибутив OpenVPN, который можно найти тут:
http://openvpn.net/index.php/downloads.html. OpenVPN так же является свободной разработкой, о чём гласит надпись на их сайте "OpenVPN is Free Software released under the GNU/GPL License." При установке мы должны выбрать только TAP-Win32 Virtual Ethernet Adapter, убрав все остальные галочки. На вопросы о совместимости оборудования отвечаем "Всё равно продолжить". После окончания установки у нас появится новый сетевой интерфейс. Если windows русская, то она его назовёт "Подключение по локальной сети" + какой-то номер. Заходим в Панель управления > Сеть и подключения к Интернету > Сетевые подключения. Там видим ещё одно подключение (сетевой кабель не подключен). Подводим к нему мышь и во всплывающей подсказке мы должны увидеть что-то вроде TAP-Win32 Adapter V8. Нажимаем правой кнопкой мыши и выбираем пункт "Переименовать", после чего даём нашему тап интерфейсу для определённости имя tap0. Затем в Qemu Manager нажимаем на иконку с красным плюсом, вводим имя машины, задаём количество памяти и размер жётского диска. После чего нажимаем кнопку с надписью Create, переходим на вкадку Networking в правой части окна, дважды кликаем на строку VLAN0 User Networking и в выпадающем меню Network Type выбираем пункт Tap Networking. В появившейся строке VLAN0 Tap ID вводим имя нашего tap интерфейса. В данном случае tap0. Теперь необходимо объёдинить его с физическим интерфейсом. Заходим в Сетевые подключения, одиночным щелчком выделяем наш tap интерфейс и удерживая Ctrl выделяем физический интерфейс, потом на одном из них нажимаем правой кнопкой мыши и выбираем пункт "Подключение типа мост". Всё, наша виртуальная машина будет использовать нашу реальную сетевую карту для общения с сетью. В отличие от юникса нам понадобится две сетевых карты. Одна - для хост системы, другая для виртуальных машин. Так же, нам надо заранее создать столько tap интерфейсов, сколько виртуальных машин предполагается держать включенными одновременно. Добавить новый tap интерфейс можно запустив скрипт C:\Program Files\OpenVPN\bin\addtap.bat, после чего его нужно будет по аналогии переименовать в tap1. Привязать его к мосту можно в свойствах моста, просто отметив галочкой.
Часть 2. Любимый linux. Или чем всё закончилось.
Придя к выводу, что виртуальные машины - это часто очень удобно, я решил сделать дома себе ещё одну "платформу виртуализации". Так как память и жёсткие диски сейчас довольно дёшевы, я сделал себе новогодний подарок - 8Гб оперативной памяти и 2 жёстких диска по 640Гб с кешем 32Мб. Зачем так много? Я знаю, что хватило бы и меньшего, но это на "вырост". Итак, что нам необходимо - возможность запускать виртуальные машины, используя те же образы жёстких дисков, что и под win, которые находились бы в той же сети, что и наша машина, другими словами, реализовать то же самое, что мы уже рассмотрели выше, только средствами linux.
Сейчас моя машина работает под 64-х битной Ubuntu 8.10.
Для начала нужно установить два пакета - quemu и qemuctl, которые есть практически в любом дистрибутиве.
Под дистрибутивами, основанными на debian это можно сделать, дав комманду
sudo apt-get install qemu qemuctl.
Первый из пакетов - это собственно сам эмулятор, второй - средство для управления им, которое потребуется нам например в случае необходимости послать эмулятору Ctrl+Alt+Del. Синтаксис параметров запуска qemuctl полностью совпадает с таковым для qemu.
Предположим, образ жёсткого диска для виртуальной машины называется disk.dsk и лежит в директории, из которой происходит запуск и мы хотим выделить машине 256 мегабайт оперативной памяти. Команда будет выглядеть так:
qemuctl -hda disk.dsk -m 256
Этого будет вполне достаточно. Теперь мы сможем передавать нашей виртуальной машине различные нажатия сочетаний клавиш, делать скришноты, останавливать работу машины и т.д..
Теперь вернёмся к вопросам работы с сетью. Сразу оговорюсь, что мой способ несколько отличается от тех, что я видел в сети.
Нам нужно создать так называемый мост (объединение интерфейсов на канальном уровне), после чего для каждой виртуальной машины создавать виртуальный tap интерфейс и объединять его с мостом. В отличие от windows, где нам приходилось создавать для каждой виртуальной машины новый tap интерфейс от имени администратора, в linux есть возможность этот процесс автоматизировать и создавать tap интерфейсы автоматически для каждой новой виртуальной машины, а после завершения её работы удалять соответствующий интерфейс. Конечно, для этих действий так же необходимы права супер пользователя, но мы решим эту проблему при помощи sudo. Далее необходимо будет произвести ряд действий от имени суперпользователя, поэтому можно воспользоваться командами
sudo -s либо
su -.
Сначала установим пакет bridge-utils, который позволит нам работать с соединениями типа мост.
apt-get install bridge-utils
Ещё в нашей системе должны иметься средства для работы с tun/tap интерфейсами. Обычно это tunctl, но в моей системе (ubuntu 8.10) он почему-то назывался vde_tunctl. Вы можете это проверить следующим образом:
locate tunctl
/usr/bin/vde_tunctl
/usr/share/man/man8/vde_tunctl.8.gz
В случае, если у Вас этот исполняемый файл называется tunctl, укажите его в скриптах вместо vde_tunctl.
Далее нам необходимо создать мост. Делается это примерно следующим образом:
Сначала наш физический интерфейс должен быть поднят без адреса
ifconfig eth0 down
ifconfig eth0 0.0.0.0 up
Затем мы должны создать новый мост, добавить физический интерфейс к созданному мосту и поднять мост с теми же настройками, какие имел физический интерфейс, всё довольно просто
brctl addbr br0
brctl addif br0 eth0
ifconfig br0 192.168.1.1 up
либо если машина получает адрес через DHCP
ifconfig br0 up
dhclient br0
В debian-based дистрибутивах настройки интерфейсов находятся в файле /etc/network/interfaces. Если мы рассчитываем работать с виртуальными машинами постоянно, то будет целесообразно внести настройки в него, чтобы они остались после перезагрузки системы.
Для определённости возьмём тот же пример, когда интерфейс сетевой карты называется eth0 и имеет адрес 192.168.1.1 или получает его посредством обращения к DHCP. Тогда содержимое файла /etc/network/interfaces будет примерно следующим:
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet static
address 192.168.1.1
netmask 255.255.255.0
в случае, если ip адрес был задан статически или
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet dhcp
если адрес был получен посредством DHCP.
Вот на что мы должны заменить содержимое:
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet static
address 0.0.0.0
auto br0
iface br0 inet static
address 192.168.1.1
netmask 255.255.255.0
bridge_ports eth0
bridge_fd 9
bridge_hello 2
bridge_maxage 12
bridge_stp off
либо в случае с DHCP
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet static
address 0.0.0.0
auto br0
iface br0 inet dhcp
bridge_ports eth0
bridge_fd 9
bridge_hello 2
bridge_maxage 12
bridge_stp off
Теперь у нас есть мост, к которому мы можем добавлять любые интерфейсы в нашей системе. Для добавления и удаления tap интерфейсов мы напишем пару скриптов, которые будут выполняться до старта виртуальной машины и после окончания её работы.
Я обычно использую в своей работе vim, Вы можете воспользоваться тем, что привычнее Вам, скажем, nano или mcedit. Следующая комманда откроет текстовый редактор и после сохранения создаст файл /usr/sbin/tapup:
vim /usr/sbin/tapup
Ниже содержимое скрипта:
#!/bin/sh
#Script for creating new tap interface and appending it to the existing bridge
#Usage: tapup [ UID_of_interface_owner ]
#(c) Evgeniy Shumilov (corpse@permlug.org)
if [ -n "$1" ]; then
if [ -n "$2" ]; then
iface=$( vde_tunctl -b -u $2 )
else
iface=$( vde_tunctl -b )
fi
chown root:qemu /dev/net/tun
/sbin/ifconfig $iface 0.0.0.0 promisc up
brctl addif $1 $iface
echo $iface
sleep 2
fi
Скрипт вызывается с двумя параметрами, первый из которых - имя интерфейса нашего моста, в нашем случае, это br0, а второй - имя пользователя, который будет владельцем созданного интерфейса и сможет впоследствии с ним работать. Например вызов /usr/sbin/tapup br0 user создаст tap интерфейс tap0, владельцем которого будет user и привяжет его к мосту br0. При повторном вызове будет создан интерфейс с именем tap1, при следующем - tap2 и т.д.. Первый параметр является обязательным, а второй можно опустить. При этом владельцем интерфейса будет root. C испоьзованием этого скрипта можно будет привязывать tap интерфейсы к различным мостам, что довольно удобно, если наша машина имеет несколько сетевых карт или несколько vlan интерфейсов, естесственно, для этой возможности каждый из них должен входить в состав какого-нибудь моста. При успешном выполнении скрипт выдаёт имя созданного интерфейса, нам это будет нужно.
Движемся далее. Создадим скрипт для удаления существующего интерфейса.
vim /usr/sbin/tapdown
Его содержимое:
#!/bin/sh
#Script to negate tap interface
#Usage: tapdown
if [ -n "$1" ]; then
vde_tunctl -d $1
fi
Здесь всё просто. tap интерфейс удаляется по имени, имя - это единственный и обязательный параметр. Не забудьте изменить vde_tunctl на tunctl, если он называется так в Вашей системе.
Теперь создадим группу, которая будет иметь право работать с qemu.
addgroup qemu
Перейдём в папку /usr/sbin и изменим владельца и права на наши скрипты:
cd /usr/sbin/
chown root:qemu tapup tapdown
chmod 750 tapup tapdown
chmod +s tapup tapdown
Проверяем, что получилось
ll tap*
-rwxr-x--- 1 root qemu 125 2009-01-01 16:00 tapdown
-rwxr-x--- 1 root qemu 403 2009-01-01 15:45 tapup
Редактируем файл /etc/sudoers и добавляем в него следующие строки:
%qemu ALL=NOPASSWD:/usr/sbin/tapup *
%qemu ALL=NOPASSWD:/usr/sbin/tapdown *
Теперь добавляем пользователя, которому нужно будет работать с виртуальными машинами в группу qemu:
adduser user qemu
Теперь, если Вы внесли изменения в /etc/network/interfaces, необходимо перезапустить службу
/etc/init.d/networking restart
Проверяем, что получилось:
ifconfig
br0 Link encap:Ethernet HWaddr 00:11:22:33:44:55
inet addr:192.168.1.8 Bcast:192.168.1.255 Mask:255.255.255.0
inet6 addr: fe80::21b:fcff:fe8c:a2a6/64 Диапазон:Ссылка
ВВЕРХ BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:134759 errors:0 dropped:0 overruns:0 frame:0
TX packets:72278 errors:0 dropped:0 overruns:0 carrier:0
коллизии:0 txqueuelen:0
RX bytes:174331133 (174.3 MB) TX bytes:6743605 (6.7 MB)
eth0 Link encap:Ethernet HWaddr 00:11:22:33:44:55
inet6 addr: fe80::21b:fcff:fe8c:a2a6/64 Диапазон:Ссылка
ВВЕРХ BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:134763 errors:0 dropped:0 overruns:0 frame:0
TX packets:72284 errors:0 dropped:0 overruns:0 carrier:0
коллизии:0 txqueuelen:1000
RX bytes:176221131 (176.2 MB) TX bytes:7036251 (7.0 MB)
Прервано:252 Base address:0x2000
lo Link encap:Локальная петля (Loopback)
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Диапазон:Узел
ВВЕРХ LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:37 errors:0 dropped:0 overruns:0 frame:0
TX packets:37 errors:0 dropped:0 overruns:0 carrier:0
коллизии:0 txqueuelen:0
RX bytes:2876 (2.8 KB) TX bytes:2876 (2.8 KB)
Затем входим под логином пользователя user, желательно это сделать не в иксах, а в одной из консолей, которые доступны по сочетанию клавиш Ctrl+Alt+F1 - Ctrl+Alt+F6 и проверяем, как работают наши скрипты:
sudo /usr/sbin/tapup br0 user
tap0
sudo /usr/sbin/tapdown tap0
Set 'tap0' nonpersistent
Всё замечательно. Пользователи, входящие в группу qemu ограничены в правах для работы с tunctl (vde_tunctl) и brctl напрямую, но имеют возможность работать с мостами и tap интерфейсами в той мере, в которой это необходимо для вывода в сеть виртуальных машин.
Теперь нам нужно ещё два скрипта. qemu, во всяком случае тот, что находится в репозитории ubuntu 8.10 при старте сети с поддеркой tap интерфейса выполняет скрипт /etc/qemu-ifup, без которого виртуальная машина просто не запустится. Поэтому на его место мы выложим заглушку - скрипт, который ничего не делает.
echo "#!/bin/sh" > /etc/qemu-ifup
При завершении работы тоже должен исполняться скрипт - /etc/qemu-ifdown, но при его отсутствии в поток ошибок, который при старте скрипта запуска не из консоли Вы просто не увидите, может выдаваться ошибка. Думаю, это не существенно.
Теперь всё готово. Пишем последний скрипт, который будет запускать нашу виртуальную машину.
#!/bin/bash
IFACE=$(sudo /usr/sbin/tapup br0 user )
qemuctl -m 256 -net nic -net tap,ifname=$IFACE -hda disk.dsk
sudo /usr/sbin/tapdown $IFACE
Теперь если на стороне виртуальной машины при настройке сети указать ip адрес из того же диапазона, что и на хост-машине, то они смогут друг-друга видеть.
Примечание: так как по умолчанию qemu эмулирует хоть и довольно распространённую в своё время, но уже довольно старую сетевую карту Realtek на базе чипа rtl8029, которую Windows 2003 уже не знает и драйвера на которую для этой операционной системы я так и не смог поставить, как ни бился, то для корректной работы с сетью стоит указывать другой тип сетевого адаптера. Например, rtl8139. Тогда строка запуска будет выглядеть следующим образом:
qemuctl -m 256 -net nic,model=rtl8139 -net tap,ifname=$IFACE -hda disk.dsk