неділю, 26 січня 2014 р.

LXC 1.0: Второй контейнер

Статья 2 из 10, в которой речь пойдёт об LXC и создании второго контейнера, используя другие шаблоны и параметры.

Больше шаблонов.

В статье LXC 1.0: Первый Ubuntu контейнер легко и просто создали первый контейнер p1 с помощью шаблона по умолчанию ubuntu. Но LXC поддерживает больше систем, чем просто Ubuntu. На данный момент поддерживаются Alpine Linux, Alt Linux, Arch Linux, busybox, CentOS, Cirros, Debian, Fedora, OpenMandriva, OpenSUSE, Oracle, Plamo, sshd, Ubuntu Cloud и Ubuntu.

Шаблоны можно найти в /usr/share/lxc/templates. Все шаблоны обладают дополнительными опциями, которые можно узнать по ключу --help после вызова lxc-create. Только нужно применять -- , чтобы разделять опции lxc-create и опции шаблона.

Написание дополнительных шаблонов не сложно. Это просто исполняемые файлы, часто, но не обязательно, это shell скрипты, которые понимают набор стандартных аргументов и выполняют rootfs в нужном пути.

В связи с недостающими инструментами не все дистрибутивы Linux могут самозагружать (Bootstrapping) любой дистрибутив. Разработчики LXC заинтересованы в улучшении ситуации, даже если используются странные трюки как в Fedora, так что если есть не работающая комбинация хост + гость, то патчи приветствуются!

Но хватит болтать, давайте двигаться дальше.
sudo lxc-create -t oracle -n p2 -- -a i386

Но скорее всего установка провалится, так как нет rpm и yum. Установите их и попробуйте снова. После установки нужных пакетов rpm и после создания контейнера, можно запустить его:
sudo lxc-start -n p2

Приглашение в систему просто просит ввести - логин root и пароль root.

Контейнер запущен без ключа -d поэтому для возврата в хост-shell придётся завершить работу контейнера. Нельзя отсоединиться (detach) от контейнера, который был запущен не в фоне с ключом -d.

Теперь стоит задаться вопросом - почему два шаблона Убунту? Обычный шаблон ubuntu, который использовался до сих пор, создавал контейнер "линукс с нуля" через debootstrap. Шаблон ubuntu-cloud скачивает подготовленный облачный образ и запускает его. Образ включает в себя cloud-init и поддерживает стандартные облачные метаданные.

Какой шаблон лучше использовать - дело вкуса. Шаблон ubuntu может быстро работать, если репозитория расположены на быстрых локальных зеркалах. И главное, что шаблоны используют кэш. Для данной архитектуры первоначальное создание контейнера может быть медленным, но последующие будут использовать локальную копию из кэша и всё будет происходить быстрее.

Автозагрузка.

Как сделать, чтобы контейнер автоматически стартовал при загрузке хоста? Долгое время в Убунту и других дистрибутивах использовались init скрипты и симлинки в /etc/, но совсем недавно была реализована автозагрузка в upstream'е.

Как реализована сейчас автозагрузка контейнера? Каждый контейнер описывается своим конфигурационным файлом в /var/lib/lxc/имя-контейнера/config, в котором можно видеть строки
ключ = значение
Все значения можно прочесть в lxc.conf(5).

Значения, связанные с автостартом контейнера:

  • lxc.start.auto = 0 (выключено) или 1 (включено)
  • lxc.start.delay = 0 (задержка в секундах до автостарта контейнера)
  • lxc.start.order = 0 (приоритет контейнера, чем выше значение, тем раньше стартует контейнер)
  • lxc.group = group1,group2,group3,… (членами каких групп является контейнер)

Когда стартует хост-машина, init скрипт lxc-autostart запустит все контейнеры, у которых не указана группа, в правильном порядке и через определённое ими время, но в конфиге контейнера указано lxc.start.auto=1.

Чтобы показать работу механизма автостарта. Поправим /var/lib/lxc/p1/config и внесём:
lxc.start.auto = 1
lxc.group = ubuntu

В /var/lib/lxc/p2/config внесём:
lxc.start.auto = 1
lxc.start.delay = 5
lxc.start.order = 100

После перезагрузки хост-машины, только контейнер p2 стартанёт автоматически, так как он указан без группы. lxc.start.order не играет сейчас никакой роли, так как стартующий контейнер сейчас один, но будет 5 секундная задержка перед стартом p2.

Можно проверить, какие контейнеры автоматически стартуют, с помощью sudo lxc-ls --fancy

NAME    STATE    IPV4        IPV6                                    AUTOSTART     
---------------------------------------------------------------------------------
p1      RUNNING  10.0.3.128  2607:f2c0:f00f:2751:216:3eff:feb1:4c7f  YES (ubuntu)
p2      RUNNING  10.0.3.165  2607:f2c0:f00f:2751:216:3eff:fe3a:f1c1  YES

