…Яйцо в утке, утка в зайце…
⇡#Столь необычный на первый взгляд комбайн сделать самому не так уж сложно. В качестве примера мы рассмотрим работу контейнеров LXC с Ubuntu в ВМ VirtualBox (мы с ней уже сталкивались ранее), запущенной в Windows или Mac OS X. Если у вас есть отдельная машина с Ubuntu на борту, можно проделать то же самое без установки виртуальной машины. То, чем мы будем заниматься, называется виртуализацей на уровне ОС. Фактически у нас будет как бы много-много физических серверов с Linux, с которыми можно работать точно так же, как и с обычными — настраивать, устанавливать свой софт и так далее. А в реальности, как мы понимаем, всё это хозяйство будет работать всего лишь на одном компьютере.
Пригодится подобная схема в первую очередь для более подробного знакомства с контейнерной виртуализацией. На практике похожие решения используются, например, хостинг-провайдерами, для отладки будущих распределённых сервисов, для изоляции отдельных приложений путём запуска не вместе со всеми, а в отдельном контейнере. В общем, применений масса. Вплоть до организации «выделенного» сервера под эксперименты разработчиков, студентов или сотрудников. Условный недостаток этой системы — невозможность виртуализации иных ОС, кроме Linux. А главное преимущество — достаточно высокая скорость работы виртуализированной ОС и возможность одновременного запуска большого числа контейнеров.
⇡#Подготовка
Для реализации данной задачи нам понадобится ПК с Windows или Mac OS X. Естественно, что чем мощнее будет процессор и чем больше оперативной памяти, тем быстрее всё будет работать внутри виртуальной машины. Также обязательные условия — поддержка процессором аппаратной виртуализации (Intel VT-x/AMD-V) и доступ в Интернет. Скачайте и установите свежую версию VirtualBox. Ещё нам понадобится ISO-образ Ubuntu Server 11.10, который можно найти здесь. Совсем ленивые могут скачать образ уже установленной системы и воспользоваться им.
Итак, запускаем VirtualBox и приступаем к созданию новой виртуальной машины. В качестве гостевой системы указываем Ubuntu и выделяем память, сколько не жалко. Только не переусердствуйте — основной ОС она тоже нужна. Затем с помощью мастера создаём новый динамический виртуальный диск нужного объёма. Раз уж он динамический, то можно задать объём хоть в 100 Гбайт — реально он будет занимать ровно столько места, сколько нужно под данные, хранящиеся на нём.
Теперь надо немного изменить настройки виртуальной машины — отключить ненужное вроде эмуляции звуковой карты и убедиться, что всё нужное включено. Не забываем подключить к виртуальному CD-ROM ISO-образ Ubuntu. Для пущего быстродействия можно отдать машине больше одного ядра физического процессора, включив попутно IO-APIC.
Важный пункт — настройка сети. Один из адаптеров будет внешним, и его надо настроить как NAT или мост к физической сетевой карте. Через него будет получать доступ в Сеть гостевая система и контейнеры. Для второго адаптера надо выбрать режим работы «Виртуальный адаптер хоста» и обязательно указать «Разрешить всё» в списке «Неразборчивый режим».
Всё, теперь можно запустить виртуальную машину и приступать к установке Ubuntu Server. Подробно останавливаться на этом процессе мы не будем, так как ничего сложного в нём нет. Да и поломать что-то вам вряд ли удастся. В случае неудачи всегда можно пересоздать ВМ и начать всё с нуля.
Скриншоты помогут определиться с настройками. Имя сервера можно выбрать любое, как и имя пользователя с паролем. Разбивку диска лучше оставить на плечах установщика, отказавшись от LVM и шифрования. Домашнюю папку также надо оставить незашифрованной и не забыть включить автоматическое обновление, а на последнем этапе снять галочки со всех наборов ПО. В общем, по возможности облегчить систему.
После перезагрузки войдите в систему под логином и паролем, которые были заданы во время установки. Тем патриотам, кто выбрал русский язык в качестве системного, придётся проделать ещё пару вещей. В консоли надо выполнить команду
sudo apt-get install console-cyrillic
и отредактировать файл /etc/rc.local, в котором надо добавить ещё одну строку перед exit0 и вписать в неё команду cyr. Её же надо будет выполнить после редактирования и сохранения файла (Ctrl+X, Y, Enter).
sudo nano /etc/rc.local
Обновим систему и установим необходимый минимум пакетов.
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install dkms build-essential bridge-utils lxc
Ещё необходимо установить дополнения VirtualBox в Ubuntu. Выбираем в меню «Устройства» → «Установить дополнения гостевой ОС…». В консоли вводим пару команд и ждём, пока соберётся модуль для нашего ядра.
sudo mount /dev/cdrom /media/cdrom
sudo /media/cdrom/VBoxLinuxAdditions.run
Осталось только настроить сетевые интерфейсы в файле /etc/network/interfaces.
sudo nano /etc/network/interfaces
Его надо привести к такому виду:
auto lo
iface lo inet loopback
auto br0 iface br0
inet dhcp
bridge_ports eth0
bridge_fd 0
auto br1
iface br1 inet static
address 192.168.56.2
netmask 255.255.255.0
bridge_ports eth1
bridge_fd 0
Интерфейс br0 смотрит наружу и получает по DHCP параметры сети, а br1 предназначен для использования только внутри виртуального окружения. Для удобства мы задали последнему статический IP-адрес из диапазона 192.168.56.XXX, который по умолчанию используется внутри VirtualBox.
Сохраняем файл (Ctrl+X, Y, Enter) и перезагружаемся.
sudo reboot
⇡#Работа с контейнерами LXC
Первым делом надо на всякий случай проверить, всё ли готово для работы с LXC-контейнерами с помощью команды lxc-checkconfig. Напротив каждого пункта в её выводе должно стоять значение enabled.
Теперь приступим к созданию первого контейнера, который потом можно будет клонировать для упрощения настроек сколько угодно раз. На его создание уйдёт порядка пяти минут и полугигабайта дискового пространства. Мы будем создавать контейнер с Ubuntu, но можно выбрать и другой. По умолчанию есть шаблоны для Ubuntu (ubuntu), Fedora Core (fedora), Debian (debian), OpenSUSE (opensuse) и некоторых других. Параметру name передаётся имя контейнера (в примере мы везде будем использовать vmh1, но можно выбрать и своё), а в template — имя шаблона, если таковой используется.
sudo lxc-create --name vmh1 --template ubuntu
Для некоторых шаблонов доступны дополнительные параметры. Посмотреть их для Ubuntu можно так:
sudo lxc-create --template ubuntu --help
Вся файловая система контейнеров фактически находится в каталоге /var/lib/lxc/имя_контейнера/rootfs (а значит, мы можем легко монтировать туда папки с опцией bind). Там же находится и конфигурационный файл config, в котором описаны все параметры. В принципе, параметры и файлы можно на лету менять с хост-машины, но это не всегда безопасно. Кстати, шаблонами пользоваться совсем необязательно. Практически для каждого популярного дистрибутива можно найти пример оформления config-файла или же создать его самому. В нашем случае надо добавить информацию о сетевых интерфейсах для только что созданного контейнера.
sudo nano /var/lib/lxc/vmh1/config
В конец файла необходимо добавить следующие строки:
lxc.network.type = veth
lxc.network.flags = up
lxc.network.link = br0
lxc.network.name = eth0
lxc.network.ipv4 = 10.0.2.201/24
lxc.network.type = veth
lxc.network.flags = up
lxc.network.link = br1
lxc.network.name = eth1
lxc.network.ipv4 = 192.168.56.201/24
Из названия сетевых переменных в общем-то ясно, за что они отвечают. Тип veth выбирается при использовании сетевого моста, флаг up даёт команду на поднятие сетевого интерфейса при старте контейнера, в link прописывается используемый интерфейс хост-машины, а в name — имя адаптера внутри контейнера. В примере прописано два интерфейса. Один для выхода в Сеть, второй для обмена данными между контейнерами и хост машиной. IP-адрес прописывается вручную из выбранных выше диапазонов, чтобы потом не выяснять, как подключиться к тому или иному контейнеру. Внутри самого контейнера править сетевые настройки не требуется.
Раз уже LXC использует механизмы cgroups, то можно использовать в конфигурационном файле множество различных параметров. В примере выше мы задали следующие ограничения: memory.limit_in_bytes — максимальный объём памяти для контейнера, memory.memsw.limit_in_bytes — максимальный размер подкачки (swap), cpuset.cpus — доступные процессоры/ядра (первый и третий, в VirtualBox мы указали использование трёх ядер). Параметр cpu.shares чуть хитрей. Если у одного контейнера он принимает значение x, а у второго 2x, то в каждый конкретный промежуток времени второй получит в два раза больше процессорных циклов, чем первый. Остальные параметры можно посмотреть, пролистав каталог /sys/fs/cgroup либо просто поискав документацию в Сети.
lxc.cgroup.memory.limit_in_bytes = 512M
lxc.cgroup.memory.memsw.limit_in_bytes = 1G
lxc.cgroup.cpu.shares = 1024
lxc.cgroup.cpuset.cpus = 0, 2
Впрочем, оставим эти эксперименты на потом, а пока проверим работоспособность контейнера, запустив его указанной ниже командой. Для отладки можно добавить параметры --logfile /путь/до/log-файла и --logpriority DEBUG. В случае неудачи просмотр логов поможет разобраться, что же именно не так.
sudo lxc-start --name vmh1
Если всё нормально, то через несколько секунд контейнер заработает и выдаст приглашение для входа в консоль. По умолчанию логин и пароль совпадают и равны root. Лучше сразу же создать нового пользователя без root-полномочий, а заодно проверить работоспособность сети — например, пропинговать хост-машину (у нас в примере это была 192.168.56.2) и какой-нибудь домен в Интернете. Возможно, придётся прописать хотя бы один IP-адрес DNS-сервера в файле /var/lib/lxc/имя_контейнера/rootfs/etc/resolv.conf, да и вообще настроить ОС в контейнере под свои нужды.
adduser username
После того как все настроено и проверено, контейнер можно остановить. Лучше всё-таки выполнить внутри него что-нибудь в духе
sudo shutdown -h now
Но можно и из консоли хост-машины принудительно остановить его.
sudo lxc-stop --name vmh1
Чтобы запустить контейнер в фоновом режиме, надо добавить к команде lxc-start параметр --daemon (-d). В этом случае подключиться к консоли контейнера можно командой lxc-console с указанием имени контейнера, а отключиться последовательным нажатием клавиш Ctrl+A и Q. Полезно узнать ещё пару команд. lxc-info показывает текущее состояние контейнера, а lxc-freeze «замораживает» его — при последующем размораживании (команда lxc-unfreeze) будет полностью восстановлено его состояние до заморозки (процессы, содержимое памяти и так далее).
Проще всего для изучения команд lxc ввести в консоли lxc- и нажать Tab — вы увидите все доступные команды. Каждую из них можно запустить с ключом --help и посмотреть доступные параметры. Впрочем, в Сети документации тоже полно. Напоследок мы склонируем наш, пока что единственный, контейнер во второй, с именем vmh2. Не забудьте в конфигурационном файле новой копии поменять как минимум IP-адреса. Для удаления любого контейнера воспользуйтесь командой lxc-destroy.
lxc-clone -o vmh1 -n vmh2
В дальнейшем можно клонировать готовую конфигурацию сколько угодно раз и выстраивать свой виртуальный кластер. Для автоматического запуска контейнеров надо поместить их конфигурационные файлы с расширением .conf в папку /etc/lxc. Проще сделать символическую ссылку. Также в файле /etc/default/lxc надо раскомментировать строку RUN=yes.
sudo ln -s /var/lib/lxc/vmh1/config /etc/lxc/auto/vmh1.conf
sudo nano /etc/default/lxc
Заключение
Пожалуй, для базового знакомства с LXC этого материала будет достаточно. Остальное придётся осваивать самостоятельно, да и для описания всех возможностей и тонкостей работы LXC понадобилась бы не одна солидная статья. Помимо LXC для Linux существует и ряд других систем виртуализации уровня ОС — OpenVZ, Virtuozzo и Linux-VServer. Хотя бы одной из них мы наверняка коснёмся в будущих материалах. Но это потом, а пока позвольте откланяться и по традиции пожелать удачных экспериментов на виртуальных нивах.
Если Вы заметили ошибку — выделите ее мышью и нажмите CTRL+ENTER.