Запуск Docker в LXC 2

Это может показаться довольно странным, на первый взгляд, однако, в определенных случаях может быть весьма полезным. Например, в случае если необходимо на тестовом сервере выделить площадку для разработки с возможностью запускать привилегированные контейнеры Docker. В случае, если вся работа происходит на одном сервере, то пользователь получает доступ сразу ко всем контейнерам/образам на сервере, что неправильно с точки зрения безопасности. С другой стороны, такие системы виртуализации, как QEMU/KVM или Xen обладают определенным оверхедом по производительности и сложнее в настройке. LXC, в данном случае, позволяет обойти оба этих недостатка.

Теория

Как известно, контейнеры LXC и Docker основаны на идентичных технологиях — cgroups, которые могут быть неограниченно вложенными. Отсюда следует, что уровень вложенности контейнеров также неограничен, все что необходимо — возможность создавать новые cgroups.

Как и многое другое в UNIX, cgroups представлены в файловой семантике, то есть каждая группа — это папка в псевдофайловой системе в /sys/fs/cgroup/<controller_name>/.

Для виртуализации системных каталогов, общих для хост-машины (/proc/ и /sys/) и контейнеров LXC использует технологию LXCFS, которая монтирует статические файлы поверх данных директорий в контейнерах. Так как основное дерево cgroups расположено в /sys/, необходимо отключить LXCFS.

Однако, разграничение ресурсов между контейнерами LXC основано еще на двух технологиях: AppArmor и Capabilities, доступ к которым также присутствовать у контейнера для создания дочерних контейнеров. Первая используется для того, чтобы контейнер не мог изменить ресурсы, разделяемые с хост-машиной и другими контейнерами. Вторая — позволяет внести дополнительные ограничения контейнер (по умолчанию на привилегированные контейнеры отсутствуют какие-либо ограничения со стороны capabilities), например запретить доступ к привилегированным портам TCP/UDP, возможность менять владельца файлов и др.

Таким образом, для того, чтобы создавать субконтейнеры, необходимо дать доступ контейнеру с возможностью записи с этим трем подсистемам хост-машины — cgroups, AppArmor и capabilities. Это подразумевает под собой определенные риски, т. к. получается, что, теоретически, каждый контейнер может изменить параметры другого контейнера. Это необходимо принять во внимание перед внедрением данного решения. С другой стороны, дочерние контейнеры не обязаны наследовать эти параметры от родителя (а в случае с Docker, они не наследуются, если не задать обратное явно в файле конфигурации), и приложения внутри них будут также изолированы от окружающей среды, как если бы эти контейнеры были запущены на хост-машине.

Практика

В данном примере используется Debian 8 и привилегированные контейнеры LXC. Совет — для того чтобы сделать доступными все возможности LXC и Docker (overlayfs, docker swarm), установите из бекпортов свежее ядро и LXC (здесь и далее вывод команд пропущен):

root@sol:~# echo "deb http://mirror.yandex.ru/debian/ jessie-backports main" >> /etc/apt/sources.list.d/backports.list
root@sol:~# apt-get update
root@sol:~# apt-get install -t jessie-backports linux-image-amd64 lxc

Отключите LXCFS:

root@sol:~# systemctl stop lxcfs
root@sol:~# systemctl disable lxcfs

Создайте контейнер LXC:

root@sol:~# lxc-create -t debian -n dock0

В зависимости от вашей конфигурации, вам могут потребоваться дополнительные действия с контейнером (например, настройка сети). В моем случае получился следующий конфиг в /var/lib/lxc/dock0/config:

# Template used to create this container: /usr/share/lxc/templates/lxc-debian
# Parameters passed to the template:
# Template script checksum (SHA-1): 2ad4d9cfe8988ae453172bd4fe3b06cf91756168
# For additional config options, please look at lxc.container.conf(5)

# Uncomment the following line to support nesting containers:
#lxc.include = /usr/share/lxc/config/nesting.conf
# (Be aware this has security implications)

lxc.network.type = veth
lxc.network.hwaddr = 00:16:3e:af:12:18
lxc.network.link = br0
lxc.network.name = eth0
lxc.network.flags = up
lxc.start.auto = 1
lxc.start.delay = 2
lxc.rootfs = /var/lib/lxc/dock0/rootfs
lxc.rootfs.backend = dir

# Common configuration
lxc.include = /usr/share/lxc/config/debian.common.conf

# Container specific configuration
lxc.tty = 4
lxc.utsname = test
lxc.arch = amd64

Внесите следующие изменения в конфигурационный файл:

Раскомментируйте данную строку, она убирает ограничения AppArmor и capabilities:

lxc.include = /usr/share/lxc/config/nesting.conf

Добавьте следующие строки:

 

lxc.network.ipv4 = 172.16.1.253/24 172.16.1.255
lxc.network.ipv4.gateway = 172.16.1.1
lxc.mount.auto = cgroup-full:rw

Первые две строки необязательны — это настройка сети. Третья монтирует с хост-машины директорию с cgroups

Запустите контейнер:

root@sol:~# lxc-start -n dock0

Установите и протестируйте работу Docker:

Установка:

root@dock0:~# apt-get update
root@dock0:~# apt-get install apt-transport-https curl gnupg
root@dock0:~# echo deb https://download.docker.com/linux/debian jessie stable >> /etc/apt/sources.list.d/docker.list
root@dock0:~# curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add -
root@dock0:~# apt-get update
root@dock0:~# apt-get install docker-ce

Проверка работоспособности:

root@dock0:~# docker run -d --rm postgres:9.6
Unable to find image 'postgres:9.6' locally
9.6: Pulling from library/postgres
ad74af05f5a2: Pull complete
8996b4a29b2b: Pull complete
c03b4ca2b603: Pull complete
3243337e6ae1: Pull complete
ce0a50b46ced: Pull complete
97177a7c64ab: Pull complete
b5fb28a05da6: Pull complete
ae499890cb44: Pull complete
d2c07cb2c5c1: Pull complete
92eecd72c92a: Pull complete
56de99a4d80f: Pull complete
607901f31580: Pull complete
Digest: sha256:b8bf3cb0e7d660964e92b57fda1e8571eff9c852426c948f7a0871ad8e8faa62
Status: Downloaded newer image for postgres:9.6
eba9357d95fb675b74580324124a375c130fcb855098a42c6d92884e1238ee58
root@dock0:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
eba9357d95fb postgres:9.6 "docker-entrypoint..." 5 seconds ago Up 3 seconds 5432/tcp eloquent_volhard
root@test:~#

Готово! LXC никак не влияет на функционал контейнеров Docker они полностью аналогичны установленным на bare metal.

Добавить комментарий