Содержание статьи
Виртуализация позволяет сделать работу системного администратора простой и логичной, снизить расходы на оборудование и вдохнуть новую жизнь в простаивающие сервера. Но если ты считаешь, что за все это приходится платить сложностью и запутанностью самой технологии, то эта статья как раз для тебя. Я покажу, что поднять сотню-другую виртуальных серверов не сложнее, чем настроить среднестатистический web-сервер.
Виртуализация так плотно вошла в нашу жизнь, что уже трудно представить себе пользователя, никогда не видевшего виртуальную машину собственными глазами. Сегодня виртуализация используется везде: для создания серверов в хостинг-компаниях, для изоляции небезопасных сетевых сервисов, для создания сети тонких клиентов, для тестирования программного обеспечения, драйверов, разработки операционных систем и многого-многого другого.
Сегодня существует множество технологий виртуализации, среди которых есть как простые виртуальные машины, используемые на ПК обычных пользователей, так и целые облачные инфраструктуры, позволяющие управлять десятками тысяч виртуальных машин, разбросанных по всему миру. Особое место среди них занимают так называемые «системы виртуализации уровня операционной системы » или, как их иногда называют сисадмины, «псевдовиртуальные машины».
Виртуализация уровня ОС
В отличие от «настоящих» виртуальных машин, которые программно воссоздают аппаратную начинку ПК, системы виртуализации уровня ОС виртуализируют операционную систему, позволяя как бы расщепить ее на несколько независимых друг от друга ОС.
Проще всего понять это на примере дистрибутива GNU/Linux. Грубо его можно разделить на два логических компонента: ядро, имеющее максимальные привилегии и управляющее всем оборудованием, и компоненты пространства пользователя, представляющие собой набор демонов, библиотек, систему инициализации, ПО и прочее, которые получают доступ к оборудованию через вызовы функций ядра (системные вызовы). В обычной ситуации все компоненты пространства пользователя работают в одном «контексте исполнения » или, говоря образным языком, находятся в одной комнате: они могут видеть друг друга, имеют доступ к одному дереву файлов, делят между собой оборудование и все остальные ресурсы. Использование прав доступа позволяет им вполне успешно сосуществовать, не нанося друг другу вреда, однако может наступить момент, когда кто-то начнет теснить остальных, а другой, найдя способ обхода прав доступа, захватит власть над операционной системой.
И даже если администратор успевает быстро среагировать и устранить сбой — коммуналка, в которой у каждого одинаковые права на все, не может быть самым удачным способом размещения хоть людей, хоть процессов операционной системы.
Для решения этой проблемы виртуализация уровня ОС позволяет создать множество контекстов исполнения, каждый со своим деревом файлов, собственными процессами, сетевым стеком, правами на доступ к оборудованию и так далее. Проще говоря, она делает из одной операционной системы — несколько независимых, каждая из которых может иметь различные права на ресурсы, наиболее подходящие в ее конкретном случае. Такая виртуализация выгодно отличается от «настоящих» виртуальных машин: она проще в настройке, легко масштабируется и накладывает совсем незаметный (около 1%) оверхед на скорость работы ОС. Серьезный недостаток у нее всего один: возможность исполнения операционных систем только одного типа.
Почему OpenVZ?
В мире UNIX существует много различных реализаций виртуализации уровня операционной системы. Одними из первых в свою ОС ее внедрили разработчики FreeBSD. Система получила название Jail («Тюрьма») и долгое время оставалась образцом для подражания в глазах разработчиков других открытых ОС, но в последнее время сдала позиции как наименее развитая в плане функциональности.
Наверное, лучшую реализацию системы создала компания Sun для операционной системы Solaris 10, однако Solaris Zones, равно как и сама ОС, не получила широкого распространения (кстати, мы писали о Solaris Zones в одном из предыдущих номеров журнала).
Многие разработчики неоднократно предпринимали попытки воссоздать обе реализации для Linux, и на сегодня в этой области сформировалось три заметных лидера. Во-первых, это развиваемая сообществом система Linux-VServer (о ней мы также уже писали). Во-вторых, это не так давно появившийся, но очень перспективный проект LXC (LinuX Containers), который отличается очень функциональной реализацией, а также тем, что использует в своей основе стандартные механизмы ядра Linux, а потому не требует накладывания каких-либо патчей и может быть развернут за считанные минуты. В-третьих, это наиболее функциональная и стабильная система виртуализации OpenVZ, выступающая в роли ядра коммерческой системы Virtuozzo, выпускаемой российской компанией Parallels.
Сегодня OpenVZ и Virtuozzo — это стандарт де-факто для систем виртуализации уровня ОC в Linux. Они используются на тысячах серверов по всему миру, а их разработчики находятся на одном из первых мест по количеству коммитов кода в ядро Linux. Кстати, основной плюс OpenVZ заключается в том, что ты всегда сможешь найти не только огромное количество других пользователей OpenVZ, которые ответят на твои вопросы, но и массу информации на русском языке.
Что умеет OpenVZ?
По сути, OpenVZ — это модифицированное ядро Linux, в которое добавлен слой виртуализации, построенный на концепции VE (Virtual Environment — виртуальной среды), которую мы будем называть более привычным для нас термином «контейнер».
Такое ядро может обеспечивать несколько контекстов исполнения. И даже если пользователь не собирается использовать эту возможность, ядро все равно создаст один контекст, называемый Hardware Node (или нулевой контейнер). Это основная хост-система, имеющая максимальные полномочия и права на ресурсы. Говоря простым языком — стандартное Linux-окружение.
В любой момент администратор нулевого контейнера может добавить в систему новый контейнер, назначив ему номер, имя, сетевой адрес, дав прямой доступ к нужному оборудованию (если это необходимо) и выделив нужное количество ресурсов, которые будут определять «мощность» виртуального сервера.
OpenVZ использует модифицированный планировщик процессов, который учитывает не только их приоритеты, но и то, в каком контейнере они исполняются. Это позволяет задать жесткое ограничение процессорного времени на каждый контейнер, не позволив ему полностью загрузить весь процессор, лишив возможности исполнения процессы других контейнеров.
Каждый контейнер OpenVZ получает собственный виртуальный сетевой интерфейс (venet или veth) и полноценный, полностью обособленный от нулевого контейнера, сетевой стек, обеспечивающий контейнер отдельными IP-адресом, таблицей маршрутизации и правилами брэндмауэра. Одной из важнейших возможностей OpenVZ является механизм так называемого «чекпоинтинга», позволяющий сохранить образ контейнера на жесткий диск и восстановить его работу с прерванного места. Более того, образ можно безболезненно перенести на другую машину и восстановить его работу уже на ней. Причем даже если в момент «заморозки » на адрес одного из сетевых сервисов контейнера придет запрос, он будет вполне успешно обработан после восстановления, а для клиента это будет выглядеть как обычная задержка в ответе (например, на открытие web-страницы ушла не доля секунды, а 5 секунд).
OpenVZ очень хорошо масштабируется. Одна физическая машина может с легкостью обслуживать несколько сотен не слишком требовательных к ресурсам контейнеров, и пользователи каждого из них даже не заметят каких-либо проблем с производительностью.
Ограничения
Помимо уже упомянутого ограничения на тип поддерживаемых ОС, которое вытекает из того факта, что все контейнеры работают на одном ядре Linux, у OpenVZ есть несколько более мелких, но заслуживающих внимания недостатков (справедливости ради следует отметить, что это проблема всех реализаций системы виртуализации уровня ОС). Во-первых, OpenVZ накладывает определенные ограничения на работу софта, который зависит от низкоуровневых функций ядра. Так, например, ядерный NFS, OpenVPN и IPSec внутри контейнера работать не будут.
Какие-то другие программы, зависимые от ядерных модулей, также откажутся правильно функционировать (хотя в некоторых случаях OpenVZ позволяет загрузить в контейнер модули).
О различных ядерных патчах тем более придется забыть раз и навсегда. Во-вторых, все контейнеры OpenVZ используют один дисковый своп, а это значит, что если оперативная память между контейнерами будет распределена неправильно, система может начать тормозить в самый неподходящий момент. К счастью, проблема решается с помощью разделения памяти таким образом, чтобы ее суммарный объем составлял не более 80-90% от общего количества. В-третьих, контейнеры OpenVZ используют один дисковый кэш, поэтому если какой-то контейнер начнет активно обращаться к жесткому диску, то он может заполнить весь кэш своими данными, и другим контейнерам придется долго ждать очереди, чтобы записать/прочитать данные с диска. В связи с этим я бы не рекомендовал использовать OpenVZ для «хостинга» серверов, активно работающих с диском (для таких задач вообще всегда рекомендуется использовать выделенный железный сервер).
Наконец, в-четвертых, OpenVZ использует очень неэффективный механизм ограничения контейнеров в количестве оперативной памяти. Вместо подсчета реально используемой приложениями контейнера памяти он считает количество выделенной памяти, и это придется учитывать при запуске приложений, запрашивающих большие количества памяти при запуске, но не использующих ее всю во время работы (например, так ведет себя всем известный memcached при дефолтовых настройках).
Установка
Являясь «системой уровня предприятия» и основой платного продукта Virtuozzo, OpenVZ в первую очередь рассчитана на применение в дистрибутивах линейки RHEL, поэтому официальные сборки OpenVZ-ядра доступны только для этого дистрибутива.
Неофициально же OpenVZ доступен в Debian, разработчики которого самостоятельно патчат и готовят ядро OpenVZ (пакет linux-openvz-i386 FIXME).
В Ubuntu ядра OpenVZ нет еще с версии 8.10, поэтому у его пользователей остается два способа установить OpenVZ на сервер: пропатчить и собрать ядро самостоятельно либо взять уже патченое ядро из Ubuntu 8.04. Для тех, кто считает последний подход бредовым, поясню: во-первых, стабильное OpenVZ-ядро на сегодняшний день до сих пор имеет номер версии 2.6.18, тогда как в Ubuntu 8.04 используется даже более свежее ядро 2.6.24; во-вторых, Ubuntu 8.04 является LTS-дистрибутивом, а значит, обновления безопасности для любых его компонентов будут выходить вплоть до 2013 года, что, на мой взгляд, вполне приемлемо. Итак, если мы имеем дело с RHEL, то OpenVZ можно установить из официального источника. Для этого необходимо добавить репозиторий openvz.org в yum:
# cd /etc/yum.repos.d
# wget http://download.openvz.org/openvz.repo
# rpm --import http://download.openvz.org/RPM-GPG-Key-OpenVZ
Отключить SELinux:
# echo 'SELINUX=disabled' > /etc/sysconfi g/elinux
И установить ядро и утилиты управления:
# yum install ovzkernel
# yum install vzctl vzquota
В Debian все просто, достаточно выполнить только одну команду:
$ sudo apt-get install vzctl vzquota
linux-openvz-i386
В Ubuntu сложнее. Сначала необходимо добавить репозиторий Ubuntu 8.04, для чего следует создать файл / etc/apt/sources.list.d/hardy-main.list и поместить в него следующие строки:
# vi /etc/apt/sources.list.d/hardy-main.list
deb http://mirror.yandex.ru/ubuntu hardy main
deb http://mirror.yandex.ru/ubuntu
hardy-updates main
deb http://mirror.yandex.ru/ubuntu
hardy-security main
Только после этого можно установить OpenVZ-ядро и утилиты:
$ sudo apt-get update
$ sudo apt-get install vzctl vzquota
linux-openvz
После установки в любом из трех дистрибутивов необходимо изменить некоторые настройки ядра, иначе OpenVZ будет работать некорректно. Открываем файл /etc/sysctl.conf и пишем в него следующее:
# vi /etc/sysctl.conf
net.ipv4.conf.default.proxy_arp = 1
net.ipv4.ip_forward = 1
net.ipv4.conf.all.rp_fi lter = 1
kernel.sysrq = 1
net.ipv4.conf.default.send_redirects = 1
net.ipv4.conf.all.send_redirects = 0
Перезагружаем машину и загружаемся уже с новым ядром. Чтобы запустить необходимые для правильной работы OpenVZ userspace-сервисы, набираем:
# /etc/init.d/vz start
Шаблоны ОС
Как уже было сказано выше, для каждого контейнера OpenVZ создает независимый контекст исполнения, который, за вычетом всего остального, имеет собственное файловое дерево, полностью обособленное от файловой системы нулевого контейнера. Поэтому перед тем как приступить к опробованию боевых качеств OpenVZ, мы должны подготовить набор файлов, которые будут формировать файловую систему для будущих контейнеров (так называемый шаблон).
Существует три способа это сделать:
- Скопировать файловое дерево из основной системы, что приведет к тому, что любой новый контейнер будет представлять собой копию существующей системы (нулевого контейнера).
- Взять существующий дистрибутив Linux и получить готовый шаблон, выбросив из него ядро, initramfsобраз и внеся несколько изменений.
- Скачать подходящий шаблон с сайта OpenVZ.
Мы пойдем по пути наименьшего сопротивления и воспользуемся третьим способом. Для этого переходим в каталог-хранилище шаблонов:
$ cd /var/lib/vz/template/cache
И скачиваем нужный шаблон с помощью wget:
$ sudo wget http://download.openvz.org/template/precreated/debian-5.0-x86.tar.gz
Весь список подготовленных шаблонов можно просмотреть, открыв страницу download.openvz.org/template/precreated в браузере.
Создаем контейнеры
Для управления OpenVZ используется несколько консольных утилит, наиважнейшая из которых носит имя vzctl. Она применяется для создания, удаления, запуска, остановки, а также изменения настроек контейнеров.
Любой сисадмин OpenVZ должен знать все ее параметры и опции назубок. Способ вызова утилиты следующий:
# vzctl команда номер_контейнера аргументы
Команда — это действие, которое должен выполнить OpenVZ, а аргументы уточняют или дополняют его.
Для создания контейнера используется команда create, для изменения параметров — set, для уничтожения — destroy. Также доступны команды enter, start, stop и restart, позволяющие «заходить» в контейнеры и управлять их работой.
Vzctl — очень гибкая утилита, с помощью которой можно создать и полностью настроить контейнер почти любой сложности, не затронув ни единого конфигурационного файла. Вот как это делается:
1. Сначала создаем новый контейнер с номером 100 (кстати, в качестве номера удобно использовать последнюю часть его IP-адреса):
# vzctl create 100 --ostemplate debian-5.0-x86
--confi g vps.basic
Здесь debian-5.0-x86 — это скачанный ранее шаблон без расширения tar.gz, а vps.basic — набор стандартных предустановок, которые мы все равно собираемся менять.
2. Меняем настройки контейнера так, чтобы он запускался при загрузке системы:
# vzctl set 100 --onboot yes --save
3. Меняем сетевое имя контейнера:
# vzctl set 100 --hostname my-fi rst-vps.org.ru --save
4. Даем ему новый IP-адрес:
# vzctl set 100 --ipdel all --ipadd 192.168.0.100 --save
5. Указываем дефолтный DNS-сервер:
# vzctl set 100 --nameserver 192.168.0.1 --save
6. Устанавливаем пароль пользователя root:
# vzctl set 100 --userpasswd root:password --save
7. Выделяем контейнеру 15% от общей мощности процессора (один процессор — это 100%, два — 200%, четыре — 400% и так далее):
# vzctl set 100 --cpulimit 15 --save
8. Выделяем контейнеру 20 Гб дискового пространства с возможностью его превышения до 25 Гб на небольшой промежуток времени:
# vzctl set 100 --diskspace 20G:25G --save
9. Устанавливаем ограничение на объем оперативной памяти (в первой строке устанавливаем гарантированный ресурс, во второй — негарантированный, он будет доступен контейнеру только в том случае, если в системе есть его излишек):
# vzctl set 100 --vmguarpages 256M:256M --save
# vzctl set 100 --privvmpages 512M:512M --save
10. Теперь можно войти в контейнер и продолжить настройку уже внутри него (установить необходимые сервисы, настроить брэндмауэр и маршрутизацию):
# vzctl enter 100
Более подробную информацию о настройке контейнеров можно почерпнуть из man-страницы vzctl.
UBC
В терминах OpenVZ лимиты и гарантии ресурсов называются User Beancounters (UBC). Всего существует около 20 UBC, контролирующих почти все возможные ресурсы системы. Каждый UBC имеет свою опцию в команде vzctl, а также строку в файле /proc/user_ beancounters, с помощью которого можно узнать о текущем количестве выделенных ресурсов и определить их нехватку. Файл представляет собой таблицу, каждая строка которой содержит информацию об одном ресурсе, а колонки отражают следующие данные:
Файл /proc/user_beancounters
- uid — идентификатор контейнера;
- resource — имя ресурса;
- held — текущая утилизация ресурса;
- maxheld — максимальный уровень утилизации ресурса за все время работы контейнера;
- barrier — максимальный уровень утилизации ресурсов, который может быть временно превышен;
- limit — жесткое ограничение утилизации ресурса, которое никогда не может быть превышено;
- failcnt — счетчик отказов, который увеличивается каждый раз, когда контейнер делает запрос ресурсов сверх своего лимита.
Не обязательно разбираться во всех тонкостях системы подсчета ресурсов OpenVZ, чтобы эффективно управлять контейнерами. Достаточно время от времени поглядывать на значение колонки failcnt и, если оно оказывается больше нуля, начинать предпринимать меры либо по оптимизации исполняемого в рамках контейнера софта, либо по увеличению количества выделяемых контейнеру ресурсов.
Выводы
Эта статья охватывает лишь малую часть того, что принято называть термином «виртуализация уровня ОС», но изложенной в ней информации вполне достаточно, чтобы начать применять технологию и двинуться дальше.
О настройке контейнеров
Самое замечательное в настройке OpenVZконтейнеров — это целостность инструментов. При необходимости система сама изменяет конфигурационные файлы дистрибутива, расположенного в контейнере, так, чтобы они соответствовали запрошенным. К примеру, настройка адреса DNS-сервера с помощью vzctl автоматически приведет к его добавлению в файл /etc/resolv.conf в файловой системе контейнера.
Такой уровень гибкости гораздо сложнее получить при использовании «классических» систем виртуализации.
Список OpenVZ-утилит
- vzlist используется для получения списка всех контейнеров;
- vzmigrate предназначена для осуществления offlineи online-миграции;
- vzcfgvalidate проверяет конфигурационные файлы на корректность;
- vzmemcheck, vzcpucheck, vzcalc осуществляют проверку на доступные ресурсы внутри контейнера;
- vzsplit автоматически генерирует конфигурационные файлы;
- vzpid определяет номер контейнера по PID’у процесса;
- vzquota управляет дисковой квотой контейнера.
Links
- Все, что нужно знать о UBC: wiki.openvz.org/UBC;
- Руководство по созданию шаблонов: http://goo.gl/h1gNL.
- О том, как производить чекпоинтинг: http://goo.gl/lZbzW.
- Как превратить физический сервер в виртуальный: http://goo.gl/sYtxF;
- Настройка I/Oприоритетов для контейнеров: http://goo.gl/YtjiV.
- Cписок панелей управления OpenVZ: http://goo.gl/KfEbB.
- OpenVZ Web Panel, одна из лучших web-панелей для управления OpenVZ: http://goo.gl/x7UlF.
- Настройка OpenVZ Web Panel: http://goo.gl/vx73u.
- Описание процесса установки OpenVZ в Ubuntu 10.04 с помощью сборки из исходников: http://goo.gl/XEaou.