Иногда требуется запустить docker в lxc, например, для установки Docker Swarm, или для установки Kubernetos. LXC позволяет запускать Docker внутри контейнера. Рекомендуется использовать хост машину Ubuntu 18.04.

Перейдите по ссылке, если вас интересует обычная настройка Docker Swarm .

Перейдите по ссылке, если вас интересует настройка Docker Swarm в LXC .

Прежде чем начать:

  1. выполните базовую настройку Ubuntu
  2. обновите ядро системы до версии 5.3
  3. установите LXC на Ubuntu по инструкции

На хост машине добавьте драйвера br_netfilter в автозагрузку:

_x000D_echo overlay >> /etc/modules-load.d/docker.conf_x000D_echo br_netfilter >> /etc/modules-load.d/docker.conf

Для того, чтобы запустить Docker в LXC нужно выполнить следующие действия:

  1. запустить контейнер в privileged mode
  2. включить мод lxc nested containers

Запуск контейнера в privileged mode

Privileged mode — это привелигированный режим, запуск контейнера от рута.

Перед установкой контейнера, нужно закоментировать строки в файле /etc/lxc/default.conf . Комментировать строки, нужно только при установке контейнера, который вы хотите, чтобы он работал в привелигированном режиме.

_x000D_#lxc.idmap = u 0 100000 65536_x000D_#lxc.idmap = g 0 100000 65536

Это позволит установить контейнер под рутом.

Выполните команду установки контейнера для Centos 7:

_x000D_lxc-create -t download -n docker0 -- --dist centos --release 7 --arch amd64

Для Ubuntu 20.04

_x000D_lxc-create -t download -n docker0 -- --dist ubuntu --release focal --arch amd64

Для Ubuntu 22.04:

_x000D_lxc-create -t download -n test-ubuntu -- --dist ubuntu --release bionic --arch amd64

Для Ubuntu 24.04:

_x000D_lxc-create -t download -n test-ubuntu -- --dist ubuntu --release noble --arch amd64

Затем нужно обязательно раскоментировать эти строки обратно в файле /etc/lxc/default.conf

_x000D_lxc.idmap = u 0 100000 65536_x000D_lxc.idmap = g 0 100000 65536

Настройка сети

Рекомендуется для LXC использовать сеть 172.30.0.1/24. Более подробный список указан в списке сетей .

В файле /etc/default/lxc-net пропишите

_x000D_USE_LXC_BRIDGE="true"_x000D_LXC_BRIDGE="lxcbr0"_x000D_LXC_ADDR="172.30.0.1"_x000D_LXC_NETMASK="255.255.255.0"_x000D_LXC_NETWORK="172.30.0.0/24"_x000D_LXC_DHCP_RANGE="172.30.0.2,172.30.0.254"_x000D_LXC_DHCP_MAX="253"_x000D_LXC_DHCP_CONFILE=/etc/lxc/dnsmasq.conf_x000D_#LXC_DOMAIN="lxc"

Создайте файл /etc/lxc/dnsmasq.conf и пропишите в нем:

_x000D_port=53_x000D_listen-address=172.30.0.1_x000D_resolv-file=/etc/resolv.conf_x000D_domain-needed_x000D_no-dhcp-interface=_x000D_interface=lxcbr0_x000D_except-interface=eth*_x000D_except-interface=enp*_x000D_except-interface=wlan*_x000D_except-interface=wlp*_x000D_except-interface=virbr0_x000D_except-interface=fan-*

Настройка конфига LXC контейнера

Nested контейнер — это возможность запустить контейнер в контейнере (вложенные контейнеры). Чтобы включить данную опцию, нужно внести изменения в конфиг LXC контейнера.

Опция включается в файле конфига контейнера /var/lib/lxc/<название контейнера>/config

Раскоментируйте строчку:

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

Пропишите параметры сети:

_x000D_lxc.net.0.ipv4.address = 172.30.0.20/24_x000D_lxc.net.0.ipv4.gateway = 172.30.0.1

Также вам понадобится прописать параметры для монтирования файловой системы cgroup и отключения AppArmor в контейнере

_x000D_lxc.mount.auto = cgroup-full:rw_x000D_lxc.apparmor.profile = unconfined_x000D_lxc.cgroup.devices.allow = a_x000D_lxc.cap.drop =

Для Ubuntu в файле /var/lib/lxc/<название контейнера>/rootfs/etc/netplan/10-lxc.yaml укажите:

_x000D_network:_x000D_ version: 2_x000D_ ethernets:_x000D_ eth0:_x000D_ dhcp4: no_x000D_ dhcp6: no_x000D_ addresses: [172.30.0.20/24]_x000D_ gateway4: 172.30.0.1_x000D_ nameservers:_x000D_ addresses: [172.30.0.1]_x000D_

Настройка доступа к видеокарте

Для доступа к видеокарте nvidia в конфиге контейнера укажите строки:

_x000D_# GPU_x000D_lxc.cgroup.devices.allow = c 195:* rwm_x000D_lxc.cgroup.devices.allow = c 243:* rwm_x000D_lxc.cgroup.devices.allow = c 510:* rwm_x000D_lxc.cgroup2.devices.allow = c 195:* rwm_x000D_lxc.cgroup2.devices.allow = c 243:* rwm_x000D_lxc.cgroup2.devices.allow = c 510:* rwm_x000D_lxc.mount.entry = /dev/nvidia0 dev/nvidia0 none bind,optional,create=file_x000D_lxc.mount.entry = /dev/nvidiactl dev/nvidiactl none bind,optional,create=file_x000D_lxc.mount.entry = /dev/nvidia-uvm dev/nvidia-uvm none bind,optional,create=file_x000D_lxc.mount.entry = /dev/nvidia-modeset dev/nvidia-modeset none bind,optional,create=file_x000D_lxc.mount.entry = /dev/nvidia-uvm-tools dev/nvidia-uvm-tools none bind,optional,create=file_x000D_

Настройка ssh сервера

1) Вместо /home/user укажите вашу домашнюю папку.

_x000D_mkdir /var/lib/lxc/<название контейнера>/rootfs/home/ubuntu/.ssh_x000D_cat /home/user/.ssh/id_rsa.pub >> /var/lib/lxc/<название контейнера>/rootfs/home/ubuntu/.ssh/authorized_keys_x000D_chmod 700 /var/lib/lxc/<название контейнера>/rootfs/home/ubuntu/.ssh_x000D_chmod 600 /var/lib/lxc/<название контейнера>/rootfs/home/ubuntu/.ssh/authorized_keys_x000D_chown -R 1000:1000 /var/lib/lxc/<название контейнера>/rootfs/home/ubuntu/.ssh

2) Запустите контейнер и подключитесь к нему:

_x000D_lxc-start <название контейнера>_x000D_lxc-attach <название контейнера>

3) Разрешите пинг

_x000D_sudo setcap cap_net_raw+ep /bin/ping

4) Установите ssh сервер:

_x000D_apt-get update_x000D_apt-get install openssh-server

5) Подключитесь к контейнеру через ssh

Откройте терминал под текущим пользователем (не рут) и подключитесь к системе:

_x000D_ssh ubuntu@172.30.0.20

Если сертификат установлен верно, то должно подключиться без пароля.

Настройка контейнера Ubuntu 24.04

1) Установите программы:

_x000D_apt update_x000D_apt install aptitude mc nano htop iftop bwm-ng iperf iperf3 iotop tmux screen net-tools rsync jq

2) Настройка DNS

Выполните

_x000D_rm /etc/resolv.conf_x000D_nano /etc/resolv.conf

Укажите следующие настройки

_x000D_nameserver 127.0.0.53_x000D_options edns0 trust-ad_x000D_ndots:1_x000D_search .

3) Отключите apparmor в LXC контейнере

_x000D_systemctl stop apparmor_x000D_systemctl disable apparmor

4) Установите локаль. Раскоментируйте строки в файле /etc/locale.gen

_x000D_en_US.UTF-8 UTF-8_x000D_ru_RU.UTF-8 UTF-8

Пропишите локаль на уровне системы:

nano /etc/profile.d/0.locale.sh

_x000D_export LANG="en_US.UTF-8"_x000D_export LANGUAGE="en_US:en"_x000D_export LC_CTYPE="en_US.UTF-8"_x000D_export LC_NUMERIC="en_US.UTF-8"_x000D_export LC_TIME="en_US.UTF-8"_x000D_export LC_COLLATE="en_US.UTF-8"_x000D_export LC_MONETARY="en_US.UTF-8"_x000D_export LC_MESSAGES="en_US.UTF-8"_x000D_export LC_PAPER="en_US.UTF-8"_x000D_export LC_NAME="en_US.UTF-8"_x000D_export LC_ADDRESS="en_US.UTF-8"_x000D_export LC_TELEPHONE="en_US.UTF-8"_x000D_export LC_MEASUREMENT="en_US.UTF-8"_x000D_export LC_IDENTIFICATION="en_US.UTF-8"_x000D_

