Ловушки на пути сине-зеленых развертываний с Docker

Docker (а также Kubernetes) предлагает вам способ обновлять ваши приложения без простоев с помощью общей стратегии, называемой
Сине-зеленое развертывание.

Сине-зеленые развертывания работают следующим образом:

  1. Ваше текущее развернутое приложение («Зеленый») обслуживает входящий трафик.
  2. Новая версия вашего приложения развернута («синяя») и протестирована, но еще не получает никакого трафика.
  3. Когда «Синий» будет готов, мы можем начать отправлять входящий трафик и на «Синий».
  4. На данный момент у нас есть две копии нашего приложения, работающие параллельно («Зеленая» и «Синяя»).
  5. Теперь мы должны перестать отправлять входящий трафик в «Зеленое» приложение, «Синее» обрабатывает весь входящий трафик.
  6. Поскольку «Зеленый» больше не получает трафика, его можно безопасно удалить.
  7. «Синий» будет помечен как «Зеленый», что позволит в будущем развернуть более новую версию с использованием той же стратегии.

Сине-зеленое развертывание Docker Swarm

Если вы используете Docker Swarm, это может быть файл стека, реализующий сине-зеленую стратегию развертывания.



version: '3.4'
services:
  app:
    image: acme/todo-list:${VERSION}
    deploy:
      update_config:
        order: start-first

acme/todo-list это простое веб-приложение списка дел. update_config.order: start-first инструктирует docker swarm
используйте сине-зеленую стратегию развертывания.

Разверните v1 нашего списка задач в кластере Docker-Swarm, который мы можем запустить:

VERSION=v1 docker stack deploy todolist_app -c app.yml

Если мы хотим обновить приложение до v2 мы можем запустить:

VERSION=v2 docker stack deploy todolist_app -c app.yml

Обновление будет следовать сине-зеленой стратегии развертывания, как описано выше.
Докер сохранит v1 работает и будет развернут v2.
Когда v2 готов, он будет перенаправлять весь трафик на v2 и удалит v1. Аккуратный!

Но если мы посмотрим на журналы нашего балансировщика нагрузки, мы увидим что-то вроде:

1.2.3.4 - - [13/Jun/2019:06:00:10 +0000] "GET /toto/list HTTP/1.1" 502 150 ....

Код состояния 502«Плохой шлюз».
Этот код состояния HTTP означает, что балансировщик нагрузки получил недопустимый ответ от сервера приложений (или не получил ответа).
Почему это?

Удалять v1после прекращения отправки входящего трафика Docker отправляет SIG_TERM сигнал к приложению и ждет
до 10 секунд, чтобы приложение корректно завершило работу.
Если v1 все еще работает через 10 секунд, Докер жестоко убивает v1 приложение.
Это прервет любое соединение, которое было у приложения (и ожидающие запросы получат ошибку 502).

Изящная остановка

Мы можем изменить количество секунд, в течение которых Docker будет ждать перед удалением контейнера, настроив параметр stop_grace_period параметр:



version: '3.4'
services:
  php:
    image: acme/todo-list:${VERSION}
    stop_grace_period: 120s
    deploy:
      update_config:
        order: start-first

При такой конфигурации после отправки SIG_TERM сигнал, докер будет ждать до двух минут, прежде чем закрыть приложение.
В зависимости от конкретной логики и времени отклика вашего приложения вы можете указать докеру, как долго
подождите, пока ваше приложение завершится, прежде чем принудительно его выполнить.

Сине-зеленые развертывания и PHP-FPM

Если вы используете PHP-FPM, предыдущих конфигураций может быть недостаточно.

К сожалению (?) PHP-FPM настроен по умолчанию на завершение сразу после получения SIG_TERM сигнал.
Даже если докер готов ждать 10 секунд (или любое другое значение, которое вы могли настроить с помощью stop_grace_period)
PHP завершит себя (и все обслуживаемые запросы) без ожидания.

Это снова приведет к 502 ошибки.

Чтобы решить эту проблему, мы также должны указать PHP, чтобы у него было достаточно времени для завершения обслуживания ожидающих запросов,
тюнинг process_control_timeout параметр (проверьте здесь полный список конфигураций PHP-FPM).

Установив process_control_timeout = 5,
PHP-FPM будет ждать до 5 секунд, прежде чем выйти и убить все процессы, которые обслуживали запросы.

Мы можем добавить этот параметр в Dockerfile при создании нашего образа PHP.


FROM php:fpm



RUN { \
    echo '[global]'; \
    echo 'process_control_timeout = 5'; \
    } | tee /usr/local/etc/php-fpm.conf
    

Точно так же, как докер ждал завершения работы контейнера, теперь PHP будет делать то же самое и ждать до 5 секунд.
чтобы его дочерние процессы завершили обслуживание запросов.

Таким образом мы настроили, как долго докер должен ждать перед завершением контейнера, а также как долго PHP
будет ждать завершения запросов.

Если PHP может остановить работу менее чем за 5 секунд, он это сделает (например, когда все ожидающие запросы будут быстро обработаны).
То же самое относится и к докеру.
Таким образом, эти тайм-ауты применяются только в худшем случае.

Этот пост был впервые опубликован на https://www.goetas.com/blog/traps-on-the-way-of-blue-green-deployments/.

Похожие записи

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *