Бесшовный деплой с Docker Swarm

Перевод проекта с Docker Compose на Docker Swarm для кластера из виртуальных машин. Организация бесшовного деплоя. Управление размещением сервисов.

  • 00:00:46 Проблема зависимостей запуска контейнеров
  • 00:04:05 Удаление зависимостей Nginx
  • 00:09:32 Вынос резолвера в сниппет
  • 00:11:21 Проверка здоровья контейнера
  • 00:12:34 Healthcheck для Nginx
  • 00:19:12 Проверки в Gateway
  • 00:20:55 Проверка для Frontend
  • 00:23:01 Healthcheck для PHP-FPM
  • 00:34:42 Доработка конфигурации docker-compose
  • 00:35:16 Перенос миграций в сервис
  • 00:38:33 Конфигурирование параметров деплоя
  • 00:41:37 Конфигурирование размещения сервисов
  • 00:43:43 Режим подключения к БД
  • 00:47:17 Изменение команды деплоя
  • 00:54:05 Деплой проекта
  • 00:55:53 Смена хука для Certbot
  • 00:59:45 Размещение сервисов по меткам
  • 01:03:54 Простановка меток через Ansible
  • 01:05:59 Обзор результата
  • 01:07:05 Подключение к Docker по TLS
Скрытый контент (код, слайды, ...) для подписчиков. Открыть →
Дмитрий Елисеев
elisdn.ru
Комментарии (40)
Руслан
2020-07-18 16:51

Спасибо!

Ответить
Arunas
2020-07-18 19:39

Спасибо.

Ответить
Андрей
2020-07-19 09:33

Очень круто!

Ответить
Yevhenii Lykholai
2020-07-19 11:37

Спасибо.

Ответить
Руслан
2020-07-20 16:18

Здравствуйте, подскажите, есть ли пример реализации паттерна сага на php?

Ответить
Дмитрий Елисеев
2020-07-27 09:31

Сага обычно реализуется как обычный обработчик команды и слушатель событий. Хореографическая сага реализуется обычным вызовом наших сущностей из слушателей событий других сущностей. И даже сагу-оркестратор при необходимости хранить состояние можно оформить тоже как обычную Doctrine-сущность.

Мы здесь как раз все эти варианты рассмотрим.

Ответить
Paul
2020-08-02 22:06

Дмитрий, а если я монтирую папку с файлами (файловое хранилище) через volume, но при этом хочу запустить несколько инстансов приложения, я столкнусь с проблемой о которой вы говорили про базу (что swarm будет создавать volume на разных хостах, а нам надо только на одном). Тоже самое произойдет, если я, например, хочу сохранять сессии на основной хост. Где-то в комментариях видел, что для хранения файлов будет использоваться s3 хранилище, но хотелось бы понять, как можно обойтись без этого.

Ответить
Дмитрий Елисеев
2020-08-04 06:29

Вместо хранения сессий по умолчанию в файлах переходят на хранение в БД или в Redis. Для этого во многих фреймворках вместо HttpSession имеются классы DbSession или RedisSession.

А для хранения файлов у себя на нужном хосте можно через докер на нём поднять сервис хранилища. Потом из php-fpm загружать в него файлы по FTP и проксировать запросы из gateway.

Ответить
Павел
2020-08-09 15:27

здравствуйте! спасибо за ваши труды. не могу только найти бесшовный деплой в условиях связанных сервисов. например, версия фронта может работать с определенной версией бека, поэтому обновлять по 1 сервису не вариант, так как запросы могу "перемешиваться" и будут возникать ошибки. поэтому нужен blue-green деплой сразу для нескольких сервисов, например объединенных одной сетью и переключать трафик между сетями. где то вроде у вас я видел такое видео или ошибаюсь?

Ответить
Дмитрий Елисеев
2020-08-13 15:42

Если частей несколько, то следят за обратной совместимостью API и занимаются его версионированием. То есть новые вещи добавляют аккуратно, чтобы они не ломали старые запросы. Тогда проблем с поломками фронтенда или мобильного приложения не будет.

Ответить
Alexey Antipin
2020-08-31 07:56

Доброго времени. Дмитрий подскажите, когда мы раворачиваем NGINX в докере получаем замену IP на бридж IP тоесть в логах NGINX мы больше не видим client ip, вместо этого видим Docker bridge ip, если ли рещения в вашем арсенале? Вынос из докера gateway тоже не самая удобная идея.

Ответить
Alexey Antipin
2020-09-02 04:42

Проблема оказалась не в этом, Конфликты faerwalld iptables and nftables . Centos 8 в топку пока)

Ответить
Дмитрий Елисеев
2020-09-03 08:58

Да, это специфика работы overlay-сети в Swarm. При балансировке между несколькими нодами на gateway передаётся не реальный клиентский запрос с реальным IP-адресом, а уже перенаправленный внутрь запрос из балансировщика Docker с IP-адресом этого балансировщика.

