Настройка Docker Swarm в LXC контейнерах.
Предисловие
Docker Swarm — это простой кластер. Для его создания нужно несколько машин. Чтобы развернуть кластер на локалке, нужно сначала запустить виртуальные машины, а в них настроить кластер. Для этой задачи хорошо подойдут LXC контейнеры. LXC контейнеры в отличии от VirtualBox не будут требовать резервирования оперативной памяти. Также LXC выполняется на том же ядре, что и хост, это ускорит работу Docker Swarm.
Инструкция по запуску Docker Swarm на локальной машине
Для запуска Docker swarm на локальной машине необходимо создать два и более LXC контейнера, установить туда Docker и иницировать Swarm. Контейнеры с докер должны работать в привелигированном режиме.
Перед тем как настривать Docker Swarm в LXC установите:
- новое ядро 5.3
- программу 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А также в /etc/hosts пропишите IP адреса контейнеров
_x000D_172.30.0.20 docker0_x000D_172.30.0.21 docker1Установка драйвера br_netfilter
На хост машине сделайте:
_x000D_echo overlay >> /etc/modules-load.d/docker.conf_x000D_echo br_netfilter >> /etc/modules-load.d/docker.confУстановка контейнера docker0
Все команды надо делать по рутом.
1) В файле /etc/lxc/default.conf закоментируйте строчки:
_x000D_#lxc.idmap = u 0 100000 65536_x000D_#lxc.idmap = g 0 100000 655362) Установитк два контейнера:
_x000D_lxc-create -t download -n docker0 -- --dist ubuntu --release focal --arch amd64_x000D_lxc-create -t download -n docker1 -- --dist ubuntu --release focal --arch amd643) Раскоментируйте обратнр строчки
_x000D_lxc.idmap = u 0 100000 65536_x000D_lxc.idmap = g 0 100000 655364) Внесите изменения в файл /var/lib/lxc/docker0/config
Раскоментируйте строку
_x000D_lxc.include = /usr/share/lxc/config/nesting.confЭто позволит создать Nested контейнер — возможность запустить контейнер в контейнере (вложенные контейнеры).
Добавьте в файл следующие строки
_x000D_lxc.net.0.ipv4.address = 172.30.0.20/24_x000D_lxc.net.0.ipv4.gateway = 172.30.0.1_x000D_lxc.mount.auto = cgroup-full:rw_x000D_lxc.apparmor.profile = unconfined_x000D_lxc.cgroup.devices.allow = a_x000D_lxc.cap.drop =В файле /var/lib/lxc/docker0/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]5) Пересоздайте resolv.conf
_x000D_rm /var/lib/lxc/docker0/rootfs/etc/resolv.conf_x000D_nano /var/lib/lxc/docker0/rootfs/etc/resolv.confУкажите в нем новый адреса DNS серверов:
_x000D_nameserver 172.30.0.1Достаточно указать ДНС 172.30.0.1. На хост машине запускается dnsmasq на этом адресе и является проксирующим ДНС. Также он резолвит все домены из /etc/hosts. Поэтому при настройке сети на хосте нужно было в /etc/hosts прописать IP адреса контейнеров docker0 и docker1.
6) Скопируйте ssh ключ. Вместо /home/user укажите вашу домашнюю папку.
_x000D_mkdir /var/lib/lxc/docker0/rootfs/root/.ssh_x000D_chmod 700 /var/lib/lxc/docker0/rootfs/root/.ssh_x000D_cat /home/user/.ssh/id_rsa.pub >> /var/lib/lxc/docker0/rootfs/root/.ssh/authorized_keys_x000D_chmod 600 /var/lib/lxc/docker0/rootfs/root/.ssh/authorized_keys_x000D__x000D_mkdir /var/lib/lxc/docker0/rootfs/home/ubuntu/.ssh_x000D_chmod 700 /var/lib/lxc/docker0/rootfs/home/ubuntu/.ssh_x000D_cat /home/user/.ssh/id_rsa.pub >> /var/lib/lxc/docker0/rootfs/home/ubuntu/.ssh/authorized_keys_x000D_chmod 600 /var/lib/lxc/docker0/rootfs/home/ubuntu/.ssh/authorized_keys_x000D_chown -R 101000:101000 /var/lib/lxc/docker0/rootfs/home/ubuntu/.ssh7) Запустите контейнер и подключитесь к нему:
_x000D_lxc-start docker0_x000D_lxc-attach docker08) Установите программы:
_x000D_apt update_x000D_apt install aptitude mc nano htop iftop bwm-ng iperf iperf3 iotop tmux screen openntpd sshfs net-tools dnsutils bind9-utils9) Установите локаль. Раскоментируйте строки в файле /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 PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/sbin:/bin"_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_export EDITOR=nano_x000D_Пересоздайте локаль:
_x000D_locale-gen10) Установите ssh сервер:
_x000D_aptitude install openssh-server11) Далее нужно переподключиться к контейнеру через ssh.
Выйдите из контейнера:
_x000D_exitНастройка конфига ssh
Для упрощения подключения к контейнерам, рекомендуется в локальной домашней папке в файле ~/.ssh/config прописать параметры docker0 и docker1
_x000D_Host *_x000D_ Protocol 2_x000D_ KeepAlive yes_x000D_ TCPKeepAlive yes_x000D_ ServerAliveInterval 5_x000D_ ServerAliveCountMax 100_x000D_ Compression no_x000D_ #CompressionLevel 9_x000D_ #ForwardX11 yes_x000D_ UseRoaming no_x000D__x000D_Host docker0_x000D_ Hostname 172.30.0.20_x000D_ User ubuntu_x000D_ Port 22_x000D__x000D_Host docker1_x000D_ Hostname 172.30.0.21_x000D_ User ubuntu_x000D_ Port 22После внесенных изменений подключаться можно будет по командам:
_x000D_ssh docker0_x000D_ssh docker1или:
_x000D_ssh root@docker0_x000D_ssh root@docker1Настройка контейнера docker0
1) Подключитесь к контейнеру через ssh
Откройте терминал под текущим пользователем (не рут) и подключитесь к системе:
_x000D_ssh docker0Если сертификат установлен верно, то должно подключиться без пароля.
2) Ограничьте размер логов systemd
Пропишите в /etc/systemd/journald.conf строчку:
_x000D_SystemMaxUse=1GЭто строчка ограничивает максимальный размер логов в 1 гигабайт.
Перезагрузите конфигурацию systemd:
_x000D_systemctl daemon-reload3) Сделайте sudo su -l без ввода пароля
Добавьте группу wheel
_x000D_groupadd -r wheel_x000D_usermod -a -G wheel ubuntuв /etc/sudoers добавьте строчку
_x000D_%wheel ALL=(ALL:ALL) NOPASSWD: ALLВсе пользователи, которые находятся в группе wheel будут иметь возможность выполнять команды рут без пароля
4) Добавьте группу www
_x000D_groupadd -g 800 -r www_x000D_useradd -u 800 -g 800 -r www_x000D_mkdir /home/www_x000D_chown www:www /home/www_x000D_usermod -d /home/www www_x000D_usermod -s /bin/bash www5) Установите Docker
_x000D_curl -sSL https://get.docker.com | sh_x000D_systemctl enable docker_x000D_systemctl start docker_x000D_apt-get install docker-composeДля хранения логов рекомендуется journald. В файле /etc/docker/daemon.json пропишите:
_x000D_{_x000D_ "log-driver": "json-file",_x000D_ "log-opts": {_x000D_ "max-size": "10m",_x000D_ "max-file": "1"_x000D_ }_x000D_}6) Отключите apparmor в LXC контейнере
_x000D_systemctl stop apparmor_x000D_systemctl disable apparmor7) Проверьте запущен ли докер:
_x000D_docker psЕсли выдает ошибку, значит проблема в файле /etc/docker/daemon.json . Пересоздайте его. Возможно в нем скопировались невидимые символы.
8) Добавьте в группу docker пользователя ubuntu чтобы он мог управлять docker
_x000D_usermod -a -G docker ubuntu_x000D_usermod -a -G docker wwwУстановка контейнера docker1
Зайдите по рут на хост машине. Остановите контейнер docker0.
_x000D_lxc-stop docker0Скопируйте docker0 в docker1
_x000D_mkdir /var/lib/lxc/docker1_x000D_cp -rfpH /var/lib/lxc/docker0/* /var/lib/lxc/docker1Поменяйте rootfs, hostname, IP и MAC адрес в файле /var/lib/lxc/docker1/config
_x000D_lxc.rootfs.path = dir:/var/lib/lxc/docker1/rootfs_x000D_lxc.uts.name = docker1_x000D_lxc.net.0.hwaddr = 00:16:3e:c5:02:e9_x000D_lxc.net.0.ipv4.address = 172.30.0.21/24Также в файле /var/lib/lxc/docker1/rootfs/etc/netplan/10-lxc.yaml
_x000D_addresses: [172.30.0.21/24]В файле /var/lib/lxc/docker1/rootfs/etc/hosts
_x000D_127.0.1.1 docker1_x000D_127.0.0.1 localhost_x000D_::1 localhost ip6-localhost ip6-loopback_x000D_ff02::1 ip6-allnodes_x000D_ff02::2 ip6-allroutersВ файле /var/lib/lxc/docker1/rootfs/etc/hostname
_x000D_docker1Настройка кластера
1) Запустите оба контейнера:
_x000D_lxc-start docker0_x000D_lxc-start docker1Подключитесь из двух терминалов к контейнерам:
_x000D_ssh docker0_x000D_ssh docker12) На docker0 создайте кластер
_x000D_docker swarm init --advertise-addr 172.30.0.203) Эта команда выдаст токен. Искользуйте его, чтобы на docker1 подключитесь к кластеру
_x000D_docker swarm join --token TOKEN 172.30.0.20:2377Кластер создан. Если вы забыли Token, то введите команду docker swarm join-token manager на primary node
Проверка работы кластера
Создайте файл compose.yaml
_x000D_version: "3.3"_x000D__x000D_services:_x000D_ nginx:_x000D_ image: nginx:latest_x000D_ labels:_x000D_ name: nginx_x000D_ version: 1.0_x000D_ deploy:_x000D_ replicas: 1_x000D_ endpoint_mode: dnsrr_x000D_ update_config:_x000D_ parallelism: 1_x000D_ failure_action: rollback_x000D_ delay: 5s_x000D_ restart_policy:_x000D_ condition: "on-failure"_x000D_ delay: 10s_x000D_ window: 120s_x000D_ placement:_x000D_ constraints:_x000D_ - "node.hostname == docker1"_x000D_ ports:_x000D_ - target: 80_x000D_ published: 80_x000D_ protocol: tcp_x000D_ mode: host_x000D_ networks:_x000D_ - backend_x000D_ logging:_x000D_ driver: journald_x000D_ _x000D_networks:_x000D__x000D_ backend:_x000D_ driver: overlay_x000D_ attachable: trueЗапустите сервис
_x000D_docker stack deploy --compose-file compose.yaml devПодождите некоторое время и проверьте запустился ли контейнер на хосте docker1 командой docker ps
Если он не запускается, узнайте ошибку
_x000D_docker service ps --no-trunc dev_nginxОбратите внимание, что указан параметр mode: host в секции проброса 80 порта. Это означает, что нужно по http обращаться к серверу docker1, т.к. на нем должен запуститься контейнер.
Исправление ошибок при запуске Docker Swarm
1) Если Docker swarm в LXC выдает ошибку:
_x000D_WARNING: No swap limit support_x000D_WARNING: bridge-nf-call-iptables is disabled_x000D_WARNING: bridge-nf-call-ip6tables is disabledили
_x000D_Failed creating ingress network: error creating external connectivity network: cannot restrict inter-container communication: please ensure that br_netfilter kernel module is loadedТо это означает, что у вас установлено старое ядро. Обновите ядро на хост машине согласно инструкции .
И не загружен модуль ядра br_netfilter. Его нужно загрузить командой:
_x000D_modprobe br_netfilter_x000D_modprobe overlayИли прописать его в автозагрузку (об этом ниже в инструкции).
Более подробно об этой ошибке:
https://github.com/lxc/lxd/issues/5193#issuecomment-431693318
https://bugs.launchpad.net/ubuntu/+source/docker.io/+bug/1618283
2) Может возникнуть эта ошибка;
_x000D_Starting container failed: container: endpoint create on GW Network failed: failed to create endpoint gateway_00555448fe8e on network docker_gwbridge: network does not existи syslog будет выдавать следующее
_x000D_$ tail -n 20 /var/log/syslog_x000D__x000D_[ 3419.850480] br0: port 2(veth0) entered blocking state_x000D_[ 3419.850486] br0: port 2(veth0) entered forwarding state_x000D_[ 3419.943752] br0: port 2(veth0) entered disabled state_x000D__x000D_Oct 16 08:38:25 docker0 kernel: [ 3285.847755] veth0: renamed from veth945e509_x000D_Oct 16 08:38:25 docker0 kernel: [ 3285.964009] eth0: renamed from veth6d61c08_x000D_Oct 16 08:38:25 docker0 kernel: [ 3286.135717] br0: port 3(veth1) entered disabled state_x000D_Oct 16 08:38:25 docker0 kernel: [ 3286.136040] br0: port 3(veth1) entered blocking state_x000D_Oct 16 08:38:25 docker0 kernel: [ 3286.136043] br0: port 3(veth1) entered forwarding state_x000D_Это связано тоже с версией ядра и тем, что модуль br_netfilter не загружен.
3) Не пингуются контейнеры между собой и не пробрасывается порт. Это происходит по одной причине. Почему то виртуальные IP адреса и ingress в докер под LXC не работают. Решается это просто. Нужно включить dnsrr (DNS Round Robin) в секции для каждого сервиса и использовать mode: host при проброске портов.
DNS Round Robin — это способ адресации к сервисам. В докере существуют два способа через виртуальные ip адреса (по умолчанию) и через DNS Round Robin. При использовании виртуальных IP адресов, для каждого сервиса создается IP адрес и все контейнеры его получают при поиске сервиса. При отправке пакета на этот IP адрес, докер сам разруливает к какому контейнеру отправить запрос. Получается виртуальный IP адрес — это промежуточный IP адрес. При использовании DNS Round Robin будут другие контейнеры будут получать прямые IP адреса контейнеров.
mode: host отвечает за проброс портов. Существует два варианта ingress (по умолчанию) и host. При использовании ingress обращение на порт любого серверу в Docker кластере будет переадресовано в контейнер, где указан проброс этого порта. Если поставить mode: host, то проброс потров будет работать только на том сервер, где запустился этот контейнер.