Docker в LXC без Swarm
Иногда требуется запустить 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
Для Ubuntu 22.04:
lxc-create -t download -n test-ubuntu -- --dist ubuntu --release bionic --arch amd64
Для Ubuntu 24.04:
lxc-create -t download -n test-ubuntu -- --dist ubuntu --release noble --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
resolv-file=/etc/resolv.conf
domain-needed
no-dhcp-interface=
interface=lxcbr0
except-interface=eth*
except-interface=enp*
except-interface=wlan*
except-interface=wlp*
except-interface=virbr0
except-interface=fan-*
Настройка конфига LXC контейнера
Nested контейнер — это возможность запустить контейнер в контейнере (вложенные контейнеры). Чтобы включить данную опцию, нужно внести изменения в конфиг LXC контейнера.
Опция включается в файле конфига контейнера /var/lib/lxc/<название контейнера>/config
Раскоментируйте строчку:
#lxc.include = /usr/share/lxc/config/nesting.conf
Пропишите параметры сети:
lxc.net.0.ipv4.address = 172.30.0.20/24
lxc.net.0.ipv4.gateway = 172.30.0.1
Также вам понадобится прописать параметры для монтирования файловой системы cgroup и отключения AppArmor в контейнере
lxc.mount.auto = cgroup-full:rw
lxc.apparmor.profile = unconfined
lxc.cgroup.devices.allow = a
lxc.cap.drop =
Для Ubuntu в файле /var/lib/lxc/<название контейнера>/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]
Настройка доступа к видеокарте
Для доступа к видеокарте nvidia в конфиге контейнера укажите строки:
# GPU
lxc.cgroup.devices.allow = c 195:* rwm
lxc.cgroup.devices.allow = c 243:* rwm
lxc.cgroup.devices.allow = c 510:* rwm
lxc.cgroup2.devices.allow = c 195:* rwm
lxc.cgroup2.devices.allow = c 243:* rwm
lxc.cgroup2.devices.allow = c 510:* rwm
lxc.mount.entry = /dev/nvidia0 dev/nvidia0 none bind,optional,create=file
lxc.mount.entry = /dev/nvidiactl dev/nvidiactl none bind,optional,create=file
lxc.mount.entry = /dev/nvidia-uvm dev/nvidia-uvm none bind,optional,create=file
lxc.mount.entry = /dev/nvidia-modeset dev/nvidia-modeset none bind,optional,create=file
lxc.mount.entry = /dev/nvidia-uvm-tools dev/nvidia-uvm-tools none bind,optional,create=file
Настройка ssh сервера
1) Вместо /home/user укажите вашу домашнюю папку.
mkdir /var/lib/lxc/<название контейнера>/rootfs/home/ubuntu/.ssh
cat /home/user/.ssh/id_rsa.pub >> /var/lib/lxc/<название контейнера>/rootfs/home/ubuntu/.ssh/authorized_keys
chmod 700 /var/lib/lxc/<название контейнера>/rootfs/home/ubuntu/.ssh
chmod 600 /var/lib/lxc/<название контейнера>/rootfs/home/ubuntu/.ssh/authorized_keys
chown -R 1000:1000 /var/lib/lxc/<название контейнера>/rootfs/home/ubuntu/.ssh
2) Запустите контейнер и подключитесь к нему:
lxc-start <название контейнера>
lxc-attach <название контейнера>
3) Разрешите пинг
sudo setcap cap_net_raw+ep /bin/ping
4) Установите ssh сервер:
apt-get update
apt-get install openssh-server
5) Подключитесь к контейнеру через ssh
Откройте терминал под текущим пользователем (не рут) и подключитесь к системе:
ssh ubuntu@172.30.0.20
Если сертификат установлен верно, то должно подключиться без пароля.
Настройка контейнера Ubuntu 24.04
1) Установите программы:
apt update
apt install aptitude mc nano htop iftop bwm-ng iperf iperf3 iotop tmux screen net-tools rsync jq
2) Настройка DNS
Выполните
rm /etc/resolv.conf
nano /etc/resolv.conf
Укажите следующие настройки
nameserver 127.0.0.53
options edns0 trust-ad
ndots:1
search .
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 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"
Пересоздайте локаль:
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.d/wheel
%wheel ALL=(ALL:ALL) NOPASSWD: ALL
Все пользователи, которые находятся в группе wheel будут иметь возможность выполнять команды рут без пароля
8) Установите iptables
aptitude install iptables-persistent
Обязательно включите NAT, если вы хотите использовать Docker или LXC
echo 1 > /proc/sys/net/ipv4/ip_forward
echo "net.ipv4.ip_forward=1" > /etc/sysctl.d/ip_forward.conf
При работе с iptables будьте осторожны.
Одно неверное движение и доступ к серверу может быть заблокирован!!!
Пример конфига /etc/iptables/rules.v4
*filter
:INPUT ACCEPT [19:913]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [39:3584]
:ALLOW-INPUT - [0:0]
:f2b-sshd - [0:0]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
# Fail2Ban SSH
#-A INPUT -p tcp -m multiport --dports 22 -j f2b-sshd
# Разрешаем входящие соединения ssh
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
# Перейти к цепочке ALLOW-INPUT
-A INPUT -j ALLOW-INPUT
# Запрещаем остальные входящие соединения
-A INPUT -j REJECT
-A FORWARD -j REJECT
# Раскомментируйте, если нужно запретить все исходящие соединения
#-A OUTPUT -j REJECT
# Разрешить http
-A ALLOW-INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A ALLOW-INPUT -p tcp -m tcp --dport 443 -j ACCEPT
-A ALLOW-INPUT -j RETURN
# Fail2ban
-A f2b-sshd -j RETURN
COMMIT
Скопируйте этот же конфиг в /etc/iptables/rules.v6
cp /etc/iptables/rules.v4 /etc/iptables/rules.v6
9) Перезагрузите контейнер:
init 6
Установка Docker на Centos 7
Запустите контейнер и войдите в него:
lxc-start <название контейнера>
lxc-attach <название контейнера>
Установите 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 на Ubuntu 24.04
Установите Docker
sudo aptitude install docker.io
Альтернативный способ
curl -sSL https://get.docker.com | sh
systemctl enable docker
systemctl start docker
Настройка Docker
Для хранения логов рекомендуется journald. В файле /etc/docker/daemon.json пропишите:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "1"
}
}
Можно также добавить строчки
"max-concurrent-uploads": 1,
"max-concurrent-downloads": 1,
Они позволяют ограничить количество потоков на загрузку докер образов. По умолчанию 3 потока.
Перезапустите докер
service docker restart
Проверьте запущен ли докер:
docker ps
Если выдает ошибку, значит проблема в файле /etc/docker/daemon.json. Пересоздайте его. Возможно в нем скопировались невидимые символы.
Добавьте в группу docker пользователя ubuntu чтобы он мог управлять docker
usermod -a -G docker ubuntu
В крон через команду sudo crontab -e пропишите команду, которая будет автоматически очищать контейнеры
0 */2 * * * docker system prune --filter "until=24h" -f -a > /dev/null
0 */2 * * * docker image prune --filter "until=168h" -f > /dev/null
После установки, скачайте тестовый контейнер и убедитесь что он работает:
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/*