OpenVZ

Материал из Национальной библиотеки им. Н. Э. Баумана
Последнее изменение этой страницы: 10:23, 28 июня 2016.
OpenVZ
Openvz logo vertical.png
виртуализация на уровне ОС
Разработчики: Сообщество, поддерживается Parallels
Постоянный выпуск:

Ядро:
2.6.32-042stab084.17 (стабильное)[1]
2.6.32-042stab113.5 (экспериментальное)[2]
vzctl — 4.6.1[3]

vzquota — 3.1[4]
Операционная система: Linux
Платформа: x86, x86-64, IA-64, PowerPC, SPARC, ARM
Тип ПО: виртуализация
Лицензия: GNU GPL v.2
Веб-сайт http://openvz.org/

OpenVZ[5] — это open-source реализация технологии виртуализации на уровне операционной системы, которая базируется на ядре Linux. OpenVZ позволяет на одном физическом сервере запускать множество изолированных копий операционной системы, так называемых контейнеров (Virtual Environments, VE).

Поскольку OpenVZ базируется на ядре Linux, в роли «гостевых» систем могут выступать только дистрибутивы GNU/Linux. Однако виртуализация на уровне операционной системы в OpenVZ дает также и многие преимущества, а именно: удобство в администрировании, плотное размещения виртуальных контейнеров в хост-системе (это обычно положительно отражается на стоимости VPS-хостинга) и несколько лучшую производительность по сравнению с технологиями полной виртуализации.

OpenVZ является базовой платформой для Virtuozzo — проприетарного продукта Parallels, Inc. OpenVZ распространяется на условиях лицензии GNU GPL v.2[6].

Архитектура[7]

Архитектура

OpenVZ разрабатывается[8] как патч (набор улучшений и дополнений) к исходным текстам ядра Linux. В модифицированном ядре добавлен массив дополнительных сущностей – виртуальных окружений (virtual environments, VE), а для всех имеющихся объектов (процессы, сокеты и т. д.) введены дополнительные поля – номер VE, к которому этот объект относится, и номер объекта внутри VE.

Каждое виртуальное окружение имеет собственный набор квот на потребление системных ресурсов и отдельный каталог для использования в качестве корневой файловой системы.

Дополнительные модули ядра – vzdev, vzmon и прочие – отвечают за работу ограничений, мониторинг, эмуляцию сети в VE, сохранение и восстановление текущего состояния запущенных контейнеров.

К преимуществам OpenVZ по сравнению с более универсальными инструментами виртуализации, такими как Xen и KVM, является прозрачный доступ из внешней системы к процессам, файлам и прочим ресурсам в гостевых. Например, если потребуется остановить во всех контейнерах сервис, в котором обнаружилась уязвимость, во внешней системе («хост-системе») достаточно выполнить команду «killall имя_исполняемого_файла».

Данный пример выводит номера (PID) всех процессов init с номерами контейнеров, в которых они запущены:

	# ps -A | grep -w init | awk '{print $1}' | xargs vzpid
	Pid    VEID    Name
	1         0    init
	6905     11    init
	7462     12    init

Процессы init, запущенные в контейнерах 11 и 12, внутри контейнеров, как им и положено, имеют PID 1, при этом в хост-системе они видны как PID 6905 и 7462. Номер контейнера, которому принадлежит процесс с указанным PID, сообщает утилита vzpid.

Структура каталогов

