Что такое Linux-VServer?
Vserver это расширение Linux-ядра позволяющее создавать виртуальные частные сервера (VPS).
Окружение VPS практически полностью идентично обычному Linux-серверу.
Центральная концепция Linux-VServer — Контекст Безопасности (Security Context).
Чем отличается от других технологий виртуализации?
Vserver в отличие от виртуальных машин (VM) не предоставляет абстракции аппаратного обеспечения.
Нет возможности запуска других гостевых ОС.
Высокая скорость и практически нулевой уровень дополнительных вычислительных затрат.
Большинство приложений не требуют доступа к аппаратному обеспечению и пользуются абстракцией предоставляемой операционной системой.
Концепция виртуализации Linux-VServer
Главная задача ядра Linux это предоставление ресурсов ЭВМ как абстракции для приложений.
Если у машины достаточно ресурсов для запуска десяти серверов почему бы не запустить их все одновременно?
Многие приложения написаны под конкретное окружение ОС (требования библиотек и т.д.) и совместная работа с прочими программами затруднена.
Linux-VServer позволяет с минимальными затратами реализовать иллюзию полноценного окружения Linux.
Что уже есть в ядре Linux?
Linux Capability System основана на POSIX Capabilities
Традиционная система привелегий в UNIX основана на принципе «всё или ничего». Суперпользователь имеет неограниченные права а обычный пользователь существенно в них ограничен.
Это не всегда удобно!
Capabilities - средство для гибкого назначения привилегий в системе.
Каждый процесс имеет три битовых поля (32 бита):
inheritable — маска permitted для процессов после exec(2). После fork(2) и clone(2) процесс получает точную копию битовых полей.
permitted — определяют разрешённые возможности для процесса вообще.
effective — определяют текущие эффективные возможности. Любая из них может быть отключена временно.
Детальный список битов можно найти в /usr/incluce/linux/capability.h.
[0]CAP_CHOWN | изменение владельца и группы-владельца файла |
[5]CAP_KILL | посылка сигнала процессу с другим реальным ID или эффективным ID |
[6]CAP_SETGID | разрешить setgid(2), setgroups(s) |
[8]CAP_SETPCAP | Установка и удаление любой возможности у любого pid |
[9]CAP_LINUX_IMMUTABLE | Разрешение модификации S_APPEND и S_IMMUTABLE атрибутов |
[11]CAP_NET_BROADCAST | Разрешена посылка и приём broadcast и multicast |
[12]CAP_NET_ADMIN | Разрешено конфигурирование файрвола, отладка сокетов, изменение маршрутных таблиц, вход в promiscuous mode и др. |
[13]CAP_NET_RAW | Разрешено использование RAW и PACKET сокетов |
[16]CAP_SYS_MODULE | Разрешена загрузка и выгрузка модулей ядра |
[18]CAP_SYS_CHROOT | Разрешено использование chroot(2) |
[19]CAP_SYS_PTRACE | Разрешено использование ptrace(2) |
[21]CAP_SYS_ADMIN | Много различных привилегий относящихся к задачам системного администрирования |
[22]CAP_SYS_BOOT | Разрешено использование reboot(2) |
[23]CAP_SYS_NICE | Разрешено модифицировать и устанавливать приоритеты у других процессов в т.ч. модифицирование планировщика |
[24]CAP_SYS_RESOURCE | Разрешено превышать квоты системы на дисковые ресурсы и память |
[27]CAP_MKNOD | Разрешено создание специальных файлов устройств |
Лимитирование ресурсов
Linux позволяет задать лимиты на системные ресурсы для каждого процесса. Каждый лимит имеет мягкий и жёсткий пределы.
Подробный список можно посмотреть в /usr/include/asm/resource.h.
Лимитируемые ресурсы.
[0] RLIMIT_CPU | Процессорное время в секундах, при превышении мягкого лимита посылается сигнал SIGXCPU, при превышении жёсткого лимита SIGKILL. |
[4]RLIMIT_CORE | Максимальный размер core файла |
[5]RLIMIT_RSS | Максимальный размер резидентной виртуальной памяти (страниц в RAM) |
[6]RLIMIT_NPROC | Максимальное количество дочерних процессов или нитей |
[7]RLIMIT_NOFILE | Максимальное количество открытых файлов |
[8]RLIMIT_MEMLOCK | Максимальное количество невыгружаемой памяти (страниц в RAM) выделенных mlock(2) или mlockall(2) |
[9]RLIMIT_AS | Максимальный размер адресного пространства (страниц) |
Файловые атрибуты
Ранее расширенные атрибуты файлов поддерживались только в ext2, однако в настоящий момент основные файловые системы поддерживают эти атрибуты:
s | SECRM | Файл с установленным атрибутом при стирании заполняется нулями |
u | UNRM | Файл при удалении сохраняет содержимое. |
c | COMPR | Файл автоматически сжимается при записи и разжимается при чтении. |
i | IMMUTABLE | Файл нельзя модифицировать, удалить или переименовать, создать ссылку и нельзя записать. |
a | APPEND | Файл может быть открыт только в режиме O_APPEND. |
d | NODUMP | Файл игнорируется утилитой dump. |
s | SYNC | Обновления в файл записываются синхронно. |
a | NOATIME | Атрибут atime файла не модифицируется. |
t | NOTAIL | Предотвращается совместное использование последнего блока файла вместе с другими файлами. |
d | DIRSYNC | Запись изменений в директорию осуществляется синхронно. |
Эти атрибуты можно установить и просмотреть с помощью утилит lsattr(1) и chattr(1).
Утилита chroot(1)
Утилита chroot(1) использует системный вызов chroot(2) который позволяет изменить корневой каталог для запускаемой программы. При всей своей привлекательности и простоте chroot(2) имеет недостатки, которые не позволяют использовать его в чистом виде для организации безопасной изоляции окружений.
Требуемые модификации в ядре
- Разделение и изоляция контекстов. Требует дополнительных данных для различения контекстов и описания ресурсов.
- Разделение сетевых ресурсов. Изменяется некоторым образом поведение при привязке к специальному адресу IPADDR_ANY.
- Помещение контекста в собственную корневую иерархию. Существуют методы «побега» из chroot(2) поэтому использовать его напрямую нельзя. Требуется хранение дополнительных данных в структуре данных корневого каталога иерархии.
- Capabilities и ограничения на контекст в целом.
- Изоляция ресурсов IPC, идентификаторов пользователей и групп, файлов псевдотерминала, сокетов и т.д.
- Тэгирование файлов XID (Context ID). В настоящее время используются биты в полях UID и GID для хранения XID.
- Дополнительные модификации для специальных возможностей Linux-VServer.
Linux-VServer помимо capabilities задаваемых для всего контекста имеет расширенные и более «тонкие» разрешения которыми можно манипулировать для каждого из контекстов.
- Разрешения контекста. Связаны с доступом к специфичным системным ресурсам, RAW_ICMP, SYSLOG, SECURE_MOUNT, BINARY_MOUNT и т.д.
- Флаги контекста, специфичные для Linux-VServer, задаются возможности виртуализации системной информации такой как информация о памяти, CPU, загрузке системы и т.д.
- Флаги сетевого контекста, параметры виртуализации сетевых ресурсов.
- Флаги системных возможностей унаследованных от Linux но задаваемых для контекста в целом.
Задать флаги для окружения очень просто:
# echo HIDE_NETIF >> nflags
Лимитирование ресурсов CPU
В Linux существует две концепции — нити и процессы. Нити позволяют создавать иллюзию одновременного параллельного выполнения программы. Каждый процесс или нить планируется на выполнение отдельно. На одном CPU в единицу времени может работать только один процесс или нить.
Современные операционные системы позволяют запускать множество одновременных процессов и нитей, создавая иллюзию одновременной работы — многозадачность.
Каждая нить или процесс планируются отдельно. Планировщик следит за тем чтобы процесс или нить не захватили процессор монопольно. Планировщик сам представлен в виде нити ядра которая пробуждается по прерыванию таймера. Планировщик может быть вызван процессом или нитью принудительно.
Ведро с маркерами
Ограничение ресурсов CPU осуществляется с использованием весьма популярной концепцией ведра с маркерами.
Существует ведро ёмкостью V маркеров. Через определённый интервал тиков J в ведро попадает T маркеров. В заполненное ведро маркеры не помещаются.
Главное преимущество ведра с маркерами — накопление ресурсов для покрытия кратковременных высоких нагрузок.
Самый простой вариант — жёсткое ограничение ресурсов CPU.
T - количество маркеров на интервал
J - интервал в jiffies
Это отношение определяет использование CPU данным контекстом. Если машина имеет 4 CPU то для того чтобы контекст в среднем получил один процессор нужно задать соотношение 1/4.
В некоторых случаях лучше лимитировать CPU после некоторого броска вычислительной нагрузки. В таком случае задаётся максимальное количество маркеров в ведре и минимально необходимое для повторного назначения ресурсов контекста на планирование после израсходования всех маркеров.
Пусть максимальный размер ведра будет Vmax а минимальный Vmin.
Время броска обозначим как tburst время штрафа через thold а интервал прерывания таймера через Hz.
Отсюда можно выразить необходимое минимальное количество маркеров для данного времени штрафования и интервала прерывания таймера.
Рассчитать нужное количество маркеров для броска тоже не сложно. Составим простое и достаточно очевидное уравнение.
Где V0 - текущее количество маркеров в ведре или искомое максимальное количество маркеров,V(t)in - количество маркеров наполняющих ведро а V(t)out количество маркеров, которые изымает планировщик при каждом тике у активного контекста. Нас интересует время t при котором маркеры закончатся а значит и контекст будет оштрафован.
- это скорость заполнения ведра маркерами в секунду.
- это скорость изъятия маркеров из ведра планировщиком.
Тогда наше уравнение выглядит следующим образом:
Немного алгебры, и мы получим выражение:
Выразим теперь максимальное количество маркеров для известного t.
Таким образом можно вычислить требуемый максимальный размер ведра.
Для гарантированного распределения ресурсов CPU обязательно выполнение условия:
Жёсткое закрепление ресурсов CPU за каждым контекстом не всегда эффективное решение. Предположим что каждому контексту выделена 1/10 процессорного времени. Допустим четыре контекста работают, и съедают 4/10 процессорного времени, но остальные 6/10 остаются неиспользованными.
Начиная с версии Linux-VServer 2.1.1 появилась возможность справедливо разделять неиспользованное процессорное время между контекстами таким образом реализуя возможность некоторого QoS в виде гарантированного и максимально доступного процессорного времени.
Для распределения неиспользуемого процессорного времени задаётся ещё один коэффициент T/J называемый T2/J2. Этот коэффициент определяет какую часть свободного процессорного времени может использовать данный контекст. Свободное время распределяется справедливо между контекстами, в соответствии с этим коэффициентом.
Вычислить фактическое распределение процессорного времени для контекста не сложно и задаётся следующей формулой:
Где Cidleкоэффициент текущего неиспользованного процессорного времени например 6/10.
Если теперь в нашем примере 6/10 процессорного времени свободно, а для двух контекстов задано отношение T2/J2 как соответственно 1/2 и 1/4.
для первого контекста
и для второго.
Если коэффициент используемого свободного процессорного времени задан у всех контекстов одинаково то вышеприведённая формула упрощается.
Где - N текущее количество активных контекстов.
Лимитирование памяти
Лимит на использование памяти контекстом вещь весьма полезная.
Пожалуй имеет смысл ограничивать размер RSS и AS.
RSS — резидентный размер памяти используемой контекстом (в страницах). Жёсткий лимит RSS выглядит как максимальный объём ОЗУ для контекста и отображается утилитой free внутри контекста. Мягкий лимит позволяет задать границу после которой будет использован swap.
При превышении жёсткого лимита ядро воспользуется OOM killer для уничтожения зарвавшихся процессов контекста.
AS - использование ограничения на адресное пространство контекста не выглядит особо практично.
Изменить текущие значения лимитов контекста можно прямо на лету (размер в страницах):
# /usr/sbin/vlimit -c 49000 --rss 10000
или изменить конфигурационный файл:
# /etc/vservers/
Текущие лимиты для указанного XID можно увидеть так:
# vlimit -c
RSS N/A 5000 10000
Дисковые квоты
Linux-VServer имеет возможность задать квоту на использование дискового пространства целиком на весь контекст. Для этого потребуется использование XID на файловой системе и необходимо монтировать её с опцией tag.
# mount -o tag /dev/sdd1 /var/lib/vservers
Затем маркируются собственным XID-ом файлы принадлежащие данному vserver:
# chxid -URx -c
В каталоге /etc/vservers/[name]
directory | Каталог с назначаемыми лимитами |
inodes_total | Лимит на количество индексных узлов |
reserved | Резервируемое дисковое пространство для root в процентах |
space_total | Лимит на занимаемое пространство измеряемое в блоках по 1024 байта |
После перезапуска vserver можно наблюдать фактические лимиты на дисковое пространство с помощью следующей команды:
# vdlimit --xid
300 /vservers
space_used=235604
space_total=650600
inodes_used=95402
inodes_total=100000
reserved=5
Использование vhashify
Linux-VServer имеет одну весьма примечательную особенность. Это возможность прилично сэкономить дисковое пространство в случае использования множества VPS с одинаковыми файлами.
Множество файлов ОС статичны и не изменяются. Это библиотеки, бинарные файлы. Средство vhashify позволяет переместить одинаковые файлы в одно место и создать на них жёсткие ссылки. В случае записи в файл, который является жёсткой ссылкой, автоматически создаётся его локальная копия, т.е. реализуется механизм COW (copy-on-write).
Сначала создаётся каталог куда будут помещаться совпадающие файлы затем каждый vserver подлежащий процедуре линковки файлов пропускается через vhashify.
# mkdir /etc/vservers/.defaults/apps/vunify/hash \
/var/lib/vservers/.hash
# ln -s /var/lib/vservers/.hash \
/etc/vservers/.defaults/apps/vunify/hash/root
Для каждого vserver создать файл в каталоге:
# mkdir /etc/vservers/[name]
Или для работающего vserver запустить команду:
# vserver
Можно получить некоторый прирост производительности т.к. для совпадающих файлов используется один и тот же буферный кеш.