Контейнеры эффективно разделяют ресурсы, управляемые единственной операционной системой, на изолированные группы, для достижения лучшего баланса между конфликтующими запросами на использование ресурсов. В отличие от виртуализации, здесь не требуется ни эмуляция на командном уровне, ни компиляция "на лету" (just-in-time compilation). Контейнеры могут исполнять прямые процессорные команды, не прибегая к механизмам интерпретации. Также отпадают сложности паравиртуализации и преобразования системных вызовов.
Предоставляя средства для создания и использования контейнеров, ОС дает приложениям возможность работать как бы на отдельной машине, при этом совместно используя множество базовых ресурсов. Например, кэширование страниц общих файлов — например, glibc — можно эффективно использовать совместно, потому что все контейнеры используют одно и тоже ядро и, в зависимости от настроек контейнера, обычно одну и ту же библиотеку libc. Часто такое совместное использование распространяется и на другие файлы и папки, в которые не происходит запись.
Экономия от совместного использования ресурсов в сочетании с предоставляемой изоляцией приводит к тому, что контейнеры требуют значительно меньших накладных расходов, чем истинная виртуализация.
Контейнерные технологии существуют уже довольно продолжительное время. В качестве примеров контейнеров из других Unix-систем следует назвать Solaris Zones и BSD jails. У контейнерных технологий в Linux также давние традиции: Linux-Vserver, OpenVZ и FreeVPS. Хотя каждая из этих технологий является вполне зрелой, решительных шагов по интеграции поддержки их контейнерных возможностей в основную ветвь ядра Linux не предпринималось.
В статье Сержа Халлина (Serge Hallyn) "Модули безопасности Linux: Рецепты для работы с контейнерами" (developerWorks, февраль 2009 г.), рассказывается, как можно усилить безопасность легких контейнеров с помощью политик SELinux и Smack. Подробности об этих технологиях ищите в Ресурсах.
Проект Linux Resource Containers (который разрабатывается и поддерживается специалистом IBM Дэниелом Лезкано (Daniel Lezcano); см. ссылку на исходный код в Ресурсах ), напротив, направлен на реализацию контейнеров в сотрудничестве с разработчиками основной ветви ядра Linux. Одновременно этот вклад может быть полезен и для более зрелых контейнерных Linux-решений, предоставляя для них общий внутренний интерфейс. Данная статья содержит краткое введение в использование утилит, созданных проектом LXC.
Для лучшего понимания статьи необходимо уверенно чувствовать себя в командной строке в работе с такими программами, как make, gcc, и patch, а также быть знакомым с процессом распаковки тарболов (файлов с расширением .tar.gz).
Получение, сборка и установка LXC
Проект LXC состоит из патча для ядра Linux и утилит, работающих в пользовательском пространстве. Утилиты используют новую функциональность, добавляемую патчем в ядро, и предлагают упрощенный набор инструментов для управления контейнерами.
Прежде чем начать использовать LXC, необходимо скачать исходный код ядра Linux, установить соответствующий LXC-патч, затем собрать, установить и загрузить новое ядро. Далее необходимо загрузить, собрать и установить инструментарий LXC.
Мы использовали пропатченное ядро Linux 2.6.27 (см. ссылки в Ресурсах ). Скорее всего, lxc-патч для ядра 2.6.27 не подойдет для исходного кода ядра вашего любимого дистрибутива, и в то же время версии ядра Linux старше 2.6.27 могут уже содержать значительную часть функциональности, представленной в патче. Поэтому настоятельно рекомендуется использовать последние версии патча и ядра из основной ветви. Также вместо загрузки исходного кода ядра и установки на него патча можно получить код, используя git:
git clone git://git.kernel.org/pub/scm/linux/kernel/git/daveh/linux-2.6-lxc.git |
Инструкции по наложению патчей, настройке, сборке, установке и загрузке ядра можно найти на сайте kernelnewbies.org (см. ссылку в Ресурсах).
Для LXC необходимы некоторые специфические настройки в ядре. Самый простой способ правильно настроить ядро для работы с LXC — это использовать
make menuconfig и включить Container
support. Это, в свою очередь, автоматически включит набор других опций, зависящих от возможностей, поддерживаемых ядром.
В дополнение к ядру, поддерживающему контейнеры, нам понадобятся инструменты для упрощения запуска и управления контейнерами. Основными средствами управления в этой статье являются утилиты из библиотеки liblxc (см. ссылку в Ресурсах, а также ссылку на libvirt в качестве альтернативного решения). В этом разделе обсуждаются:
- Утилита liblxc
- Утилита iproute2
- Настройка сети
- Заполнение файловой системы контейнера (путем собственной сборки в Debian или запуска ssh-контейнера)
- Подключение к файловой системе контейнера (SSH, VNC, VT: tty, VT: GUI)
Скачайте и распакуйте liblxc (см. Ресурсы), затем выполните из папки liblxc команду:
./configure --prefix=/ make make install |
Если вам удобнее собирать из SRPM, такой пакет также имеется (см. Ресурсы).
Для управления сетевыми интерфейсами внутри контейнеров необходим пакет iproute2 версии 2.6.26 или старше (см. Ресурсы). Если в вашем дистрибутиве он отсутствует, то скачайте, настройте, соберите и установите его, следуя инструкциям из архива с исходным кодом.
Еще один ключевой компонент многих функциональных контейнеров — сетевой доступ. Наилучшим способом подключения контейнера к сети в настоящее время является соединение сегментов Ethernet сетевым мостом таким образом, что они выглядят единым сегментом сети. Готовясь к использованию LXC, мы создадим сетевой мост (см. Ресурсы) и с его помощью соединим наш настоящий сетевой интерфейс и сетевой интерфейс контейнера.
Создаем сетевой мост с именем br0:
brctl addbr br0 brctl setfd br0 0 |
Теперь поднимите интерфейс моста с вашим IP от уже существующего интерфейса (в этом примере
10.0.2.15):
ifconfig br0 10.0.2.15 promisc up. Добавьте в мост существующий интерфейс (в нашем примере
eth0) и уберите его прямую связь с IP-адресом:
brctl addif br0 eth0
ifconfig eth0 0.0.0.0 up
|
Любой интерфейс, добавленный к мосту br0, будет соответствовать IP-адресу моста. Напоследок убедитесь, что пакеты следуют к шлюзу через правильный маршрут по умолчанию:
route add -net default gw 10.0.2.2 br0. Позже, при настройке контейнера, мы укажем
br0 в качестве пути во внешний мир.
Заполнение файловой системы контейнера
Помимо сети, контейнерам часто нужна собственная файловая система. Существует несколько способов заполнить ее в зависимости предъявляемых требований. Обсудим два из них:
- Сборка собственного Debian-контейнера
- Запуск SSH-контейнера
Собрать собственный Debian-контейнер проще всего с помощь команды
debootstrap:
debootstrap sid rootfs http://debian.osuosl.org/debian/ |
Если делается большое количество контейнеров сразу, то можно сэкономить время, предварительно скачав пакеты и объединив их в тарбол:
debootstrap --make-tarball sid.packages.tgz sid http://debian.osuosl.org/debian/.
Команда из этого примера соберет tar-файл размером около 71 МБ (52 МБ в сжатом виде), в то время как корневой каталог займет примерно 200 МБ. Теперь все готово к сборке корневой папки в rootfs:
debootstrap --unpack-tarball sid.packages.tgz sid rootfs.
(man-страница debootstrap содержит более полную информацию по сборке контейнеров меньшего размера или размера, более подходящего вам по другим параметрам.
В итоге мы получаем среду (см. Ресурсы), чрезвычайно избыточную по отношению к основному хост-контейнеру.
Запуск SSH-контейнера позволяет очень существенно снизить объём дискового пространства, выделяемого исключительно под файловую систему контейнера. Например, данный способ использует лишь несколько килобайт, чтобы включить множество ssh-демонов из разных контейнеров, работающих на порту 22 (см. пример в Ресурсах). Контейнер делает это, используя монтирование "только для чтения" (read-only bind mounts), таких важных корневых папок, как /bin, /sbin, /lib и др., для совместного доступа к содержимому пакета sshd из существующей системы Linux. При этом используется сетевое пространство имен и создается очень небольшое изменяемое содержимое.
Методы, использованные выше для создания легких контейнеров, в основном такие же, какие используются для создания chroot-сред. Разница лишь в использовании синонимов «только для чтения» (read-only bind mounts) и в использовании пространств имен для повышения изолированности chroot-среды до такой степени, что она становится эффективным контейнером.
Далее нам необходимо выбрать способ подключения к контейнеру.
Следующий шаг — подключение к контейнеру. Здесь, в зависимости от настроек контейнера, возможно несколько способов:
- SSH
- VNC (графический режим)
- VT: tty (текстовый режим)
- VT: X (графический режим)
Подключение через SSH хорошо подходит для тех случаев, когда контейнеру не требуется графический интерфейс. В этом случае вполне достаточно простого соединения ssh (см. выше " Запуск контейнера SSHЗапуск контейнера SSH"). Преимущество этого метода, основанного на IP-адресации, в возможности создавать произвольное количество контейнеров.
Если ssh-соединение ожидает ввод пароля слишком долго, то широковещательный демон Avahi службы DNS/Service Discovery при запросе к DNS может остановить работу по тайм-ауту.
Подключение через удалённый доступ к рабочему столу (VNC) позволит использовать контейнер с графическим интерфейсом.
Для запуска X-сервера, обслуживающего только VNC-клиентов, используйте vnc4server. Установленный vnc4server необходимо будет запустить из файла /etc/rc.local контейнера таким образом:
echo '/usr/bin/vnc4server :0 -geometry 1024x768 -depth 24' >> rootfs/etc/rc.local.
В результате при старте контейнера будет создан экран с разрешением 1024*768 пикселов и глубиной цвета 24 бита. Теперь для подключения достаточно ввести:
vncviewer <ip>:<display> |
Подключение через VT: tty (текстовый режим) удобно, когда контейнер делит tty с основной машиной (хостом). В этом случае для подключения к контейнеру можно использовать Linux Virtual Terminals (VT). Простейшее использование VT начинается с авторизации в одном из устройств tty, которые обычно совпадают с виртуальными терминалами Linux. Процесс, отвечающий за авторизацию, называется getty. Чтобы использовать VT 8, вводим:
echo '8:2345:respawn:/sbin/getty 38400 tty8' >> rootfs/etc/inittab |
Теперь при запуске контейнера будет запускаться
getty
на tty8, что даст пользователям возможность авторизоваться в контейнере. Аналогичный прием можно использовать для перезапуска контейнера с помощью утилит LXC.
Этот метод не позволяет использовать графический интерфейс контейнера. Более того, поскольку к tty8 в каждый момент времени может подключиться лишь один процесс, для подключения нескольких контейнеров потребуются дополнительные настройки.
Подключение через VT: X позволит запустить графический интерфейс. Для запуска GNOME Display Manager (gdm) на VT 9, отредактируйте rootfs/usr/share/gdm/defaults.conf, заменив значения
FirstVT=7 на
FirstVT=9, и
VTAllocation=true на
VTAllocation=false.
Хотя теперь мы получили графический режим, мы используем один терминал из ограниченного количества виртуальных Linux-терминалов.
Теперь, когда у нас работает удовлетворяющее требованиям ядро, установлены утилиты LXC и есть рабочая среда, настало время научиться управлять экземплярами среды. (Совет: более подробное описание многих необходимых действий содержится в файле LXC README.)
Для управления контейнерами LXC использует файловую систему cgroup. Первое, что нужно сделать, - это смонтировать ее:
mount -t cgroup cgroup /cgroup. Файловую систему cgroup можно монтировать куда угодно. LXC будет использовать первую смонтированную cgroup из файла /etc/mtab.
Далее в статье приводятся некоторые базовые сведения по LXC, конкретные замечания и обзор низкоуровневого доступа.
Здесь мы рассмотрим следующие вопросы:
- Создание контейнера
- Получение информации о существующих контейнерах или их списка
- Запуск системных контейнеров и контейнеров приложений
- Сигнальные процессы, запущенные в контейнере
- Приостановка, возобновление, останов и уничтожение контейнера
Создание контейнера связывает имя с файлом настроек. Имя будет использовано для управления единичным контейнером:
lxc-create -n name -f configfile |
Это позволяет множеству контейнеров использовать один и тот же файл настроек. В конфигурационном файле задаются атрибуты контейнера, такие как имя хоста, настройки сети, корневая файловая система и точки монтирования в fstab. После запуска скрипта lxc-sshd (создающего для нас конфигурацию) конфигурация ssh-контейнера будет выглядеть так:
lxc.utsname = my_ssh_container lxc.network.type = veth lxc.network.flags = up lxc.network.link = br0 lxc.network.ipv4 = 10.0.2.16/24 lxc.network.name = eth0 lxc.mount = ./fstab lxc.rootfs = ./rootfs |
Независимо от файла настроек контейнеры, запускаемые утилитами LXC, по-своему видят процессы системы и доступные ресурсы межпроцессного взаимодействия (IPC), а также имеют собственное дерево точек монтирования (mount tree).
Кроме того, при запуске контейнера подразумевается, что любые ресурсы, не указанные в файле конфигурации, используются совместно с хостом. Это позволяет администраторам компактно описывать ключевые различия между хостом и контейнером, а также обеспечивает переносимость настроек.
Вывод информации о существующих контейнерах — ключевой момент в управлении ими. Просмотр состояния конкретного контейнера:
lxc-info -n name |
Просмотр процессов, принадлежащих контейнеру:
lxc-ps |
Запуск
В LXC различают два типа контейнеров: системные контейнеры и контейнеры приложений. Системные контейнеры похожи на виртуальные машины. Но, в отличие от истинной виртуализации, они создают меньшие накладные расходы за счёт меньшей изолированности. Это прямое следствие того, что все контейнеры используют одно и тоже ядро. Как и виртуальная машина, системный контейнер запускается так же, как Linux-дистрибутив, через запуск процесса init:
lxc-start -n name init |
Напротив, контейнер приложений лишь создает отдельное пространство имен, необходимое для изоляции единичного приложения. Запуск контейнера приложений:
lxc-execute -n name cmd |
Подача сигналов
Подаём сигнал всем процессам внутри контейнера:
lxc-kill -n name -s SIGNAL |
Приостановка
Приостановка контейнера по сути похожа на отправку сигнала
SIGSTOP всем процессам в контейнере. Однако отправка избыточных сигналов
SIGSTOP
может запутать некоторые программы. Поэтому LXC использует "замораживатель" процессов (Linux process freezer), доступный через интерфейс cgroup:
lxc-freeze -n name |
Возобновление
Для "размораживания" контейнера:
lxc-unfreeze -n name |
Остановка
Остановка очищает контейнер, завершая все запущенные в нем процессы:
lxc-stop -n name |
Уничтожение
Уничтожение контейнера удаляет конфигурационные файлы и метаданные, которые были связаны с его именем при создании lxc-create:
lxc-destroy -n name |
Вот несколько практических моментов, которые могут казаться полезными (некоторые из них касаются мониторинга).
Просмотр и настройка приоритета контейнера:
lxc-priority -n name lxc-priority -n name -p priority |
Непрерывное наблюдение за состоянием и изменением приоритета контейнера:
lxc-monitor -n name |
Нажмите Ctrl-C чтобы остановить наблюдение.
Ждём, пока контейнер не войдет в одно из множеств состояний, разделенных
|:
lxc-wait -n name -s states |
Ждём любого состояния, кроме RUNNING:
lxc-wait -n name -s 'STOPPED|STARTING|STOPPING|ABORTING|FREEZING|FROZEN' |
Эта команда, разумеется, приведет к немедленному возврату управления. Исключая непредвиденные ошибки, можно ожидать, что команда
lxc-wait завершится только когда контейнер войдет в указанное состояние.
Для управления контейнерами LXC использует файловую систему cgroup. Посредством LXC возможно просматривать и производить определённые действия с частями файловой системы cgroup. Использование процессора каждым контейнером можно регулировать считыванием и регулировкой параметра cpu.shares:
lxc-cgroup -n name cpu.shares lxc-cgroup -n name cpu.shares howmany |
Узнав из этого руководства об основах работы с контейнерными утилитами Linux, вы можете приступать к созданию собственных эффективных разделов ресурсов.
Этот материал основан на работе, поддержанной Агентством передовых оборонных исследовательских проектов (DARPA), в рамках Соглашения HR0011-07-9-0002.
Научиться
- Дополняющая статья Сержа Халлина (Serge Hallyn) "Книга рецептов для работы с контейнерами Secure Linux" ("
Secure Linux containers cookbook", developerWorks, февраль 2009 г.) раскрывает тему укрепления безопасности легких контейнеров с помощью политик SELinux и Smack.
- На сайте
kernelnewbies.org содержатся инструкции по применению патчей, настройке, сборке, установке и загрузке ядра.
- Другие контейнерные технологии:
- Solaris Zones (Solaris)
- BSD jails (FreeBSD)
- Linux-Vserver (Linux)
- OpenVZ (Linux)
- FreeVPS (Linux)
- Оригинал статьи "LXC: Linux container tools" (EN).
- Узнайте, как создать
сетевой мост в процессе подготовки LXC к использованию.(EN)
-
Эта среда
чрезвычайно избыточна по отношению к хост-контейнеру.(EN)
-
Этот пример с ssh
использует лишь несколько килобайт, чтобы включить множество работающих на порту 22 ssh-демонов из разных контейнеров.(EN)
- В
разделе Linux на сайте developerWorks,
есть дополнительные ресурсы для Linux-разработчиков (в том числе и
для новичков), а также можно просмотреть наши наиболее популярные статьи и учебные материалы.
-
Изучите другие советы
и
руководства
по Linux на сайте developerWorks.
-
Технические мероприятия и Web-трансляции developerWorks: будьте в курсе новостей (EN)
Получить продукты и технологии
- Проект
Linux Resource Containers project
на SourceForge.net — это репозиторий кода для реализации контейнера приложений в ядре Linux и место размещения кода, который может быть отправлен в списки рассылки ядра.(EN)
-
Скачайте исходный код ядра
Linux 2.6.27
и
lxc-патч для этой версии ядра.(EN)
-
На сайте
liblxc,
можно найти основной инструментарий управления контейнерами, используемый в этой статье.
Доступен также пакет RPM
с исходным кодом.(EN)
-
libvirt — это инструментарий и API виртуализации Linux, предоставляющий общие процедуры управления виртуальной машиной и экземплярами контейнера. libvirt не зависит от того, используется ли для виртуализации Xen, QEMU или KVM, а также LXC или OpenVZ для контейнеров.(EN)
-
Получите
пакет iproute2версии 2.6.26 или выше.(EN)
- Используйте в вашем следующем проекте разработки для Linux
ознакомительные версии ПО IBM, которые можно скачать непосредственно с developerWorks.(EN)
Обсудить
- Примите участие в обсуждении материала на форуме.
-
Участвуйте в жизни сообщества developerWorks — посещайте блоги, форумы, подкасты и дискуссионные пространства.(EN)