Пересоздайте локаль:

_x000D_locale-gen

5) Установите ssh сервер:

_x000D_aptitude install openssh-server

6) Ограничьте размер логов systemd

Пропишите в /etc/systemd/journald.conf строчку:

_x000D_SystemMaxUse=1G

Это строчка ограничивает максимальный размер логов в 1 гигабайт.

Перезагрузите конфигурацию systemd:

_x000D_systemctl daemon-reload

7) Сделайте sudo su -l без ввода пароля

Добавьте группу wheel

_x000D_groupadd -r wheel_x000D_usermod -a -G wheel ubuntu

Создайте файл /etc/sudoers.d/wheel

_x000D_%wheel ALL=(ALL:ALL) NOPASSWD: ALL

Все пользователи, которые находятся в группе wheel будут иметь возможность выполнять команды рут без пароля

8) Установите iptables

_x000D_aptitude install iptables-persistent

Обязательно включите NAT, если вы хотите использовать Docker или LXC

_x000D_echo 1 > /proc/sys/net/ipv4/ip_forward_x000D_echo "net.ipv4.ip_forward=1" > /etc/sysctl.d/ip_forward.conf

При работе с iptables будьте осторожны.
Одно неверное движение и доступ к серверу может быть заблокирован!!!

Пример конфига /etc/iptables/rules.v4

_x000D_*filter_x000D_:INPUT ACCEPT [19:913]_x000D_:FORWARD ACCEPT [0:0]_x000D_:OUTPUT ACCEPT [39:3584]_x000D_:ALLOW-INPUT - [0:0]_x000D_:f2b-sshd - [0:0]_x000D__x000D_-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT_x000D_-A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT_x000D_-A INPUT -p icmp -j ACCEPT_x000D_-A INPUT -i lo -j ACCEPT_x000D__x000D_# Fail2Ban SSH_x000D_#-A INPUT -p tcp -m multiport --dports 22 -j f2b-sshd_x000D__x000D_# Разрешаем входящие соединения ssh_x000D_-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT_x000D__x000D_# Перейти к цепочке ALLOW-INPUT_x000D_-A INPUT -j ALLOW-INPUT_x000D__x000D_# Запрещаем остальные входящие соединения_x000D_-A INPUT -j REJECT_x000D_-A FORWARD -j REJECT_x000D__x000D_# Раскомментируйте, если нужно запретить все исходящие соединения _x000D_#-A OUTPUT -j REJECT_x000D__x000D_# Разрешить http_x000D_-A ALLOW-INPUT -p tcp -m tcp --dport 80 -j ACCEPT_x000D_-A ALLOW-INPUT -p tcp -m tcp --dport 443 -j ACCEPT_x000D_-A ALLOW-INPUT -j RETURN_x000D__x000D_# Fail2ban_x000D_-A f2b-sshd -j RETURN_x000D__x000D_COMMIT

Скопируйте этот же конфиг в /etc/iptables/rules.v6

_x000D_cp /etc/iptables/rules.v4 /etc/iptables/rules.v6

9) Перезагрузите контейнер:

_x000D_init 6

Установка Docker на Centos 7

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

_x000D_lxc-start <название контейнера>_x000D_lxc-attach <название контейнера>

Установите docker и включите автозапуск:

_x000D_yum install -y yum-utils_x000D_yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo_x000D_yum install -y docker-ce docker-ce-cli containerd.io_x000D__x000D_systemctl enable docker_x000D_systemctl start docker

Установка Docker на Ubuntu 24.04

Установите Docker

_x000D_sudo aptitude install docker.io

Альтернативный способ

_x000D_curl -sSL https://get.docker.com | sh_x000D_systemctl enable docker_x000D_systemctl start docker

Настройка Docker

Для хранения логов рекомендуется journald. В файле /etc/docker/daemon.json пропишите:

_x000D_{_x000D_ "log-driver": "json-file",_x000D_ "log-opts": {_x000D_ "max-size": "10m",_x000D_ "max-file": "1"_x000D_ }_x000D_}

