Стратегии деплоя в Kubernetes: rolling, recreate, blue/green, canary, dark (A/B-тестирование)
Прим. перев.: Этот обзорный материал от Weaveworks знакомит с наиболее популярными стратегиями выката приложений и рассказывает о возможности реализации наиболее продвинутых из них с помощью Kubernetes-оператора Flagger. Он написан простым языком и содержит наглядные схемы, позволяющие разобраться в вопросе даже начинающим инженерам.
Схема взята из другого обзора стратегий выката, сделанного в Container Solutions
Одной из самых больших проблем при разработке cloud native-приложений сегодня является ускорение деплоя. При микросервисном подходе разработчики уже работают с полностью модульными приложениями и проектируют их, позволяя различным командам одновременно писать код и вносить изменения в приложение.
Более короткие и частые развертывания имеют следующие преимущества:
В этой публикации мы обсудим различные стратегии деплоя в Kubernetes, в том числе rolling-развертывания и более продвинутые методы, такие как канареечные (canary) выкаты и их разновидности.
Стратегии деплоя
Существует несколько различных типов стратегий развертывания, коими можно воспользоваться в зависимости от цели. Например, вам может потребоваться внести изменения в некое окружение для дальнейшего тестирования, или в подмножество пользователей/клиентов, или возникнет необходимость провести ограниченное тестирование на пользователях, прежде чем сделать некую функцию общедоступной.
Rolling (постепенный, «накатываемый» деплой)
Это стандартная стратегия развертывания в Kubernetes. Она постепенно, один за другим, заменяет pod’ы со старой версией приложения на pod’ы с новой версией — без простоя кластера.
Kubernetes дожидается готовности новых pod’ов к работе (проверяя их с помощью readiness-тестов), прежде чем приступить к сворачиванию старых. Если возникает проблема, подобное накатываемое обновление можно прервать, не останавливая всего кластера. В YAML-файле с описанием типа deployment’а новый образ заменяет собой старый образ:
Параметры накатываемого обновления можно уточнить в файле манифеста:
Recreate (повторное создание)
В этом простейшем типе развертывания старые pod’ы убиваются все разом и заменяются новыми:
Соответствующий манифест выглядит примерно так:
Blue/Green (сине-зеленые развертывания)
Стратегия сине-зеленого развертывания (иногда ее ещё называют red/black, т.е. красно-чёрной) предусматривает одновременное развертывание старой (зеленой) и новой (синей) версий приложения. После размещения обеих версий обычные пользователи получают доступ к зеленой, в то время как синяя доступна для QA-команды для автоматизации тестов через отдельный сервис или прямой проброс портов:
После того, как синяя (новая) версия была протестирована и был одобрен ее релиз, сервис переключается на неё, а зеленая (старая) сворачивается:
Canary (канареечные развертывания)
Канареечные выкаты похожи на сине-зеленые, но лучше управляются и используют прогрессивный поэтапный подход. К этому типу относятся несколько различных стратегий, включая «скрытые» запуски и А/В-тестирование.
Эта стратегия применяется, когда необходимо испытать некую новую функциональность, как правило, в бэкенде приложения. Суть подхода в том, чтобы создать два практически одинаковых сервера: один обслуживает почти всех пользователей, а другой, с новыми функциями, обслуживает лишь небольшую подгруппу пользователей, после чего результаты их работы сравниваются. Если все проходит без ошибок, новая версия постепенно выкатывается на всю инфраструктуру.
Хотя данную стратегию можно реализовать исключительно средствами Kubernetes, заменяя старые pod’ы на новые, гораздо удобнее и проще использовать service mesh вроде Istio.
Например, у вас может быть два различных манифеста в Git: обычный с тегом 0.1.0 и «канареечный» с тегом 0.2.0. Изменяя веса в манифесте виртуального шлюза Istio, можно управлять распределением трафика между этими двумя deployment’ами:
Пошаговое руководство по реализации канареечных развертываний с помощью Istio можно найти в материале GitOps Workflows with Istio. (Прим. перев.: Мы также переводили материал про канареечные выкаты в Istio здесь.)
Канареечные развертывания с Weaveworks Flagger
Weaveworks Flagger позволяет легко и эффективно управлять канареечными выкатами.
Flagger автоматизирует работу с ними. Он использует Istio или AWS App Mesh для маршрутизации и переключения трафика, а также метрики Prometheus для анализа результатов. Кроме того, анализ канареечных развертываний можно дополнить вебхуками для проведения приемочных (acceptance) тестов, нагрузочных и любых других типов проверок.
На основе deployment’а Kubernetes и, при необходимости, горизонтального масштабирования pod’ов (HPA), Flagger создает наборы из объектов (deployment’ы Kubernetes, сервисы ClusterIP и виртуальные сервисы Istio или App Mesh) для проведения анализа и реализации канареечных развертываний:
Реализуя контур управления (control loop), Flagger постепенно переключает трафик на канареечный сервер, параллельно измеряя ключевые показатели производительности, такие как доля успешных HTTP-запросов, средняя продолжительность запроса и здоровье pod’ов. Основываясь на анализе KPI (ключевых показателей эффективности), канареечная часть либо растет, либо сворачивается, и результаты анализа публикуются в Slack. Описание и демонстрацию этого процесса можно найти в материале Progressive Delivery for App Mesh.
Dark (скрытые) или А/В-развертывания
Скрытое развертывание — еще одна вариация канареечной стратегии (с ней, кстати, Flagger тоже может работать). Разница между скрытым и канареечным развертыванием состоит в том, что скрытые развертывания имеют дело с фронтендом, а не с бэкендом, как канареечные.
Другое название этих развертываний — А/В-тестирование. Вместо того, чтобы открыть доступ к новой функции всем пользователям, ее предлагают лишь ограниченной их части. Обычно эти пользователи не знают, что выступают тестерами-первопроходцами (отсюда и термин «скрытое развертывание»).
С помощью переключателей функциональности (feature toggles) и других инструментов можно следить за тем, как пользователи взаимодействуют с новой функцией, увлекает ли она их или они считают новый пользовательский интерфейс запутанным, и другими типами метрик.
Flagger и A/B-развертывания
Помимо маршрутизации с учётом весов, Flagger также может направлять на канареечный сервер трафик в зависимости от параметров HTTP. При А/В-тестировании можно использовать заголовки HTTP или файлы cookie для перенаправления определенного сегмента пользователей. Это особенно эффективно в случае frontend-приложений, требующих привязки сессии к серверу (session affinity). Дополнительную информацию можно найти в документации Flagger.
Автор выражает благодарность Stefan Prodan, инженеру Weaveworks (и создателю Flagger), за все эти потрясающие схемы деплоя.
Blue-Green Deployment на минималках
В этой статье мы с помощью bash, ssh, docker и nginx организуем бесшовную выкладку веб-приложения. Blue-green deployment — это техника, позволяющая мгновенно обновлять приложение, не отклоняя ни одного запроса. Она является одной из стратегий zero downtime deployment и лучше всего подходит для приложений, у которых один инстанс, но есть возможность загрузить рядом второй, готовый к работе инстанс.
Допустим, у Вас есть веб-приложение, с которым активно работает множество клиентов, и ему совершенно никак нельзя на пару секунд прилечь. А Вам очень нужно выкатить обновление библиотеки, фикс бага или новую крутую фичу. В обычной ситуации, потребуется остановить приложение, заменить его и снова запустить. В случае докера, можно сначала заменить, потом перезапустить, но всё равно будет период, в котором запросы к приложению не обработаются, ведь обычно приложению требуется некоторое время на первоначальную загрузку. А если оно запустится, но окажется неработоспособным? Вот такая задача, давайте её решать минимальными средствами и максимально элегантно.
Disclaimer: Большая часть статьи представлена в экспериментальном формате — в виде записи консольной сессии. Надеюсь, это будет не очень сложно воспринимать, и этот код сам себя документирует в достаточном объёме. Для атмосферности, представьте, что это не просто кодсниппеты, а бумага из «железного» телетайпа.
Интересные техники, которые сложно нагуглить просто читая код описаны в начале каждого раздела. Если будет непонятно что-то ещё — гуглите и проверяйте в explainshell (благо, он снова работает, в связи с разблокировкой телеграма). Что не гуглится — спрашивайте в комментах. С удовольствием дополню соответствующий раздел «Интересные техники».
Сервис
Сделаем подопытный сервис и поместим его в контейнер.
Интересные техники
Распечатка
Я специально разрываю сниппет, чтобы включить подсветку для Python. В конце будет ещё один такой кусок. Считайте, что в этих местах бумагу разрезали для передачи в отдел хайлайтинга (где код раскрашивали вручную хайлайтерами), а потом эти куски вклеили обратно.
Реверс-прокси
Чтобы наше приложение имело возможность незаметно поменяться, необходимо, чтобы перед ним была ещё какая-то сущность, которая скроет его подмену. Это может быть веб-сервер nginx в режиме реверс-прокси. Реверс-прокси устанавливается между клиентом и приложением. Он принимает запросы от клиентов и перенаправляет их в приложение а ответы приложения направляет клиентам.
Приложение и реверс-прокси можно связать внутри докера с помощью docker network. Таким образом, контейнеру с приложением можно даже не пробрасывать порт в хост-системе, это позволяет максимально изолировать приложение от угроз из внешки.
Интересные техники
Распечатка
Бесшовный деплоймент
Выкатим новую версию приложения (с двухкратным бустом startup performance) и попробуем бесшовно её задеплоить.
Интересные техники
Распечатка
На данном этапе образ билдится прямо на сервере, что требует наличия там исходников приложения, а также нагружает сервер лишней работой. Следующим шагом будет выделение сборки образа на отдельную машину (например, в CI-систему) с последующей передачей его на сервер.
Перекачка образов
К сожалению, перекачивать образа с localhost на localhost не имеет смысла, так что этот раздел можно пощупать только имея под рукой два хоста с докером. На минималках это выглядит примерно так:
А ещё, можно наблюдать за процессом перекачки (правда, для этого нужна сторонняя утилита):
Совет: Если Вам для соединения с сервером по SSH требуется куча параметров, возможно вы не используете файл
Передача образа через docker image save/load — это наиболее минималистичный метод, но не единственный. Есть и другие:
Второй способ (с тремя вариантами его реализации) хорошо описан в статье How to deploy on remote Docker hosts with docker-compose.
deploy.sh
Теперь соберём всё, что мы делали вручную в один скрипт. Начнём с top-level функции, а потом посмотрим на остальные, используемые в ней.
Интересные техники
Скрипт деплоймента
Функция get-active-slot требует небольших пояснений:
Почему она возвращает число, а не выводит строку?
А трёх условий точно хватает, чтобы различить все состояния?
Это и есть весь скрипт. И вот гист с этим скриптом для скачки через wget или curl.
Выполнение параметризированных скриптов на удалённом сервере
Пришло время стучаться на целевой сервер. В этот раз localhost вполне подойдёт:
Мы написали скрипт деплоймента, который перекачивает предварительно собранный образ на целевой сервер и бесшовно подменяет контейнер сервиса, но как его выполнить на удалённой машине? У скрипта есть аргументы, так как он универсален и может деплоить сразу несколько сервисов под один реверс-прокси (конфигами nginx можно разрулить по какому url какой будет сервис). Скрипт нельзя хранить на сервере, так как в этом случае мы не сможем его автоматически обновлять (с целью багфиксов и добавления новых сервисоы), да и вообще, стэйт = зло.
Вот давайте только без Ansible. Да, всё уже придумано. Да, велосипед. Смотрите, какой простой, элегантный и минималистичный велосипед:
Однако, мы не можем быть уверены, что на удалённом хосте есть адекватный bash, так что добавим в начало небольшую проверочку (это вместо shellbang):
А теперь всё по-настоящему:
Теперь можно открыть http://localhost/ в браузере, запустить деплоймент ещё раз и убедиться, что он проходит бесшовно путём обновления страницы по КД во время выкладки.
Не забываем убираться после работы :3
Disclaimer: Этот скрипт не является готовым ко внедрению решением. Статья написана исключительно в образовательных целях, чтобы поделиться с Вами эстетическим удовольствием от bash-скриптинга. Каждый скрипт на bash — это произведение искусства, и чем больше на этом языке пишешь, тем лучше можно понять тех, кто был против systemd, ведь с приходом systemd галерею по адресу /etc/init.d/ навсегда закрыли. Если Вы стремитесь к унификации и отдаёте предпочтение готовым поддерживаемым инструментам, то для Вас есть Docker Swarm Mode (пока) и множество мощных оркестраторов с кучей готовых стратегий бесшовной выкладки. Но готовые инструменты никогда не являются панцеей. Этот скрипт родился не только из любви к bash-скриптингу, но и потому что давным-давно, в далёкой-далёкой галактике написать его оказалось проще, чем внедрить оркестратор. А ещё, его легко модицифировать под особые нужды особых приложений.
BONUS: Спустя пару месяцев после публикации, немного поменял поведение скрипта. Раньше он после деплоя удалял старый контейнер, а теперь останавливает. Это позволило добавить ещё одну крайне полезную фичу, которая, надеюсь, никогда никому не пригодится:
Разработка приложений и Blue-Green deployment, опираясь на методологию The Twelve-Factor App с примерами на php и docker
Для начала немного теории. Что такое The Twelve-Factor App?
Простыми словами, это документ призванный упростить разработку SaaS приложений, помогает тем что, осведомляет разработчиков и DevOps инженеров о проблемах \ практиках которые чаще всего встречались в разработке современных приложений.
Документ сформирован разработчиками платформы Heroku.
Методология двенадцати факторов(The Twelve-Factor App) может быть применена для приложений, написанных на любом языке программирования и использующих любые комбинации сторонних служб (backing services) (базы данных, очереди сообщений, кэш-памяти, и т.д.).
Коротко о самих факторах на которых строится эта методология:
Что такое Blue-Green deployment?
Blue-Green deployment – это способ доставки приложения на production таким образом, что конечный клиент не видит никаких изменений со своей стороны. Другими словами, разворачивание приложения с нулевым downtime.
Классическая схема BG Deploy выглядит так как указано на изображении ниже.
Вредные и хорошие советы
Disclaimer: В примерах ниже указаны утилиты / методологии которые использую я, вы можете использовать абсолютно любые альтернативы со схожими функциями.
Большая часть примеров будет так или иначе пересекаться с веб-разработкой (вот это неожиданность), с PHP и Docker.
В пунктах ниже идет простое практическое описание использования факторов на определенных примерах, если вы хотите получить больше теории по данной теме, обратитесь по ссылкам выше к первоисточнику.
1. Кодовая база
Используйте FTP и FileZilla загружая файлы на сервера по одной штучке, не храните код нигде кроме как на production сервере.
2. Зависимости
Скачивайте все библиотеки папками прямо в корень проекта. Обновления делайте просто переносом нового кода в папку с текущей версией библиотеки. Ставьте все необходимые утилиты прямо на хостовый сервер где работает ещё 20 служб.
Проект всегда должен иметь четко понятный список зависимостей (под зависимостями я так же понимаю и окружение). Все зависимости должны быть явно определены и изолированы.
В качестве примера возьмем Composer и Docker.
Composer — пакетный менеджер, позволяющий устанавливать в PHP библиотеки. Composer дает возможность строго или не строго указывать версии, и явно их определять. На сервере может быть 20 различных проектов и у каждого будет личный список пакетов и библиотек не зависящий от другого.
Docker — утилита, позволяющая определять и изолировать окружение в котором будет работать приложение. Соответственно, так же как и с composer, но уже более основательно, мы можем определить то с чем работает приложение. Выбрать определенную версию PHP, поставить только необходимые для работы проекта пакеты, не добавляя ничего лишнего. А самое главное не пересекаясь с пакетами и окружением хостовой машины и других проектов. То есть все проекты на сервере работающие через Docker, могут использовать абсолютно любой набор пакетов и абсолютно разное окружение.
3. Конфигурация
Храните конфиги константами прямо в коде. Отдельные константы для тестового сервера, отдельные для продакшена. Завязывайте работу приложения в зависимости от окружения прямо в бизнес логике проекта используя конструкции if else.
Конфигурации — это единственное чем должны различаться развертывания проекта (deployment). В идеале конфигурации должны передаваться через переменные окружения (env vars).
4. Сторонние службы (Backing Services)
Жестко завязывайтесь на окружении, используйте разные подключения для одних и тех же сервисов в определенных окружениях.
На самом деле этот пункт сильно пересекается с пунктом о конфигурациях, так как без наличия этого пункта не сделать нормальные конфигурационные данные и вообще возможность конфигурирования спадет на нет.
Все подключения к внешним службам, таким как серверы очередей, базы данных, службы кэширования должны быть едиными как для локального окружения, так и для стороннего / продакшен окружения. Иными словами, я в любой момент могу изменив строку подключения заменить обращения к базе #1 на базу #2 без изменения кода приложения. Или забегая вперед как пример подойдет то что при масштабировании сервиса, вам не придется для дополнительного сервера кэша указывать подключение каким-то особенным образом.
5. Сборка, релиз, выполнение
Имейте на сервере только финальную версию кода, без шансов откатить релиз назад. Не нужно забивать дисковое пространство. Кто думает что может пустить код на продакшен с ошибкой, тот плохой программист!
Все стадии деплоймента, должны быть разделены между собой.
Имейте шанс откатиться назад. Делайте релизы с сохранением в быстром доступе старых копий приложения (уже собранных и готовых к бою), что бы в случае ошибок восстановить старую версию. То есть условно есть папка releases и папка current, и после успешного деплоя и сборки папка current связывается символической ссылкой с новым релизом который лежит внутри releases с условным названием номера релиза.
Вот тут мы и вспоминаем о Blue-Green deployment, который позволяет не просто делать переключение между кодом, но так же и переключение между всеми ресурсами и даже окружениями с возможностью откатить все назад.
6. Процессы
Храните данные состояний приложения непосредственно в самом приложении. Используйте сессии в оперативной памяти самого приложения. Используйте как можно больше разделяемых между сторонними службами. Завязывайтесь на том что приложение может иметь только один процесс и не допускайте возможности масштабирования.
По поводу сессий, храните данные только в кэше, контролируемом сторонними службами (memcached, redis), таким образом даже если у вас будет 20 процессов приложения запущено, то любой из них обратившись в кэш, сможет продолжить работать с клиентом в том же состоянии в котором пользователь был работая с приложением в другом процессе. При таком подходе получается так что, сколько бы вы копий сторонних служб не использовали бы, все будет работать штатно и без проблем с доступом к данным.
7. Привязка портов (Port binding)
Знать как работать со сторонними службами должен только веб-сервер. А лучше вообще поднимать сторонние службы прямо внутри веб сервера. Например как PHP модуль в Apache.
Все ваши службы должны быть доступны друг для друга через обращение к какому-либо адресу и порту (localgost:5432, localhost:3000, nginx:80, php-fpm:9000), то есть из nginx я могу получить доступ как к php-fpm, так и к postgres, а из php-fpm к postgres и nginx и собственно из каждой службы я могу получить доступ к другой службе. Таким образом жизнеспособность службы не завязана на жизнеспособности другой службы.
8. Параллелизм
Работайте с одним процессом, а то вдруг несколько процессов не смогут друг с другом поладить!
Оставляйте возможность масштабирования. Отлично для этого подойдет docker swarm.
Docker Swarm — это инструмент для создания и управления кластерами контейнеров как между различными машинами так и кучей контейнеров на одной машине.
Используя swarm, я могу определять то сколько ресурсов я буду выделять на каждый процесс и какое количество процессов одной и той же службы я буду запускать, а внутренний балансировщик принимая данные на заданный порт, будет автоматически проксировать его на процессы. Таким образом увидев, что нагрузка на сервер выросла, я могу добавить больше процессов, тем самым уменьшить нагрузку на определенные процессы.
9. Утилизируемость (Disposability)
Не используйте очереди для работы с процессами и данными. Убийство одного процесса должно влиять на работу всего приложения. Если упала одна служба — падает все.
Каждый процесс и служба могут быть выключены в любой момент и это не должно затронуть другие службы (речь конечно не о том что служба будет недоступна для другой службы, а о том что другая служба не отключится в след за этой). Все процессы должны завершаться мягко, таким образом что при их завершении не пострадают данные и при следующем включении система заработает корректно. То есть даже в случае аварийного завершения, данные не должны пострадать (тут подойдет механизм транзакций, запросы в бд работают только группами, и если хоть один запрос из группы не выполнился или выполнился с ошибкой, то не никакой другой запрос из группы в итоге не выполняется в действительности).
10. Паритет разработки/работы приложения
Продакшен, стейджинг и локальная версия приложения должны быть разными. На продакшене у нас фреймворк Yii Lite, а локально Yii, чтоб на проде пошустрее работало!
В действительности все разворачивания и работа с кодом должны быть чуть ли не в идентичном окружении (речь не идет о физическом железе). Так же развернуть код на продакшене при необходимости, должен суметь любой сотрудник разрабоки, а не какой-то специально обученный devops отдел, который только благодаря особой силе может поднимать приложение в продакшене.
В этом так же нам помогает Docker. При соблюдении всех предыдущих пунктов, использование docker, доведет процесс разворачивания окружения как на production, так и на локальной машине до ввода одной-двух команд.
11. Журналирование (Logs)
Логи пишем в файлы и бд! Файлы и бд от логов не чистим. Купим просто жесткий диск на 9000 Пета байт и норм.
Все логи надо рассматривать как поток событий. Само приложение не должно заниматься обработкой логов. Логи должны выдаваться либо в stdout, либо отправляться по такому протоколу как udp, чтобы приложению работа с логами не создавала никаких проблем. Для этого хорошо подойдет graylog. Graylog принимая все логи по udp (по этому протоколу не требуется дожидаться ответа об успешном приеме пакета) не мешает приложению никаким образом и занимается только структурированием и обработкой логов. Логика приложения не меняется для работы с подобными подходами.
12. Задачи администрирования
Для обновления данных, бд и т/д используйте отдельно созданный эндпоинт в апи, выполнение которого 2 раза подряд приведет к тому что у вас все может за дублироваться. Но вы же не дураки, не нажмете 2 раза, а миграции нам ни к чему.
Все задачи администрирования должны выполняться в той же среде что и весь код, на уровне релизов. То есть, если нам необходимо изменить структуру бд, то мы не будем делать это руками меняя названия колонок и добавляя новые через какие-то визуальные инструменты управления БД. Для таких вещей мы создаем отдельные скрипты — миграции, которые выполняются везде и на всех окружениях одинакового с общим и понятным результатом. Для всех остальных задач, типа наполнения проекта данными, должны применяться схожие методологии.
Пример реализации на PHP, Laravel, Laradock, Docker-Compose
P.S Все примеры делались на MacOS. Большая часть подойдет и для Linux. Пользователи Windows уж простите, но с виндой я давно не работал.
Представим ситуацию что у нас на ПК не установлена никакая версия PHP и вообще ничего нет.
Устанавливаем docker и docker-compose последних версий. (это можно найти в интернете)
По поводу Laradock скажу что это очень классная штука, в которой собрано очень много контейнеров и вспомогательных штук. Но использовать как таковой Laradock без модификаций на production — я бы не рекомендовал из-за его избыточности. Лучше создать свои контейнеры опираясь на примеры в Laradock, так будет куда оптимизирование, ибо никому не нужно все что там есть одновременно.
2. Конфигурируем Laradock для работы нашего приложения.
2.1. Открываем каталог habr (родительская папка в которую склонирован laradock) в каком либо редакторе. (В моем кейсе PHPStorm)
На этом этапе ставим только название проекту.
2.2. Запускаем образ workspace. (В вашем случае образы будут какое-то время билдиться)
Workspace — это специально подготовленный образ для работы с фреймворком от имени разработчика.
Переходим внутрь контейнера с помощью
2.3. Устанавливаем Laravel
2.4. После установки проверяем создалась ли директория с проектом, и убиваем compose.
3. Добавим весь код в Git.
Для этого создадим на Github (или где угодно ещё) репозиторий. Перейдем в терминале в директорию habr и выполним следующий код.
Проверяем все ли в порядке.
Для удобства рекомендую использовать какой-либо визуальный интерфейс для Git, в моём случае это GitKraken. (тут реферальная ссылка)
Перед запуском убедитесь, что у вас на 80 и 443 порту ничего не висит.
Таким образом наш проект состоит из 3 отдельных сервисов:
1. Кодовая база — весь код лежит в одном репозитории (небольшая ремарка: возможно правильным будет внести docker внутрь проекта laravel, но это не принципиально).
2. Зависимости — Все наши зависимости явно прописаны в application/composer.json и в каждом Dockerfile каждого контейнера.
3. Сторонние службы (Backing Services) — Каждая из служб (php-fom, nignx, workspace) живет своей жизнью и подключена из вне и при работе с одной службой, другая не будет затронута.
4. Процессы — каждая служба это один процесс. Каждая из служб не сохраняет внутреннее состояние.
5. Привязка портов (Port binding)
Как мы видим, каждая служба запущена на своем собственном порту и доступна для всех других служб.
Docker позволяет нам поднимать несколько процессов одних и тех же служб с автоматической балансировкой нагрузки между ними.
Остановим контейнеры и запустим их через флаг —scale
Как мы видим, у php-fpm контейнера создались копии. Нам в работе с данным контейнером ничего не нужно менять. Мы так же продолжаем обращаться к нему по 9000 порту, а Docker за нас регулирует нагрузку между контейнерами.
8. Паритет разработки/работы приложения — все наши окружения одинаковые. Запустив систему на сервере в продакшен вам не придется ничего менять в ваших командах. Все будет точно так же базироваться на Docker.
9. Журналирование (Logs) — все логи в данных контейнерах выходят на поток и видны в консоли Docker. (в данном кейсе, в действительности, с другими самодельными контейнерами, может быть не так если вы об этом не позаботитесь)
Но, тут есть загвоздка в том, что Default значения в PHP и Nginx так же записывают логи в файл. Для соответствия 12 факторам, необходимо отключить запись логов в файл в конфигурациях каждого контейнера отдельно.
Так же докер предоставляет возможность направлять логи не просто в stdout, а ещё и в такие вещи как graylog о котором я говорил выше. А внутри graylog, мы можем оперировать логами как угодно и наше приложение никак не будет замечать этого.
10. Задачи администрирования — все задачи администрирования решаются laravel благодаря инструменту artisan именно так как этого хотели бы создатели 12 факторного приложения.
В качестве примера покажу как выполняются некоторые команды.
Заходим в контейнер.
Теперь можем воспользоваться любой командой. (обратите внимание что мы не настраивали базу данных и кэш поэтому половина команд не выполнится корректно, ибо они предназначены для работы с кэшем и бд).
11. Конфигурации и 12. Сборка, релиз, выполнение
Эту часть я хотел посвятить Blue-Green Deployment, но это оказалось слишком развернутым для этой статьи. Об этом я напишу отдельную статью.
В двух словах, концепт строится на системах CI/CD типо Jenkins и Gitlab CI. И в той и в другой можно задавать переменные окружения связанные с конкретным окружением. Соответственно при таком раскладе будет выполняться пункт с Конфигурациями.
А пункт про Сборка, релиз, выполнение решается встроенными в обе утилиты функции с названием Pipeline.
Pipeline позволяет разделять на много этапов процесс деплоймента, выделяя стадии сборки, релиза и выполнения. Так же в Pipeline, вы сможете создать бекапы, да и вообще что угодно. Этот инструмент с безграничным потенциалом.
Код приложения лежит на Github.
Не забудьте инициализировать submodule при клонировании данного репозитория.







