Proxmox. Часть 7. Разворачивание кластера Docker Swarm
Продолжим 5 и 6 часть заметок по Proxmox и развернем еще 3 примера разных сервисов. Но в данной части использовать будет не просто Docker, а платформа оркестровки контейнеров Docker Swarm, которая доступна из «коробки», если у вас установлен сам Docker.
Что такое Docker Swarm?
Docker Swarm — это стандартный, легкий и простой оркестратор для docker контейнеров с ограниченными возможностями.
Для дальнейшей работы следует иметь представление о нескольких сущностях Docker Swarm:
- Node — это виртуальные машины, на которых установлен docker. Есть manager и workers ноды. Manager нода управляет workers нодами. Она получает запросы и распределяют задачи на workers ноды. Workers ноды используются только для выполнения поставленных задач и не могут управлять кластером.
- Stack — это набор сервисов, которые логически связаны между собой. По сути это набор сервисов, которые мы описываем в обычном docker-compose файле.
- Service — это сущность из которых состоит stack. Service — описание процесса создания docker контейнеров. Такие же сервисы мы описываем в docker-compose.yml.
- Task — это контейнер, который docker создал на основе той информации, которую мы указали при описании service. Docker Swarm будет следить за состоянием контейнера и при необходимости его перезапускать или перемещать на другую ноду.
Разворачивание кластера Docker Swarm
Создадим кластер Docker Swarm состоящий из 2-х worker node и 1 manager node. Для этого создадим 3-и виртуальные машины на основе шаблона виртуальной машины 9000:
Запускаем виртуальные машины. После запуска виртуальных машин проверим их ip:
ip a
Заметим, что каждой виртуальной машине достается один и тот же ip адрес. Помогает сбрасывание сетевой конфигурации на каждой виртуальной машине и последующая перезагрузка:
sudo rm -f /etc/machine-id
sudo systemd-machine-id-setup
sudo rm -f /var/lib/dhcp/dhclient.leases
После выполнения команд и перезагрузки всех трех виртуальных машин проверим получаемые ip адреса, они должны быть уникальные!
На каждой из 3-х машин установим Docker в соответствии с инструкцией из 5-ой части.
На виртуальной машине manager1 (192.168.31.199) инициализируем кластер Docker Swarm:
sudo docker swarm init --advertise-addr 192.168.31.199
В ответ получаем команду, которую надо выполнить на worker нодах — второй и третьей виртуальной машине, чтобы объединить все три машины в кластер:
docker swarm join --token SWMTKN-1-2jg6olmfwi3yv34f23s60x7918zt53tbvqm7zjz6wf6w38he91-3f7kha8oh34vsafynrew9ntts 192.168.31.199:2377
Эту команду с токеном можно получить командой:
Для worker нод:
docker swarm join-token worker
Для manager нод:
docker swarm join-token manager
Выполняем команду для двух worker нод:
На первой виртуальной машине (manager1) убедимся, что две другие виртуальные машины подключились к кластеру как worker node:
docker node ls
Установка Portainer
Portainer — это инструмент управления контейнерами.
Для управления нашим кластером установим Portainer. Инструкцию находим на https://docs.portainer.io/start/install-ce/server/swarm/linux. Копируем команды и выполним их на manager ноде (manager1). Создаем папку port, в которую скачиваем конфигурацию сервисов portainer-agent-stack.yml:
mkdir ~/port
cd ~/port
curl -L https://downloads.portainer.io/ce2-21/portainer-agent-stack.yml -o portainer-agent-stack.yml
Содержимое portainer-agent-stack.yml на момент написания заметки:
version: '3.2'
services:
agent:
image: portainer/agent:2.21.5
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /var/lib/docker/volumes:/var/lib/docker/volumes
networks:
- agent_network
deploy:
mode: global
placement:
constraints: [node.platform.os == linux]
portainer:
image: portainer/portainer-ce:2.21.5
command: -H tcp://tasks.agent:9001 --tlsskipverify
ports:
- "1102:9443"
- "9000:9000"
- "8000:8000"
volumes:
- portainer_data:/data
networks:
- agent_network
deploy:
mode: replicated
replicas: 1
placement:
constraints: [node.role == manager]
networks:
agent_network:
driver: overlay
attachable: true
volumes:
portainer_data:
- сервисы находятся в общей сети agent_network типа overlay;
- сервис portainer/agent:
- режим развертывания: Глобальный;
- имеет доступ к файлам /var/run/docker.sock и /var/lib/docker/volumes;
3. сервис portainer/portainer:
- работает только на ноде manager1;
- веб интерфейс доступен по порту 1102;
- данные сервиса хранятся в томе portainer_data;
- автоматически подключается ко всем агентам развернутых нодах в кластере;
Запускаем стек:
docker stack deploy -c portainer-agent-stack.yml portainer
Проверим работоспособность сервисов:
docker service ls
Надо обратить внимание, что главная нода manager1 должна в своем имени иметь слово manager. Иначе необходимо будет поправить конфиг portainer-agent-stack.yml:
Откроем web-интерфейс Portainer по адресу главной manager ноды:https://192.168.31.199:1102
Возможно вы получите следующую ошибку:
Your Portainer instance timed out for security purposes. To re-enable your Portainer instance, you will need to restart Portainer.
Для решения данной проблемы перезапустим stack Portainer:
docker stack rm portainer
docker stack deploy -c portainer-agent-stack.yml portainer
Попробуем снова открыть Portainer:
https://192.168.31.199:1102
Придумываем пароль, в моем случае пароль – nickcodenickcode.
Portainer запущен:
Визуализация нашего кластера:
Разворачивание сервиса dockersamples/visualizer
Развернем сервис dockersamples/visualizer с помощью docker stack deploy со следующими параметрами:
- Сервис доступен по порту 1101;
- Сервису обеспечен доступ к файлу /var/run/docker.sock;
- Работает только на ноде manager1.
Создадим папку для проекта visualizer,
mkdir ~/visualizer
cd ~/visualizer/
nano docker-compose.yml
а в ней файл docker-compose.yml с содержимым:
version: "3.8"
services:
visualizer:
image: dockersamples/visualizer:latest
ports:
- "1101:8080"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
deploy:
placement:
constraints:
- node.hostname == manager1
Развернем стек:
docker stack deploy -c docker-compose.yml visualizer_stack
Проверим, что сервис работает корректно:
docker stack services visualizer_stack
Перейдем по адресу ноды manager1 и порту 1101, указанному в docker-compose.yml http://192.168.31.199:1101/:
Разворачивание сервиса nginxdemos/nginx-hello
Развернем третий сервис — образы nginxdemos/nginx-hello и nginx со следующими параметрами:
1. сервисы находятся в общей сети web_network типа overlay;
2. сервис web:
- режим развертывания: Глобальный;
3.сервис nginx:
- работает только на ноде manager1;
- веб интерфейс доступен по порту 1103;
- конфигурация Nginx: load balancing. При обращении по адресу http://<ip>:1103 сервис nginx перенаправляет случайно на один из контейнеров сервиса Web вне зависимости от того на какой ноде он функционирует.
Создадим папку для проекта web, а в ней файл docker-compose.yml и файл nginx.conf:
mkdir ~/web
cd ~/web
nano docker-compose.yml
nano nginx.conf
Содержимое конфигурационного файла docker-compose.yml:
version: "3.8"
services:
web:
image: nginxdemos/nginx-hello:latest
networks:
- web_network
deploy:
mode: global
proxy:
image: nginx:latest
ports:
- "1103:8080"
networks:
- web_network
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
deploy:
mode: replicated
replicas: 1
placement:
constraints: [node.role == manager]
networks:
web_network:
driver: overlay
Содержимое конфигурационного файла nginx.conf:
worker_processes 1;
events {
worker_connections 1024;
}
http {
server {
listen 8080;
location / {
proxy_pass http://web:8080;
}
}
}
Развернем стек:
docker stack deploy -c docker-compose.yml web_stack
Проверим состояние развернутых сервисов:
docker stack services web_stack
Убедимся, что сеть web_network была создана:
docker network ls
Проверяем работоспособность сервиса по адресу ноды manager1 и порту 1103, указанному в docker-compose.yml http://192.168.31.199:1103/:
При обновлении страницы видим, что Server address меняется в зависимости от того, какая нода отдает нам ответ на наш запрос:
Объединение всех сервисов
В завершении давайте попробуем объединим все наши стеки в один общий стек.
Создадим папку all, а в ней файл docker-compose.yml и nginx.conf:
mkdir ~/all
cd ~/all
nano docker-compose.yml
cp ~/web/nginx.conf ~/all
Содержимое конфигурационного файла docker-compose.yml:
version: "3.8"
services:
visualizer:
image: dockersamples/visualizer:latest
ports:
- "1101:8080"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
deploy:
placement:
constraints:
- node.hostname == manager1
agent:
image: portainer/agent:2.21.5
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /var/lib/docker/volumes:/var/lib/docker/volumes
networks:
- agent_network
deploy:
mode: global
placement:
constraints: [node.platform.os == linux]
portainer:
image: portainer/portainer-ce:2.21.5
command: -H tcp://tasks.agent:9001 --tlsskipverify
ports:
- "1102:9443"
- "9000:9000"
- "8000:8000"
volumes:
- portainer_data:/data
networks:
- agent_network
deploy:
mode: replicated
replicas: 1
placement:
constraints: [node.role == manager]
web:
image: nginxdemos/nginx-hello:latest
networks:
- web_network
deploy:
mode: global
proxy:
image: nginx:latest
ports:
- "1103:8080"
networks:
- web_network
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
deploy:
mode: replicated
replicas: 1
placement:
constraints: [node.role == manager]
networks:
agent_network:
driver: overlay
attachable: true
web_network:
driver: overlay
volumes:
portainer_data:
Содержимое конфигурационного файла nginx.conf:
worker_processes 1;
events {
worker_connections 1024;
}
http {
server {
listen 8080;
location / {
proxy_pass http://web:8080;
}
}
}
Развернем стек:
docker stack deploy -c docker-compose.yml all_stack
Проверим состояние развернутых сервисов:
docker stack services all_stack
Проверим наличие сетей:
docker network ls
И проверим работоспособность сервисов по адресам http://192.168.31.199:1101/, https://192.168.31.199:1102/, http://192.168.31.199:1103/.
Все сервисы работают в одном стеке так же, как и по отдельности.