Можно также добавить строчки

_x000D_"max-concurrent-uploads": 1,_x000D_"max-concurrent-downloads": 1,

Они позволяют ограничить количество потоков на загрузку докер образов. По умолчанию 3 потока.

Перезапустите докер

_x000D_service docker restart

Проверьте запущен ли докер:

_x000D_docker ps

Если выдает ошибку, значит проблема в файле /etc/docker/daemon.json . Пересоздайте его. Возможно в нем скопировались невидимые символы.

Добавьте в группу docker пользователя ubuntu чтобы он мог управлять docker

_x000D_usermod -a -G docker ubuntu

В крон через команду sudo crontab -e пропишите команду, которая будет автоматически очищать контейнеры

_x000D_0 */2 * * * docker system prune --filter "until=24h" -f -a > /dev/null_x000D_0 */2 * * * docker image prune --filter "until=168h" -f > /dev/null_x000D_

После установки, скачайте тестовый контейнер и убедитесь что он работает:

_x000D_docker pull alpine_x000D_docker run -it -d --name test alpine /bin/sh

Выполните команду docker ps , должно вам выдать:

_x000D_root@docker0:/# docker ps_x000D_CONTAINER ID IMAGE COMMAND CREATED STATUS  PORTS NAMES_x000D_93f0d96197e0 alpine  "/bin/sh"  28 seconds ago Up 25 seconds  test

Проверьте работу контейнера:

_x000D_root@docker0:/# docker exec -it test ping google.com_x000D_PING google.com (64.233.164.101): 56 data bytes_x000D_64 bytes from 64.233.164.101: seq=0 ttl=42 time=222.140 ms_x000D_64 bytes from 64.233.164.101: seq=1 ttl=42 time=140.911 ms_x000D_^C_x000D_--- google.com ping statistics ---_x000D_2 packets transmitted, 2 packets received, 0% packet loss_x000D_round-trip min/avg/max = 140.911/181.525/222.140 ms_x000D__x000D_root@docker0:/# docker exec -it test ifconfig_x000D_eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:02_x000D_ inet addr:172.17.0.2 Bcast:172.17.255.255 Mask:255.255.0.0_x000D_ UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1_x000D_ RX packets:34 errors:0 dropped:0 overruns:0 frame:0_x000D_ TX packets:33 errors:0 dropped:0 overruns:0 carrier:0_x000D_ collisions:0 txqueuelen:0_x000D_ RX bytes:3728 (3.6 KiB) TX bytes:3293 (3.2 KiB)_x000D__x000D_lo Link encap:Local Loopback_x000D_ inet addr:127.0.0.1 Mask:255.0.0.0_x000D_ UP LOOPBACK RUNNING MTU:65536 Metric:1_x000D_ RX packets:0 errors:0 dropped:0 overruns:0 frame:0_x000D_ TX packets:0 errors:0 dropped:0 overruns:0 carrier:0_x000D_ collisions:0 txqueuelen:1000_x000D_ RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)

Возникаемые ошибки

Если возникают ошибки:

_x000D_docker: Error response from daemon: Could not check if _x000D_docker-default AppArmor profile was loaded: open _x000D_/sys/kernel/security/apparmor/profiles: permission denied.
_x000D_failed to register layer: Error processing tar file(exit status 1): _x000D_remount /, flags: 0x84000: permission denied
_x000D_docker: Error response from daemon: OCI runtime create failed: _x000D_container_linux.go:345: starting container process caused _x000D_"process_linux.go:430: container init caused "process_linux.go:396: _x000D_setting cgroup config for procHooks process caused \""_x000D_failed to write c 10:200 rwm to devices.allow: write /sys/fs/cgroup/devices/docker/27822e65d0ccd42267cd420309f1de3ea2ddfc353d18d9ab9d362b0549b43ed0/devices.allow: _x000D_operation not permitted\"""""": unknown._x000D_

То это скорее всего связано с AppArmor. Сделайте tail -n 20 /var/log/syslog. Если в логе присутсвуют следующие строки:

_x000D_Jul 16 23:49:04 alfabook kernel: _x000D_[45843.968279] audit: type=1400 audit(1563299344.593:66): _x000D_apparmor=""DENIED"" operation=""mount"" info=""failed flags match"" _x000D_error=-13 profile=""lxc-container-default-cgns"" name=""/"" _x000D_pid=5274 comm=""exe"" flags=""rw