Так что если сильно нужен реальный IP и не хочется ставить внешний Nginx с простановкой X-Real-IP, то как компромисс можно привязывать порты gateway напрямую к портам виртуальной машины через режим mode:host вместо проброса через docker-балансировщик:

services:
    gateway:
        image: ${REGISTRY}/auction-gateway:${IMAGE_TAG}
        volumes:
            - /etc/letsencrypt:/etc/letsencrypt:ro
            - /var/www/html:/var/www/html:ro
        ports:
            - target: 80
              published: 80
              protocol: tcp
              mode: host
            - target: 443
              published: 443
              protocol: tcp
              mode: host
        deploy:
            placement:
                constraints: [node.role == manager]

Тогда входящий запрос будет отправляться в gateway напрямую. Но при таком прямом подключении портов в обход Swarm-а не получится запускать несколько реплик одновременно. Так что бесшовное обновление сделать не получится и gateway при каждой сборке будет отваливаться при обновлении.

Для бесшовного деплоя надо будет, например, присваивать и менять версию gateway вручную:

docker build --tag gateway:1.3 ...

и в продакшене в image указывать gateway:1.3. Тогда этот сервис не будет обновляться при каждой сборке. Но придётся вручную помнить, что нужно будет при изменении везде менять эту версию.

Либо можно присвоить дополнительно тег latest:

docker build --tag gateway:${IMAGE_TAG} --tag gateway:latest ...

и использовать в продакшене gateway:latest, чтобы Swarm его перезапускал только когда увидит изменения после pull. Но так мы не сможем сделать rollback.

Ответить
Alexey Antipin
2020-09-07 06:40

Победил !!! Вдруг кому то пригодится. Стек следующий Debian 10 + iptables + fail2ban (v0.11), centos and ubuntu не работает.

2020/09/07 06:18:01 [error] 6#6: *2542 limiting requests, excess: 5.384 by zone "dynamic", client: 194.193.XX.XX, server: 27.50.xx.xx, request: "GET / HTTP/1.1",
возвращает коректный client ip

рисует конфиг от DDOS

[nginx-limit-req]
enabled = true
chain=DOCKER-USER
findtime = 600
bantime = 7200
Ответить
Дмитрий
2020-09-08 07:30

Я делаю совсем другой проект (react ssr) , но твои уроки показали как сделать CI и автоматический деплой в кластер. Дима, спасибо огромное! Всё получилось! Супер!

Ответить
kashamamina
2020-11-06 00:22

почему не кубернетис?

Ответить
Дмитрий Елисеев
2020-11-06 12:57

Потому что на Swarm перейти проще. А K8s уже следующий продвинутый шаг.

Ответить
Виталий,
2021-03-17 08:34

Дмитрий, подскажите пожалуйста, все делаю как у вас в видео, взял исходники, но 1 - делаю деплой как в видео - и по адресу зайти на сервер не могу (хотя сервис gateway работает) 2. убиваю сервис и поднимаю все через docker-compose все работает отлично!

в чем может быть проблема? Спасибо

Ответить
Виталий,
2021-03-17 08:35

победил вот этим в prod.yml у gateway добавил

ports:

  - mode: host
    protocol: tcp
    published: 80
    target: 80
  - mode: host
    protocol: tcp
    published: 443
    target: 443
Ответить
Виталий,
2021-03-17 08:38

но тогда реплика только 1 - и это проблема, как победить .....

Ответить
Виталий,
2021-03-17 11:37

видать какая то ошибка в кластере, или в ПО, т.к. контейнеры друг друга в сети не видят

запустил все через docker-compose все отлично работает!

Ответить
Виталий,
2021-03-18 11:28

отвечу сам себе на железе стоит proxmox - все машинки делали контейнерами из образов CT - на них НЕ РАБОТАЕТ! как только начали делать VM обычные виртуалки - все сразу заработало как надо!

Ответить
Pavel N
2021-05-02 06:49

Здравствуйте, Дмитрий. Подскажите как лучше организовать выполнение cron команд при работе в такой системе как вы описали. Если мы запустим cron команды на каждом воркере могут возникнуть конфликты за ресурсы. Мы на всех воркерах будем одновременно выполнять одни и те же команды. Какие лучшие практики сложились для выполнения регулярных команд (cron) в Swarm (K8s)?

Спасибо за ваши уроки.

Ответить
Дмитрий Елисеев
2021-05-02 08:07

В Swarm будем использовать crazymax/swarm-cronjob. А в K8s есть CronJob.

Ответить
Руслан
2021-06-26 19:56

Дмитрий, здравствуйте,

подскажите, пожалуйста, Docker Swarm хорошо справляется с распределением и перезапуском контейнеров, а как быть с хранением данных, которые не должны потеряться при перезапуске контейнеров и справиться с ростом запросов к ним?

