Иногда требуется запустить docker в lxc, например, для установки Docker Swarm, или для установки Kubernetos. LXC позволяет запускать Docker внутри контейнера. Рекомендуется использовать хост машину Ubuntu 18.04.
Перейдите по ссылке, если вас интересует обычная настройка Docker Swarm.
Перейдите по ссылке, если вас интересует настройка Docker Swarm в LXC.
Прежде чем начать:
- выполните базовую настройку Ubuntu
- обновите ядро системы до версии 5.3
- установите LXC на Ubuntu по инструкции
На хост машине добавьте драйвера br_netfilter в автозагрузку:
echo overlay >> /etc/modules-load.d/docker.conf
echo br_netfilter >> /etc/modules-load.d/docker.conf
Для того, чтобы запустить Docker в LXC нужно выполнить следующие действия:
- запустить контейнер в privileged mode
- включить мод lxc nested containers
Запуск контейнера в privileged mode
Privileged mode - это привелигированный режим, запуск контейнера от рута.
Перед установкой контейнера, нужно закоментировать строки в файле /etc/lxc/default.conf. Комментировать строки, нужно только при установке контейнера, который вы хотите, чтобы он работал в привелигированном режиме.
#lxc.idmap = u 0 100000 65536
#lxc.idmap = g 0 100000 65536
Это позволит установить контейнер под рутом.
Выполните команду установки контейнера для Centos 7:
lxc-create -t download -n docker0 -- --dist centos --release 7 --arch amd64
Для Ubuntu 20.04
lxc-create -t download -n docker0 -- --dist ubuntu --release focal --arch amd64
Затем нужно обязательно раскоментировать эти строки обратно в файле /etc/lxc/default.conf
lxc.idmap = u 0 100000 65536
lxc.idmap = g 0 100000 65536
Настройка сети
Рекомендуется для LXC использовать сеть 172.30.0.1/24. Более подробный список указан в списке сетей.
В файле /etc/default/lxc-net пропишите
USE_LXC_BRIDGE="true"
LXC_BRIDGE="lxcbr0"
LXC_ADDR="172.30.0.1"
LXC_NETMASK="255.255.255.0"
LXC_NETWORK="172.30.0.0/24"
LXC_DHCP_RANGE="172.30.0.2,172.30.0.254"
LXC_DHCP_MAX="253"
LXC_DHCP_CONFILE=/etc/lxc/dnsmasq.conf
#LXC_DOMAIN="lxc"
Создайте файл /etc/lxc/dnsmasq.conf и пропишите в нем:
port=53
listen-address=172.30.0.1
LXC nested containers
Nested контейнер — это возможность запустить контейнер в контейнере (вложенные контейнеры). Чтобы включить данную опцию, нужно внести изменения в конфиг LXC контейнера.
Опция включается в файле конфига контейнера /var/lib/lxc/<название контейнера>/config
Раскоментируйте строчку:
#lxc.include = /usr/share/lxc/config/nesting.conf
Также вам понадобится прописать параметры для монтирования файловой системы cgroup и отключения AppArmor в контейнере
lxc.mount.auto = cgroup-full:rw
lxc.apparmor.profile = unconfined
lxc.cgroup.devices.allow = a
lxc.cap.drop =
Пропишите параметры сети:
lxc.net.0.ipv4.address = 172.30.0.20/24
lxc.net.0.ipv4.gateway = 172.30.0.1
Для Centos7 в файле /var/lib/lxc/docker0/rootfs/etc/sysconfig/network-scripts/ifcfg-eth0 укажите:
DEVICE=eth0
ONBOOT=yes
IPADDR=172.30.0.20
NETMASK=255.255.255.0
GATEWAY=172.30.0.1
DNS1=172.30.0.1
#BOOTPROTO=dhcp
HOSTNAME=test-centos
NM_CONTROLLED=no
TYPE=Ethernet
MTU=
DHCP_HOSTNAME=`hostname`
Для Ubuntu 20.04 в файле /var/lib/lxc/docker0/rootfs/etc/netplan/10-lxc.yaml укажите:
network:
version: 2
ethernets:
eth0:
dhcp4: no
dhcp6: no
addresses: [172.30.0.20/24]
gateway4: 172.30.0.1
nameservers:
addresses: [172.30.0.1]
Пересоздайте resolv.conf
rm /var/lib/lxc/docker0/rootfs/etc/resolv.conf
nano /var/lib/lxc/docker0/rootfs/etc/resolv.conf
Укажите в нем новый адреса DNS серверов:
nameserver 10.0.3.1
Скопируйте ssh ключ. Вместо /home/user укажите вашу домашнюю папку.
mkdir /var/lib/lxc/docker0/rootfs/root/.ssh
chmod 700 /var/lib/lxc/docker0/rootfs/root/.ssh
cat /home/alfa/.ssh/id_rsa.pub >> /var/lib/lxc/docker0/rootfs/root/.ssh/authorized_keys
chmod 600 /var/lib/lxc/docker0/rootfs/root/.ssh/authorized_keys
mkdir /var/lib/lxc/docker0/rootfs/home/ubuntu/.ssh
chmod 700 /var/lib/lxc/docker0/rootfs/home/ubuntu/.ssh
cat /home/alfa/.ssh/id_rsa.pub >> /var/lib/lxc/docker0/rootfs/home/ubuntu/.ssh/authorized_keys
chmod 600 /var/lib/lxc/docker0/rootfs/home/ubuntu/.ssh/authorized_keys
chown -R 1000:1000 /var/lib/lxc/docker0/rootfs/home/ubuntu/.ssh
Настройка контейнера Ubuntu 20.04
1) Запустите контейнер и подключитесь к нему:
lxc-start docker0
lxc-attach docker0
2) Установите программы:
apt update
apt install aptitude mc nano htop iftop bwm-ng iperf iperf3 iotop tmux screen openntpd sshfs net-tools
3) Отключите apparmor в LXC контейнере
systemctl stop apparmor
systemctl disable apparmor
4) Установите локаль. Раскоментируйте строки в файле /etc/locale.gen
en_US.UTF-8 UTF-8
ru_RU.UTF-8 UTF-8
Пропишите локаль на уровне системы:
nano /etc/profile.d/0.locale.sh
export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/sbin:/bin"
export LANG="en_US.UTF-8"
export LANGUAGE="en_US:en"
export LC_CTYPE="en_US.UTF-8"
export LC_NUMERIC="en_US.UTF-8"
export LC_TIME="en_US.UTF-8"
export LC_COLLATE="en_US.UTF-8"
export LC_MONETARY="en_US.UTF-8"
export LC_MESSAGES="en_US.UTF-8"
export LC_PAPER="en_US.UTF-8"
export LC_NAME="en_US.UTF-8"
export LC_ADDRESS="en_US.UTF-8"
export LC_TELEPHONE="en_US.UTF-8"
export LC_MEASUREMENT="en_US.UTF-8"
export LC_IDENTIFICATION="en_US.UTF-8"
export EDITOR=nano
Пересоздайте локаль:
locale-gen
5) Установите ssh сервер:
aptitude install openssh-server
6) Ограничьте размер логов systemd
Пропишите в /etc/systemd/journald.conf строчку:
SystemMaxUse=1G
Это строчка ограничивает максимальный размер логов в 1 гигабайт.
Перезагрузите конфигурацию systemd:
systemctl daemon-reload
7) Сделайте sudo su -l без ввода пароля
Добавьте группу wheel
groupadd -r wheel
usermod -a -G wheel ubuntu
в /etc/sudoers добавьте строчку
%wheel ALL=(ALL:ALL) NOPASSWD: ALL
Все пользователи, которые находятся в группе wheel будут иметь возможность выполнять команды рут без пароля
8) Далее нужно переподключиться к контейнеру через ssh.
Выйдите из контейнера:
exit
9) Подключитесь к контейнеру через ssh
Откройте терминал под текущим пользователем (не рут) и подключитесь к системе:
ssh root@172.30.0.20
Если сертификат установлен верно, то должно подключиться без пароля.
Установка Docker на Ubuntu 20.04
Установите Docker
curl -sSL https://get.docker.com | sh
systemctl enable docker
systemctl start docker
apt-get install docker-compose
Для хранения логов рекомендуется journald. В файле /etc/docker/daemon.json пропишите:
{
"log-driver": "journald",
"log-opts": {
"labels":"com.docker.swarm.service.name"
}
}
Проверьте запущен ли докер:
docker ps
Если выдает ошибку, значит проблема в файле /etc/docker/daemon.json. Пересоздайте его. Возможно в нем скопировались невидимые символы.
Добавьте в группу docker пользователя ubuntu чтобы он мог управлять docker
usermod -a -G docker ubuntu
Установка Docker на Centos 7
Запустите контейнер и войдите в него:
lxc-start docker0
lxc-attach docker0
Установите docker и включите автозапуск:
yum install -y yum-utils
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
yum install -y docker-ce docker-ce-cli containerd.io
systemctl enable docker
systemctl start docker
После установки, скачайте тестовый контейнер и убедитесь что он работает:
docker pull alpine
docker run -it -d --name test alpine /bin/sh
Выполните команду docker ps, должно вам выдать:
root@docker0:/# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
93f0d96197e0 alpine "/bin/sh" 28 seconds ago Up 25 seconds test
Проверьте работу контейнера:
root@docker0:/# docker exec -it test ping google.com
PING google.com (64.233.164.101): 56 data bytes
64 bytes from 64.233.164.101: seq=0 ttl=42 time=222.140 ms
64 bytes from 64.233.164.101: seq=1 ttl=42 time=140.911 ms
^C
--- google.com ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 140.911/181.525/222.140 ms
root@docker0:/# docker exec -it test ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:02
inet addr:172.17.0.2 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:34 errors:0 dropped:0 overruns:0 frame:0
TX packets:33 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:3728 (3.6 KiB) TX bytes:3293 (3.2 KiB)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
Возникаемые ошибки
Если возникают ошибки:
docker: Error response from daemon: Could not check if
docker-default AppArmor profile was loaded: open
/sys/kernel/security/apparmor/profiles: permission denied.
failed to register layer: Error processing tar file(exit status 1):
remount /, flags: 0x84000: permission denied
docker: Error response from daemon: OCI runtime create failed:
container_linux.go:345: starting container process caused
"process_linux.go:430: container init caused \"process_linux.go:396:
setting cgroup config for procHooks process caused \\\"
failed to write c 10:200 rwm to devices.allow: write /sys/fs/cgroup/devices/docker/27822e65d0ccd42267cd420309f1de3ea2ddfc353d18d9ab9d362b0549b43ed0/devices.allow:
operation not permitted\\\"\"": unknown.
То это скорее всего связано с AppArmor. Сделайте tail -n 20 /var/log/syslog. Если в логе присутсвуют следующие строки:
Jul 16 23:49:04 alfabook kernel:
[45843.968279] audit: type=1400 audit(1563299344.593:66):
apparmor="DENIED" operation="mount" info="failed flags match"
error=-13 profile="lxc-container-default-cgns" name="/"
pid=5274 comm="exe" flags="rw, rslave"
Jul 17 00:00:05 alfabook kernel:
[46504.633713] audit: type=1400 audit(1563300005.284:68):
apparmor="DENIED" operation="mount" info="failed flags match"
error=-13 profile="lxc-container-default-with-nesting"
name="/run/docker/runtime-runc/moby/0f36b9a62ec3234ad83b341a67f1a2f16c5db3dc55a6827720b85e30f0ecc547/runc.DcCoEi"
pid=7011 comm="exe" flags="ro, remount, bind"
Jul 17 00:00:05 alfabook kernel:
[46504.676276] audit: type=1400 audit(1563300005.328:69):
apparmor="DENIED" operation="mount" info="failed flags match"
error=-13 profile="lxc-container-default-with-nesting"
name="/var/lib/docker/overlay2/f40a7cc6f04db2b5cd48ddf8ec82303e07d9a744241250852c4462c12aa58df1/merged/"
pid=7028 comm="runc:[2:INIT]" srcname="/var/lib/docker/overlay2/f40a7cc6f04db2b5cd48ddf8ec82303e07d9a744241250852c4462c12aa58df1/merged/"
flags="rw, rbind"
То, да причина в AppArmor. Обычно в конфиг LXC lxc.apparmor.profile, lxc.mount.auto, lxc.cgroup.devices.allow помогает. Но если не помогло, то выполните следующие команды:
Включите обучение AppArmor
aa-complain /etc/apparmor.d/*
Запустите LXC контейнеры, и попробуйте заново запустить docker. Затем, после выдачи ошибки, перейдите на хост машину и выполните команду aa-logprof. Данная комманда анализирует лог /var/log/syslog и предлагает вам варианты патчинга правил AppArmor.
Пропатчите конфиг AppArmor и затем выключите обучение:
aa-enforce /etc/apparmor.d/*