Comments 20
В целом, поставил вам плюс, в первую очередь за популяризацию Docker Swarm. Сейчас к вам тут набегут хейтеры, которые объявят что он умер и туда ему и кубернетес.
У меня, до недавнего времени, был целый зоопарк скриптов и сервисов (ок 100 штук), которые выполнялись на нескольких серверах в контейнерах и без. В какой-то момент я понял что надо навести в этом порядок и долго выбирал какой-нибудь оркестратор. Поскольку работаю я один, то k8s пришлось отмести из-за сложности с сопровождением. В итоге выбрал Docker Swarm и всё туда перенес за пару месяцев. Нормальной оркестрации и шедулера так и не нашел, пришлось написать самому.
В вашем проекте вы используете nginx - однако, насколько я знаю, он резолвит доменные имена при старте и, если IP сервиса меняется - то он об этом не узнает. Если вы обновляете frontend - то приходится и nginx тоже рестартовать? Именно из-за этого я выбрал Traefik для динамической маршрутизации. Он сам находит новые сервисы без рестарта. Впрочем, конфиги в labels мне не нравятся, да и вообще nginx я тоже люблю больше, конечно..
С другой стороны, у вас фронтенд - это чисто статика, насколько я вижу.. Тогда такой проблемы, наверное, нет.
Вы выставляете порты для базы данных наружу - это очень небезопасно. Тем более что они доступны по всем интерфейсам хоста. Тем более это не нужно в overlay сетях - сервисы прекрасно найдут базу внутри swarm. Вы можете возразить что вам нужно к ней иногда подключаться, но для этого можно придумать промежуточный временный контейнер, который подключится одним концом к базе, а порт прокинет наружу - только на localhost и только в моменты когда вам это нужно. Можно сделать его на socat, и можно просто на ssh tunnel.
Конфиги и секреты - да, это боль. Нельзя изменить конфиг/секрет если его использует хотя бы один сервис, то есть чтобы поменять SSL-сертификат - надо удалить сервис, удалить конфиг с сертификатом, создать новый конфиг и снова создать сервис. У меня тоже самописное решение - примерно как у вас, создаются временные конфиги, а в labels к ним пишется время обновления..
Не хейтер докер сварма и не особо слежу за этим инструментом, но взгляд зацепился за то, что даже у вас в одном сообщении сначала идет:
Сейчас к вам тут набегут хейтеры, которые объявят что он умер и туда ему и кубернетес
а затем:
Нормальной оркестрации и шедулера так и не нашел, пришлось написать самому.
Может поэтому сварм и не такой популярный, раз его приходится вот так вот допиливать? Опять же, не знаю почти ничего о сварме, но мне казалось, что главная ценность оркестратора контейнеров — это, собственно, нормальная оркестрация и шедулинг... А что не так с этим у сварма из коробки?
Видите ли - я не уверен что нормальный шедулинг есть и в кубернетесе. По крайней мере я не нашёл того, что я хотел бы видеть. А хотел я видеть что-то вроде дашборда ДАГов в Apache Airflow. Но только не хотел использовать Airflow для запуска, потому что уж больно сложная схема там получается внутри. А, как известно, если программисту не нравится чужая программа, то он пишет свою (фатальный недостаток). Начальство не возражало - ну так надо пользоваться случаем.
Для докера нет родного UI (как нет и в k8s), но есть API, через который сторонние инструменты могут им управлять. Для Swarm всё, действительно, остановилось в развитии пару лет назад, но сам он достаточно законченный инструмент (хотя, есть баги и они уже чинятся плохо, я сам наткнулся на парочку). Впрочем, есть ощущение, что и сам Docker теряет позиции - приходят containerd и podman, и теснят его с рынка.
Большое спасибо за такой подробный и развернутый комментарий!
В вашем проекте вы используете nginx - однако, насколько я знаю, он резолвит доменные имена при старте и, если IP сервиса меняется - то он об этом не узнает. Если вы обновляете frontend - то приходится и nginx тоже рестартовать?
В моём случае всё крутится на одном сервере, пеезжать пока не приходилось. Так что все адреса, можно сказать, постоянные.
Нет, при обновлении frontend'а nginx-proxy не нужно рестартить. Он так же продолжает перенаправлять соответствующий трафик на фронтовый сервис.
Вы выставляете порты для базы данных наружу - это очень небезопасно. Тем более что они доступны по всем интерфейсам хоста. Тем более это не нужно в overlay сетях - сервисы прекрасно найдут базу внутри swarm.
Согласен. Порт был открыт именно из-за необходимости периодически подключаться к базе напрямую. Про то, что сервисы базу внутри swarm найдут и без этого - знаю.
Вы можете возразить что вам нужно к ней иногда подключаться, но для этого можно придумать промежуточный временный контейнер, который подключится одним концом к базе, а порт прокинет наружу - только на localhost и только в моменты когда вам это нужно. Можно сделать его на socat, и можно просто на ssh tunnel.
Не знал про такие решения. Приму на вооружение, спасибо!
Небольшое примечание: в текущей версии спецификации Compose-файла его имя по-умолчанию уже не содержит префикса docker-
, там просто compose.yaml
: https://docs.docker.com/compose/compose-application-model/
Несколько вопросов
1) у вас на схеме идёт от одной базы связь к другой из продакшена в test, что это значит?
2) зачем такая сложная схема с лейблами если образ не был изменён он и не появится соответственно и не обновится. обновиться только те образы которые появились от изменений в коде.
3) в какой момент происходит обновление продакшена - это ручное нажатие скрипта? Обновиться абсолютно весь production (для того чтобы ваше лейблы были одинаковой версии) или только те сервисы которые изменились?
4) как происходит замена тестового окружения если нужно откатить изменения в том числе на старую базу данных?
1) у вас на схеме идёт от одной базы связь к другой из продакшена в test, что это значит?
Там показана связь от сервиса "Backend API" в окружении "dev" до двух баз: в "prod" и в "dev". Строго говоря, это не совсем верно, поскольку окружения должны быть полностью изолированные.
Во время разработки и тестирования новых версий backend-а иногда было полезно сходить в продовую базу, поэтому связь осталась в конфигах и на схеме
2) зачем такая сложная схема с лейблами если образ не был изменён он и не появится соответственно и не обновится. обновиться только те образы которые появились от изменений в коде.
Предполагаю, речь про лейблы в пайплайнах репозиториев backend/frontend.
Нет, в текущей реализации сборка образа не зависит от наличия или отсутствия изменений в коде. Можно собрать два одинаковых образа на базе одного и того же кода, но они будут иметь разные теги
Иногда нет необходимости собирать образ на каждый коммит. В таком случае лейбл сборки можно отключить и добавить только в тот момент, когда реально потребуется собрать образ для выкатки
3) в какой момент происходит обновление продакшена - это ручное нажатие скрипта? Обновиться абсолютно весь production (для того чтобы ваше лейблы были одинаковой версии) или только те сервисы которые изменились?
Есть 3 триггера для запуска джобы деплоя продакшена
Лейбл prod-deploy на MR.
Ручной запуск джобы в MR
Merge в main-ветку. При мердже в main-ветку автоматически запускается джоба prod-deploy.
При запуске сервисы деплоятся с теми версиями, которые указаны в конфиге. Если версия не поменялась, сервис не перезапускается. Если поменялась - обновляется
4) Как происходит замена тестового окружения если нужно откатить изменения в том числе на старую базу данных?
Аналогично выкатке, но вместо более новой версии указывается более старая. Автоматизации управления содержимым БД в моей реализации нет, тут нужно будет обновлять вручную.
Что сейчас актуально для скудулинга джобов по расписанию и одноразовых в Swarm?
Хороший вопрос. Я изучал его с полгода назад. На самом деле, оказывается, что не так уж и много вариантов.
swarm-cronjob. Запускается отдельный сервис, смотрит на labels у сервисов.
Ofelia. Примерно то же самое, но ещё может из конфига брать расписания.
У обоих конфигурация довольно тупая, результаты запуска можно найти только в логах, а какую-то статистику получить - ну пиши свои логопарсеры что ли..
Есть Apache AirFlow, он немного для другого, но у него есть оператор для запуска Docker/Swarm контейнеров. Можно шедулить и UI есть. Однако, это получается немного некрасиво: расписание запуска хардкодится на питоне в коде DAG'а, он запускает celery-таск, которая ничего не делает, но запускает ещё Docker-контейнер и висит ждёт его окончания. 40 активных тасков == 40 celery-тасков, да ещё и рестартовать их нельзя нормально. Ну как-то перебор.
В принципе, наверное, можно для этого приспособить Jenkins - у него есть и UI, и скриптовать что угодно можно. Но как-то я его не очень люблю.
Я оценил варианты и написал своё. Оно и запускать может, и Docker Images из исходников строит, и секретами динамически управляет.
Скриншоты
Выглядит заманчиво. Open source?
К сожалению, нет. Но, возможно, удастся когда-нибудь уговорить начальника на то, чтобы выпустить в OpenSource. Однако, для этого нужно потратить ещё некоторое время для того чтобы причесать код, добавить недостающие фичи и, самое главное - написать хоть какую-то документацию..
Вряд ли соберусь сделать всё это раньше чем через полгода, однако, может быть, смогу описать основные принципы в статье на хабре.
Спасибо за статью. Я как раз начинаю разбираться в Docker Swarm (мигрирую после Docker Standalone) и подчерпнул для себя полезное (разобрался с тем как Docker Secrets создавать, например).
Однако самая большая беда с которой я так и не справился пока -- это как раз тот самый PostgreSQL. Он используется в нескольких сервисах, которые держу дома для личного использования, но в одном из них он постоянно ведет себя как-то некрасиво: в Authentik он вечно отваливается без объяснения причин, поднимается потом бесконечно долго и БД в итоге все равно остается испорчена.
И вот деплой HA-PostgreSQL мне пока не поддался. Я попробовал и master-replica-haproxy, и образы bitnami/postgresql-repmgr. Все оно как-то либо падает, либо не дает подключиться к себе. В гугле гайды либо шестилетней давности, либо уже опробованы безуспешно.
Посему питаю призрачную надежду, что здесь найдется знаток, который подскажет где популярно объяснено как это можно по-человечески реализовать)
Боюсь, что у вас маловато деталей объяснено. У меня Postgres работал годами в контейнере. Как он отваливается? У него должны быть логи. Если нет - надо включить.
Может быть связано с тем, как вы его используете. Может быть, мало connections разрешено, а клиенты их много открывают и держат открытыми? Посмотрите по `select * from pg_stat_activity order by query_start`
К сожалению, логов уже нет, т.к. я окончательно сдался и удалил стак с Authentik пока что. Наиболее частый сценарий был такой: утром не работает SSO. Иду в портейнер -- там 4 дохленьких сервиса постгреса в стаке Authentik, в логах они жалуются на неожиданное завершение и пытаются восстановиться, но спустя какое-то время просто пишут server shutdown и выключаются. Но это я по памяти. Есть вероятность, что БД пострадала при миграции и все проблемы из-за этого. Есть вероятность, что это особенность Authentik. Поскольку с PostgreSQL у меня крутятся еще Gitea, Paperless и там подобного не происходит. А клиентов только 3 человека)
В целом даже безотносительно причины падения сервиса хочется понять как сделать высокодоступный постгрес...
Если на сервере дома в шкафу - то не знаю.
Рабочие базы уже 10 лет запускаю на AWS RDS - были одиночные проблемы несколько раз за всё это время, но в остальном - работает прекрасно, даже без HA-репликации. Средняя база, но держит внезапный рост количества подключений (от 10-15 обычных до, вдруг, нескольких сотен) и переваривает тяжёлые запросы. Практически не требует настройки - они сами накатывают обновления и расширяют диск, если база растёт.
Отличная статья, очень пригодилась.
А в какой программе нарисованы такие схемы?
Деплой в Docker Swarm