Задонатить и смотреть →
Открой безлимитный доступ к 100+ полезных скринкастов и получай скидки на все предстоящие мероприятия

Бесшовный деплой с 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
Комментарии (38)
Руслан

Спасибо!

Ответить
Arunas

Спасибо.

Ответить
Андрей

Очень круто!

Ответить
Yevhenii Lykholai

Спасибо.

Ответить
Руслан

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

Ответить
Дмитрий Елисеев

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

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

Ответить
Paul

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

Ответить
Дмитрий Елисеев

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

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

Ответить
Павел

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

Ответить
Дмитрий Елисеев

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

Ответить
Alexey Antipin

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

Ответить
Alexey Antipin

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

Ответить
Дмитрий Елисеев

Да, это специфика работы 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

Победил !!! Вдруг кому то пригодится. Стек следующий 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
Ответить
Дмитрий

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

Ответить
kashamamina

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

Ответить
Дмитрий Елисеев

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

Ответить
Виталий,

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

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

Ответить
Виталий,

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

ports:

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

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

Ответить
Виталий,

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

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

Ответить
Виталий,

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

Ответить
Pavel N

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

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

Ответить
Дмитрий Елисеев

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

Ответить
Руслан

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

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

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

Спасибо.

Ответить
Руслан

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

Ответить
Дмитрий Елисеев

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

Ответить
Руслан

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

Ответить
Дмитрий Елисеев

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

Ответить
Руслан

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

Ответить
Сергей

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

Ответить
Дмитрий Елисеев

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

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

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

Ответить
worfect

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

Ответить
Дмитрий Елисеев

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

Ответить
Руслан

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

Ответить
Дмитрий Елисеев

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

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

Ответить
Дмитрий

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

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

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

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

Ответить
Дмитрий Елисеев

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

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

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

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

Google
GitHub
Yandex
MailRu