В данный момент в Linux существует следующие широко известные реализации контейнеров:
Но они требуют наложения своих патчей на ядро, для получения необходимого функционала. В отличии от них lxc начиная с ядра версии 2.6.29 не требует этого. Для реализации изоляции используются уже имеющиеся в ядре namespaces, а для управления ресурсами Control Group. Это позволяет создавать не только полноценные изолированные окружения, но и осуществлять изоляцию отдельно взятых приложений. Для того чтобы начать работу с lxc потребуется запущенный linux с ядром 2.6.29. При этом в ядре должны быть включены следующие опции:
Если все это включено, то монтируем файловую систему cgroup:
Скачиваем lxc, собираем и устанавливаем:
Затем проверьте какая версия iproute2 установлена. Потребуется версия выше 2.6.26. Эта версия позволяет управлять виртуальными сетевыми усройствами и настривать network namespaces. Кроме этого если планируется использовать сеть внутри контейнера, то надо перенастроить вашу сетевую систему чтобы она использовала режим моста (bridge). Для этого опустите сетевой интерфейс:
Создайте мост br0:
Подключите к нему ваш сетевой интерфейс:
Настройте на br0 необходимый адрес и пропишите шлюз по умолчанию:
Далее когда контейнер будет стартовать, будет создаваться специальное виртуальное устройство соединяющее мост с виртуальным интерфейсом контейнера. Теперь необходим образ системы для контейнера. Самый простой способ это воспользоваться готовыми шаблонами от OpenVZ. Я использовал шаблон для CentOS. Скачайте и распакуйте его в каталог /var/lxc/centos/rootfs. После этого потребуется немного модифицировать шаблон, так-как он предназначен для работы с OpenVZ. Для этого выполните выполните следующие действия:
Перейдите в каталог /var/lxc/centos/rootfs/etc/rc.d и в файле rc.sysinit закоментируйте следующие строки:
На данный момент /dev каталог монтируется при помощи bind из текущей системы.
Затем закоментировать в каталоге /var/lxc/centos/rootfs/etc/ в файле fstab закоментируйте строку:
После чего перейдите в каталог /var/lxc/centos/rootfs/etc/sysconfig/network-scripts и создайте тем файл ifcfg-eth0 такого вида:
Далее перейдите в каталог /var/lxc/centos/rootfs/etc/sysconfig/ и создайте файл network:
Теперь осталось поменять пароль root. Для этого делаем chroot в образ системы и вызываем passwd:
С подготовкой системы закончено. Переходим к созданию настроек контейнера. Для этого создадим два файла fstab и lxc-centos.conf в каталоге /var/lib/
Далее необходимо создать файлы настроек контейнера. Создаем в каталоге /var/lxc/centos lxc-centos.conf и fstab следующего содержания:
lxc-centos.conf
fstab
Теперь можно создать контейнер. Указываем имя centos и файл конфигурации:
Проверяем создался ли контейнер:
Контейнер создался, но на данный момент не работает. Запускаем его:
У вас начнется загрузка centos. Как только увидите:
Загрузка завершена. Откройте соседнюю консоль и попробуйте попинговать адрес выделенный контейнеру. Как только он запингуется можно зайти по ssh.
Но кроме полноценных контейнеров lxc позволяет создавать контейнеры приложений. Для этого в каталоге /var/lxc/simple создаем следующую структуру каталогов:
Затем создаем lxc-simple.conf:
и fstab:
Далее создаем контейнер:
И запускаем приложение:
Как видите это с одной стороны создание контейнера с приложением проще, с другой стороны сложнее чем создание полноценного контейнера. Сейчас у вас имеется один запущенный контейнер и один контейнер приложений в остановленном состоянии. Но контейнеры кроме изоляции должен позволять ограничивать ресусы. Для этого в lxc используется lxc-cgroup. На данный момент он позволяет указывать какой процессор будет использоваться, сколько процессорного времени ему будет выделятся, ограничение доступной памяти и класс сетевого трафика исходящего с контейнера для дальнейшей обработки. Все настройки базируются на cgroup для подробного ознакомления с настройками стоит обратиться к каталогу документации ядра Documentation/cgroups
Приведу несколько постых примеров. Привязка контейнера к первому ядру процессора:
Ограничение памяти контейнера до 128Мегабайт:
Кроме этого имеются различные параметры учета. Напрямую все это без lxc-cgroup можно просмотреть в каталоге /var/lxc/cgroup/centos.
Если контейнер станет вам не нужен то его можно остановить:
И удалить:
Учтите, что хотя при этом контейнер удалится, образ системы останется на диске.
Просмотреть запущенные процессы можно при помощи lxc-ps:
lxc-info показывает состояние контейнера:
lxc-freeze блокирует все процессы в контейнере до вызова lxc-unfreeze
lxc-unfreeze снимает блокировку со всех процессов в контейнере
lxc является интересной технологией, но на данный момент она не готова для использования в production. Изоляция явно недостаточна. Так top внутри контейнера показывает все процессоры и всю память, mount выводит точки смонтированные вне контейнера, а вызов установки времени изменяет его вне контейнера. Кроме этого нет квотирования используемого диского пространства и жесткого ограничения по использованию процессора. Работа над квотированием на данный момент ведется так что буду надеяться, что в скором времени для создания контейнеров не надо будет патчить ядро.
Но они требуют наложения своих патчей на ядро, для получения необходимого функционала. В отличии от них lxc начиная с ядра версии 2.6.29 не требует этого. Для реализации изоляции используются уже имеющиеся в ядре namespaces, а для управления ресурсами Control Group. Это позволяет создавать не только полноценные изолированные окружения, но и осуществлять изоляцию отдельно взятых приложений. Для того чтобы начать работу с lxc потребуется запущенный linux с ядром 2.6.29. При этом в ядре должны быть включены следующие опции:
* General setup
** Control Group support
---> Namespace cgroup subsystem
---> Freezer cgroup subsystem
---> Cpuset support
----> Simple CPU accounting cgroup subsystem
----> Resource counters
----> Memory resource controllers for Control Groups
** Group CPU scheduler
---> Basis for grouping tasks (Control Groups)
** Namespaces support
---> UTS namespace
---> IPC namespace
---> User namespace
---> Pid namespace
---> Network namespace
* Security options
--> File POSIX Capabilities
* Device Drivers
** Network device support
---> Virtual ethernet pair device
Если все это включено, то монтируем файловую систему cgroup:
mkdir -p /var/lxc/cgroup
mount -t cgroup cgroup /var/lxc/cgroup
Скачиваем lxc, собираем и устанавливаем:
./configure --prefix=/
make
make install
Затем проверьте какая версия iproute2 установлена. Потребуется версия выше 2.6.26. Эта версия позволяет управлять виртуальными сетевыми усройствами и настривать network namespaces. Кроме этого если планируется использовать сеть внутри контейнера, то надо перенастроить вашу сетевую систему чтобы она использовала режим моста (bridge). Для этого опустите сетевой интерфейс:
ifconfig eth0 down
Создайте мост br0:
brctl addbr br0
brctl setfd br0 0
Подключите к нему ваш сетевой интерфейс:
brctl addif br0 eth0
ifconfig eth0 0.0.0.0 up
Настройте на br0 необходимый адрес и пропишите шлюз по умолчанию:
ifconfig bdr0 192.168.1.2/24 up
route add default gw 192.168.1.1
Далее когда контейнер будет стартовать, будет создаваться специальное виртуальное устройство соединяющее мост с виртуальным интерфейсом контейнера. Теперь необходим образ системы для контейнера. Самый простой способ это воспользоваться готовыми шаблонами от OpenVZ. Я использовал шаблон для CentOS. Скачайте и распакуйте его в каталог /var/lxc/centos/rootfs. После этого потребуется немного модифицировать шаблон, так-как он предназначен для работы с OpenVZ. Для этого выполните выполните следующие действия:
Перейдите в каталог /var/lxc/centos/rootfs/etc/rc.d и в файле rc.sysinit закоментируйте следующие строки:
/sbin/start_udev
mount -n /dev/pts >/dev/null 2>&1
На данный момент /dev каталог монтируется при помощи bind из текущей системы.
Затем закоментировать в каталоге /var/lxc/centos/rootfs/etc/ в файле fstab закоментируйте строку:
none /dev/pts devpts rw 0 0
После чего перейдите в каталог /var/lxc/centos/rootfs/etc/sysconfig/network-scripts и создайте тем файл ifcfg-eth0 такого вида:
DEVICE=eth0
IPADDR=192.168.1.102
NETMASK=255.255.255.0
NETWORK=192.168.1.0
BROADCAST=192.168.1.255
ONBOOT=yes
NAME=eth0
Далее перейдите в каталог /var/lxc/centos/rootfs/etc/sysconfig/ и создайте файл network:
NETWORKING="yes"
GATEWAY="192.168.1.1"
HOSTNAME="centos_ssh"
Теперь осталось поменять пароль root. Для этого делаем chroot в образ системы и вызываем passwd:
chroot /var/lxc/centos/rootfs
passwd
С подготовкой системы закончено. Переходим к созданию настроек контейнера. Для этого создадим два файла fstab и lxc-centos.conf в каталоге /var/lib/
Далее необходимо создать файлы настроек контейнера. Создаем в каталоге /var/lxc/centos lxc-centos.conf и fstab следующего содержания:
lxc-centos.conf
lxc.utsname = centos_ssh
lxc.network.type = veth
lxc.network.flags = up
lxc.network.link = br0
lxc.network.ipv4 = 192.168.1.101/24
lxc.network.name = eth0
lxc.mount = /var/lxc/centos/fstab
lxc.rootfs = /var/lxc/centos/rootfs
fstab
/dev /var/lxc/centos/rootfs/dev none bind 0 0
/dev/pts /var/lxc/centos/rootfs/dev/pts none bind 0 0
Теперь можно создать контейнер. Указываем имя centos и файл конфигурации:
lxc-create -n centos -f /var/lxc/centos/lxc-centos.conf
Проверяем создался ли контейнер:
lxc-info -n centos
'centos' is STOPPED
Контейнер создался, но на данный момент не работает. Запускаем его:
lxc-start -n centos
У вас начнется загрузка centos. Как только увидите:
INIT: no more processes left in this runlevel
Загрузка завершена. Откройте соседнюю консоль и попробуйте попинговать адрес выделенный контейнеру. Как только он запингуется можно зайти по ssh.
Но кроме полноценных контейнеров lxc позволяет создавать контейнеры приложений. Для этого в каталоге /var/lxc/simple создаем следующую структуру каталогов:
rootfs
|-- bin
|-- dev
| |-- pts
| `-- shm
| `-- network
|-- etc
|-- lib
|-- proc
|-- root
|-- sbin
|-- sys
|-- usr
`-- var
|-- empty
|-- lib
| `-- empty
`-- run
Затем создаем lxc-simple.conf:
lxc.utsname = simple
lxc.mount = /var/lxc/simple/fstab
lxc.rootfs = /var/lxc/simple/rootfs
и fstab:
/lib /var/lxc/simple/rootfs/lib none ro,bind 0 0
/bin /var/lxc/simple/rootfs/bin none ro,bind 0 0
/usr /var/lxc/simple/rootfs/usr none ro,bind 0 0
/sbin /var/lxc/simple/rootfs/sbin none ro,bind 0 0
Далее создаем контейнер:
lxc-create -n simple -f /var/lxc/simple/lxc-simple.conf
И запускаем приложение:
lxc-execute -n centos /bin/ls
Как видите это с одной стороны создание контейнера с приложением проще, с другой стороны сложнее чем создание полноценного контейнера. Сейчас у вас имеется один запущенный контейнер и один контейнер приложений в остановленном состоянии. Но контейнеры кроме изоляции должен позволять ограничивать ресусы. Для этого в lxc используется lxc-cgroup. На данный момент он позволяет указывать какой процессор будет использоваться, сколько процессорного времени ему будет выделятся, ограничение доступной памяти и класс сетевого трафика исходящего с контейнера для дальнейшей обработки. Все настройки базируются на cgroup для подробного ознакомления с настройками стоит обратиться к каталогу документации ядра Documentation/cgroups
Приведу несколько постых примеров. Привязка контейнера к первому ядру процессора:
lxc-cgroup -n centos cpuset.cpus 0
Ограничение памяти контейнера до 128Мегабайт:
lxc-cgroup -n centos memory.limit_in_bytes 128M
Кроме этого имеются различные параметры учета. Напрямую все это без lxc-cgroup можно просмотреть в каталоге /var/lxc/cgroup/centos.
Если контейнер станет вам не нужен то его можно остановить:
lxc-stop -n centos
И удалить:
lxc-destroy -n centos
Учтите, что хотя при этом контейнер удалится, образ системы останется на диске.
Просмотреть запущенные процессы можно при помощи lxc-ps:
lxc-ps --lxc
centos 7480 ? 00:00:00 init
centos 7719 ? 00:00:00 syslogd
centos 7736 ? 00:00:00 sshd
lxc-info показывает состояние контейнера:
lxc-info -n centos
'centos' is RUNNING
lxc-freeze блокирует все процессы в контейнере до вызова lxc-unfreeze
lxc-freeze -n centos
lxc-unfreeze снимает блокировку со всех процессов в контейнере
lxc-unfreeze -n centos
lxc является интересной технологией, но на данный момент она не готова для использования в production. Изоляция явно недостаточна. Так top внутри контейнера показывает все процессоры и всю память, mount выводит точки смонтированные вне контейнера, а вызов установки времени изменяет его вне контейнера. Кроме этого нет квотирования используемого диского пространства и жесткого ограничения по использованию процессора. Работа над квотированием на данный момент ведется так что буду надеяться, что в скором времени для создания контейнеров не надо будет патчить ядро.