Можно с консоли управлять контейнерами, используя lxc-autostart и параметры start, stop, kill, reboot для любого контейнера, имеющего в его конфиге lxc.start.auto=1.

Для примера, команда sudo lxc-autostart -a запустит все контейнеры, имеющие lxc.start.auto=1, игнорируя значение lxc.group. В нашем случае с двумя контейнерами p1 и p2, сначала произойдёт запуск контейнера p2, из-за его приоритета order=100, но с задержкой в 5 секунд. Потом стартанёт p1.

Если нужно перезагрузить все контейнеры из группы Ubuntu, а у нас в примере это только p1, то командуем sudo lxc-autostart -r -g ubuntu

Ключ -L позволит увидеть какие контейнеры это затронет и как будет происходить автозапуск, но в реальности ничего не будет выполнено, что удобно при отладке.

Заморозка контейнеров.

Иногда контейнер активно не используется, а его периодический старт и выключение занимают определённое время. Есть возможность вместо выключения/включения контейнера использовать заморозку.

sudo lxc-freeze -n имя-контейнера замораживает все процессы в контейнере, так что они не тратят такты, отведённые им планировщиком. Однако процессы продолжают существовать и потреблять ОЗУ.

sudo lxc-unfreeze -n имя-контейнера позволит разморозить процессы в нужном вам контейнере.

Сеть.

По умолчанию в Ubuntu выделяется по одному veth устройству на контейнер, который соединён в сетевой мост с lxcbr0 на хосте и на нём запущен dnsmasq dhcp сервер.

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

Все сетевые возможности LXC можно узнать в lxc.conf(5), но один пример можно привести.

lxc.network.type = veth
lxc.network.hwaddr = 00:16:3e:3a:f1:c1
lxc.network.flags = up
lxc.network.link = lxcbr0
lxc.network.name = eth0

lxc.network.type = veth
lxc.network.link = virbr0
lxc.network.name = virt0

lxc.network.type = phys
lxc.network.link = eth2
lxc.network.name = eth1

Контейнер будет иметь 3 интерфейса:

  • eth0 (обычный veth) будет соединён в сетевой мост c lxcbr0.
  • eth1 - это проброшенный физический интерфейс eth2 хоста. Когда контейнер стартанёт, eth2 исчезнет в хост-машине.
  • virt0 ещё одно veth устройство, соединёное в мост с virbr0 хоста.

Последние 2 интерфейса не имеют MAC адреса и сетевых флагов (network.flags), поэтому они будут получать при загрузки данного контейнера всегда разные MAC адреса и данные интерфейсы нужно самим поднимать после старта контейнера.

Присоединение (Attach).

При условии, что используется ядро 3.8 и выше, можно использовать инструмент lxc-attach. Его основной задачей является дать shell внутри запущенного контейнера: sudo lxc-attach -n p1

Можно сразу выполнять команду в контейнере, используя sudo lxc-attach -n p1 -- restart ssh

Более опасный и мощный приём - sudo lxc-attach -n p1 -e -s 'NETWORK|UTSNAME'.

Где,
-e, --elevated-privileges - не сбрасывать привилегии, перед запуском команды внутри контейнера. Нужно применять с острожностью.
-s, --namespaces - указать пространства имён, к которым нужно подсоединиться. Разрешены MOUNT, PID, UTSNAME, IPC, USER и NETWORK.

Мы получим shell, говорящий нам root@p1, благодаря UTSNAME. Выполнив ifconfig -a, получим список сетевых интерфейсов контейнера. НО все остальные команды будут "от хоста". Ключ -e не даст ограничениям cgroup, apparmor применяться к любым процессам внутри данного shell. Чем это и опасно! Но время от времени, может быть полезным для запуска программ, расположенных в хост системе, но внутри контейнера с его сетью и пространством имён PID.

Проброс устройств внутри контейнера.

Вход в контейнер, запуск программ и выход из контейнера это всё замечательно, но что насчёт доступа к устройствам, подключённым к хосту?

По умолчанию, LXC пресекает такой доступ, используя devices cgroup как фильтрирующий механизм. Можно изменить конфигурацию контейнера, разрешив доступ к нужным устройствам и перезапустить контейнер.

Но для разовых вещей есть удобный инструмент lxc-device. Для примера, sudo lxc-device add -n p1 /dev/ttyUSB0 /dev/ttyS0 добавит (mknod) /dev/ttyS0 в контейнер с тем же типом, старшим (major), младшим (minor) числами под именем /dev/ttyUSB0 и добавит разрешающие записи cgroup.


Предыдущая статья LXC 1.0: Первый Ubuntu контейнер.
Следующая статья LXC 1.0: Продвинутое использование контейнера.

Дополнительные материалы:
Серия статей LXC 1.0. от Стефана Грабера.
LXC и Vagrant. 13 причин использовать Ubuntu Server. Часть 3.
Вход в систему Unity Greeter может аутентифицировать в системе, находящейся в LXC контейнере.

Немає коментарів:

Дописати коментар

HyperComments for Blogger

comments powered by HyperComments