Ниже перечислены наиболее важные файлы и каталоги OpenVZ:

  • /etc/vz/vz.conf – файл с общими настройками;
  • /etc/vz/conf/*.conf – файлы с настройками контейнеров;
  • /var/lib/vz/private – каталог с корневыми файловыми системами контейнеров;
  • /var/lib/vz/root – каталог с точками монтирования корневых файловых систем запущенных контейнеров;
  • /var/lib/vz/template/cache – каталог для архивов с образами корневых файловых систем для заполнения создаваемых контейнеров;
  • /proc/user_beancounters – счётчики ограничений.

В тот момент, когда контейнер остановлен, его каталог в /var/lib/vz/root пуст, и редактирование данных следует производить в /var/lib/vz/private. Когда контейнер запущен, рекомендуется вносить изменения в .../root и ничего не менять в .../private. Синхронизация произойдёт автоматически.

В первых версиях OpenVZ каталог /var/lib/vz располагался в /vz, т.е. непосредственно в корневом каталоге. Некоторые описания рекомендуют создавать символьную ссылку с нового имени на старое («ln -sf /var/lib/vz /»), чтобы гарантировать правильность работы устаревших инструментов.

Также рекомендуется выносить /var/lib/vz/private на отдельный раздел, чтобы хост-система была лучше застрахована от нехватки свободного места на диске по вине одного из контейнеров.

Шаблон

Шаблон ("template cache") представляет собой tar.gz-архив с образом корневой файловой системы. Этот образ используется для заполнения файловой системы в контейнере при его создании, например:

	vzctl create 101 --ostemplate ubuntu-9.04-x86_64

Разные контейнеры можно создавать с разными шаблонами, и каждый шаблон может использоваться для инициализации любого количества контейнеров.

vzctl ищет шаблоны в каталоге /var/lib/vz/template/cache, добавляя к указанному в командной строке имени суффикс «.tar.gz». Готовые образы различных дистрибутивов можно скачать с веб-сайта download.openvz.org/template/precreated. Часть из них подготовлена разработчиками OpenVZ, часть (в подкаталоге contrib) – сообществом пользователей.

Отличия от файловых систем

Основные отличия [прим. 1] системы контейнера от файловой системы физического компьютера:

  • не нужны загрузчик и ядро – каталоги /boot и /lib/modules;
  • в /etc/init.d должны быть отключены все сервисы для управления оборудованием и ядром – udev, hal, hotplug, hdparm, consolesaver, consolefont и т. д.;
  • создание текстовых консолей getty в /etc/inittab должно быть закомментировано;
  • сетевые настройки – IP-адрес, gateway, hostname и т. д., задаваемые уже после создания контейнера – можно сделать пустыми.

При архивации файловой системы в шаблон желательно также очистить от ненужной информации каталоги /var/log, /var/spool, /var/cache и т. д.

Обновление шаблона

Обновление шаблона свежими версиями программного обеспечения должно происходить по следующей схеме (на примере обновления ALT Linux с 4.1 до 5.0):

  • создаётся и запускается новый контейнер:
	vzctl create 101 --ostemplate altlinux-4.1-x86_64
	vzctl start 101
  • в контейнере в /etc/apt/sources.list оставляется единственный файл branch50.list:
	rpm  [updates]   http://mirror.yandex.ru/altlinux/5.0/branch    x86_64 classic 
	rpm  [updates]   http://mirror.yandex.ru/altlinux/5.0/branch    noarch classic 
	#rpm [updates]   http://mirror.yandex.ru/altlinux/updates/5.0   x86_64 updates 
	#rpm [backports] http://mirror.yandex.ru/altlinux/backports/5.0 x86_64 backports
  • запускается обновление:
	vzctl enter 101 
	apt-get update
	apt-get dist-upgrade
	apt-get clean
  • удаляются файлы *.rpmnew (свежие варианты настроек, конфликтующие с изменёнными вариантами из шаблона) и *.rpmsave (старые настройки, не использующиеся в обновлённой системе)
  • контейнер останавливается, его каталог запаковывается в новый шаблон:
	vzctl stop 101
	tar -C /var/lib/vz/private/101 -czf /var/lib/vz/template/cache/altlinux-5.0-x86_64.tar.gz.

Конфигурации

Информация в данном разделе не требуется для практического использования в большинстве случаев, но будет полезной для общего понимания структуры OpenVZ.

Кроме файловой системы, создаваемому контейнеру назначается конфигурация. Как правило, «vzctl create» определяет её автоматически по имени файла-шаблона, но при необходимости можно указать её вручную параметром «--config». После создания контейнера имя его конфигурации хранится в его файле настроек (/etc/vz/conf/*.conf) – либо в строке «CONFIG=...», либо вычисляется по строке «OSTEMPLATE=...».

Конфигурации хранятся в каталоге /etc/vz/dists и содержат списки команд для управления настройками в системе, работающей внутри контейнера. Например, назначение IP-адреса для контейнера производится следующей командой:

	vzctl set 101 --ipadd 192.0.2.101

В зависимости от конфигурации, наряду с сохранением IP-адреса в /etc/vz/conf/11.conf, внутри запущенного контейнера будут выполнены следующие действия:

  • для Slackware: записать IP-адрес в файл /etc/rc.d/rc.inet1.conf и выполнить команду «/etc/rc.d/rc.inet restart»;
  • для Debian и Ubuntu: записать IP-адрес в /etc/network/interfaces и выполнить «/etc/init.d/networking restart»;
  • для ALT Linux: записать IP-адрес в /etc/net/ifaces/venet0/ipv4address и выполнить «ifup venet0».

Кроме перечисленных систем, готовые конфигурации имеются для Arch, Centos/Fedora/RHEL, Mandrake, SLES/OpenSUSE, Openwall, старых версий RedHat и SuSE. Конфигурация по умолчанию (dists/default) предназначена для систем от Redhat. Скелет для создания собственных конфигураций с подробными комментариями находится в dists/distribution.conf-template.

Доступ к устройствам

Из виртуальных окружений прямой доступ отсутствует и к железу, и к ядру. Каталог /dev почти пуст и содержит только логические устройства: null, zero, random, tty, console и т. д.

Сервисы, для работы которых требуется загрузка модулей ядра, смогут работать при выполнении трёх условий:

  • данный модуль загружен во внешней системе;
  • файл соответствующего устройства перенесён в /dev контейнера командой «vzctl set 11 --devnodes»;
  • модуль ядра во внешней системе и использующий его сервис в контейнере используют совместимые версии ABI («Application binary interface», «двоичный интерфейс для приложений»).

Если используемый в контейнере сценарий запуска сервиса в /etc/init.d пытается загружать необходимые сервису модули ядра с помощью команды modprobe, он не должен проверять результат загрузки ни через код завершения modprobe, так как modprobe завершится с ошибкой, ни с помощью команды lsmod, так как lsmod выведет пустой список.

Пример использования файловой системы

Рассмотрим пример использования файловой системы FtpFs внутри контейнера:

  • для организации доступа используется пакет curlftpfs, входящий в большинство дистрибутивов. Этот пакет должен быть инсталлирован внутри контейнера;
  • curlftpfs использует fuse (Filesystem in USErspace) для получения из ядра обращений к файловой системе, которые он преобразует в вызовы библиотеки curl для обращения к FTP-серверу;
  • Fuse состоит из двух компонентов: драйвер файловой системы в ядре и библиотека-диспетчер в пространстве пользователя, которой *драйвер передаёт все запросы;
  • драйвер и библиотека обмениваются данными через устройство /dev/fuse;
  • хотя программы и библиотеки запускаются внутри контейнера, драйвер и средства управления им должны быть инсталлированы в хост-системе;
  • каталог /dev в хост-системе и каталог /dev в контейнере – это разные каталоги; драйвер создаёт /dev/fuse в хост-системе и, чтобы /dev/fuse стал доступен в контейнере, требуется специальное указание.

Ограничения

OpenVZ ограничивает для контейнеров потребление всех системных ресурсов: процессора, оперативной памяти, дискового пространства, системных буферов, сокетов и т. д. Начальные лимиты настолько строгие, что даже команда «apt-get update» в только что созданном контейнере завершается с сообщением об ошибке.

Управление ограничениями

Управление ограничениями в системе с OpenVZ является двухуровневым: для контейнера в целом – средствами OpenVZ, внутри контейнера – стандартными средствами Linux, через ulimit и дисковые квоты.

Проверка

Для проверки внешних ограничений служит файл /proc/user_beancounters. Внутри контейнера этот файл заполнен информацией по данному контейнеру, во внешней системе содержит сведения обо всех запущенных окружениях. Основной интерес в нём представляет последний столбец, «failcnt» («failure counter», т. е. «количество сбоев»):

	egrep -v ' 0$' /proc/user_beancounters

Исправление

Примеры исправления:

	vzctl set 20 --save --privvmpages 250000:300000
	vzctl set 15 --save --numproc 200:200 --numfile 4096:4096

vzctl не полностью проверяет корректность вводимых аргументов (например, позволяет задавать разный лимит и барьер для таких параметров, как numproc и numfile, для которых лимит и барьер обязаны совпадать), поэтому рекомендуется проводить дополнительную проверку конфигурационных файлов с помощью утилиты vzcfgvalidate:

	for n in /etc/vz/conf/??.conf;do echo Check $n; vzcfgvalidate $n; done

Описание параметров[9]

Память

  • kmemsize - количество памяти, используемое ядром. Этот параметр связан со значением параметра numproc Каждый процесс потребляет некоторое количество памяти ядра: 30–50 килобайт, как минимум 16. Важно иметь достаточно большой зазор между пороговым и максимальным значениями, чтобы не вынуждать ядро завершать процессы, выполняющиеся в виртуальном окружении.
  • lockedpages - количество страниц памяти, заблокированной при помощи mlock.
  • privvmpages - объем памяти, размещаемой процессами. Память, разделяемая между разными процессами, не включается в это значение.
  • shmsize - объем памяти, доступный для межпроцессного взаимодействия через разделяемую память. Установка порогового значения, отличающегося от максимального, не имеет смысла.
  • physpages - объём физической памяти, используемое виртуальным контейнером. Используется только для учёта, пороговое значение должно быть выставленно в 0.
  • vmguarpages - гарантированный размер доступной памяти в страницах. Имеет смысл изменять только пороговое значение.
  • oomguarpages - пока использование памяти в страницах не превышает заданного порогового значения, процессы не будут принудительно завершены из-за недостка памяти даже при её реальной нехватке.

Процессы и файлы

  • numproc - количество процессов и обеспечиваемых ядром потоков. Установка порогового значения, отличающегося от максимального, не имеет смысла.
  • numflock - максимальное количество файловых блокировок. Рекомендуется оставлять зазор между пороговым и максимальным значениями.
  • numpty - количество псевдотерминалов. Не может превышать 255. Установка порогового значения, отличающегося от максимального, не имеет смысла.
  • numsiginfo - количество структур siginfo. Установка порогового значения, отличающегося от максимального, не имеет смысла.
  • dcachesize - максимальный размер кешей файловой системы (в байтах). Максимальное значение должно быть больше порогового.
  • numfile - максимальное количество открытых файлов. Установка порогового значения, отличающегося от максимального, не имеет смысла.

Сеть

  • numtcpsock - максимальное количество сокетов протокола TCP. Установка порогового значения, отличающегося от максимального, не имеет смысла.
  • tcpsndbuf - максимальный размер буферов для данных, отправляемых по протоколу TCP. Пороговое значение не должно быть меньше 64 Кб, а разница между ним и максимальным значением не должна быть меньше значения numtcpsock, умноженного на 2,5.
  • tcprcvbuf - максимальный размер буферов для данных, получаемых через протокол TCP. Пороговое значение не должно быть меньше 64 Кб, а разница между ним и максимальным значением не должна быть меньше значения numtcpsock, умноженного на 2,5.
  • othersockbuf - максимальный размер прочих (не TCP) буферов отправки. Увеличение лимита ускоряет связь через локальные сокеты.
  • dgramrcvbuf - максимальный размер прочих (не TCP) буферов получения. Установка порогового значения, отличающегося от максимального, не имеет смысла.
  • numothersock - максимальное количество не-TCP сокетов (локальных, UDP и других). Установка порогового значения, отличающегося от максимального, не имеет смысла.
  • numiptent - макисмальное количество записей в таблицах фильтрации сетевых пакетов (iptables).

Примечания

  1. Более детальное описание можно найти на сайте на сайте OpenVZ

Реквизиты

Перфильев Сергей Сергеевич, МГТУ им. Н.Э. Баумана, ИУ-8, e-mail:s.perfilev@bmstu.net

Литература