Может будет уместно рассмотреть эту тему в рамках данного курса: как поднять масштабируемое файловое хранилище доступное из разных контейнеров в Docker Swarm для хранения персистентных данных, н-р. Ceph или др.

Спасибо.

Ответить
Руслан
2021-06-26 22:03

PS: может MinIO, либо NFS или что будет оптимальней.

Ответить
Дмитрий Елисеев
2021-07-07 15:05

Для хранения пользовательских файлов вроде фотографий вместо вольюмов уместно сразу использовать отдельный файловый хостинг вроде хранилища Amazon S3 или аналогов. А как эмулятор хранилища для локальной разработки удобно как раз подключить minio.

Ответить
Руслан
2021-07-07 15:12

Дима, объектное хранилище сразу рассматривал, но столкнулся с ограничением (аналог GDPR) у клиента - данные пользователей хранить в пределах страны, а в их облачной инфраструктуре нет S3, нужно поднимать хранилище самому, поэтому и возник вопрос как это лучше сделать. Спасибо за ответ.

Ответить
Дмитрий Елисеев
2021-07-07 15:30

В России проблем нет, так как практически все провайдеры совместимы с S3. А в других странах либо поднимать свой minio с volume, либо искать хранилище с FTP или своим особым протоколом.

Ответить
Руслан
2021-07-07 15:55

Спасибо, пробую подключить MinIO.

Ответить
Сергей
2021-08-09 16:55

А будет ли каст для работы с Kubernetes?

Ответить
Дмитрий Елисеев
2021-08-16 18:01

В этой серии пока не будет.

Вместо сложного ручного разворачиванию кластера лучше взять готовый Managed Kubernetes от любого облачного провайдера и оплачивать его из бюджета компании.

А на стороне приложения нужно будет заменить docker-compose-production.yml на набор yaml-файлов для Kubernetes и переписать команду deploy на использование kubectl.

Ответить
worfect
2021-11-10 02:49

Метки в плеере забыли поставить, Дмитрий.

Ответить
Дмитрий Елисеев
2021-11-11 10:54

Добавил. Спасибо!

Ответить
Руслан
2022-02-16 07:55

Дмитрий, добрый день! Пожалуйста, подскажите как лучше расшарить volume, н-р. из мастера, между другими нодами в swarm, чтобы все имели доступ к одному файловому хранилищу? Спасибо.

Ответить
Дмитрий Елисеев
2022-03-02 16:05

По умолчанию Swarm так не умеет. Можно попробовать найти кастомный драйвер для томов вместо local. Либо ко всем виртуалкам примонтировать сетевую папку по NFS и в docker-compose.yml монтировать уже её.

Но вместо этого удобнее использовать отдельный файловый хостинг и из кода загружать в него файлы по протоколу FTP или S3, как мы сделали в эпизоде 60.

Ответить
Дмитрий
2023-08-25 11:17

Спасибо за видео!

Возник вопрос: если по бесшовному добавлению новых инстансов в целом понятно (как понял swarm их только после успешного healthcheck подключит в сеть), то как быть с бесшовным выведением старых инстансев? По-хорошему они ведь должны перестать получать новые http-запросы и завершить текущие или, например, завершить текущую обработку сообщений из очереди, а swarm про это ничего не знает.

Видел, что у docker-compose есть опция stop_grace_period, которая позволяет дать время контейнеру перед тем как его убить. Оно получается поможет с завершением текущих http-запросов и сообщениями из очередей или есть какие-то способы получше?

А как быть ещё с тем, чтобы перестали поступать новые http-запросы?

Ответить
Дмитрий Елисеев
2023-09-05 10:58

Swarm сам перестаёт маршрутизировать новые HTTP-запросы на инстанс перед тем как начать его отключать. С этим проблем нет и так.

А для завершения процесса оркестратор сначала отправляет ему сигнал завершения, а потом после таймаута принудительно отключает. Поэтому в слушателе очереди можно спрограммировать обработку сигналов как в примере к php-amqplib, чтобы по сигналу завершения слушатель отключался от очереди и завершал работу.

Ответить
Владислав
2024-11-07 00:03

Дмитрий, добрый день! В варианте деплоя через docker compose вы сначала поднимали постгрес, потом делали миграции, а потом поднимали остальные сервисы для того, что бы исключить ситуацию, когда миграции еще не прошли, а новый api поднялся и пытается обращаться к еще не созданным колонкам в БД.

А как эта проблема будет решаться в варианте с Docker Swarm? Миграции были перенесены в отдельный сервис, но ведь нет гарантий, что они пройдут до того, как будет поднят сервис с новым api?

Ответить
Дмитрий Елисеев
2024-11-23 11:32

Для бесшовного деплоя организовывают постепенную миграцию. Это уже обсуждали здесь.

Ответить
Зарегистрируйтесь или войдите чтобы оставить комментарий

Или войти через:

Yandex
MailRu
GitHub
Google