Помощь с настройкой «zero downtime»

Я пытаюсь разобраться в конфигурации «без простоев» (zero downtime). В моей текущей настройке есть несколько экземпляров Discourse для разных сообществ. У обоих используется конфигурация контейнеров data и web версии 2. На уровне хоста работает Nginx, который обрабатывает окончание SSL-соединения и использует сокетное соединение, передаваемое в Nginx контейнера.

Нашёл две темы, представляющие интерес:

Пытаюсь понять этот процесс. Кажется, что для его выполнения предполагается наличие определённых знаний. Любая помощь здесь была бы очень кстати.

Первое, что я хотел бы понять: как узнать, когда контейнер data нуждается в обновлении. Казалось бы, есть случаи, когда нельзя просто пересобрать контейнер web. Как мне точно определить, когда это так? Это все случаи, когда опция обновления в панели администратора (UI) для обновлений серая, а также потенциальная кастомная работа с темами и плагинами? Смогу ли я узнать это наверняка, просмотрев миграции схемы базы данных? Или мне нужно будет настроить staging-окружение и просто попробовать, чтобы убедиться?

Следующий вопрос: как выполнить обновление без простоев. Судя по двум ссылкам, всё равно придётся пересобирать контейнеры data и web? Я не могу расшифровать это. Нужно ли иметь отдельные контейнеры data и web, чтобы в итоге достичь обновления без простоев?

Любые рекомендации будут отличными! Вероятно, я мог бы потратить много часов и найти что-то, что вроде бы работает, но лучше опереться на плечи гигантов и не выяснять нюансы на собственном горьком опыте (в продакшене), если это возможно.

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

Спасибо.

Я не очень хорошо знаком с «миграцией после развёртывания», но, насколько я помню из прочитанного (здесь, на meta), один из способов добиться этого — использовать 3 контейнера: 1 для данных и 2 для веб-сервисов. Вы обновляете нерабочий веб-контейнер, а после обновления переключаетесь на него.

Думаю, это имеет смысл. Значит, контейнер с данными не выполняет пересборку через лаунчер? Я бы просто обрабатывал балансировку нагрузки на уровне хоста с помощью Nginx. Позвольте мне попробовать это организовать:

контейнер с данными:

./launcher enter data_container 
SKIP_POST_DEPLOYMENT_MIGRATIONS=1 rake db:migrate

контейнер веб-приложения:

./launcher rebuild web_container1 && \
sleep 60 && ./launcher rebuild web_container2 

контейнер с данными:

rails generate post_migration
SKIP_POST_DEPLOYMENT_MIGRATIONS=0 rake db:migrate

Кажется ли это разумным?

Всё зависит от того, какие обновления необходимо внести в контейнер с данными.

Обновление Postgres 12 — хороший пример неизбежного простоя. Даже если у вас есть дубликат контейнера с данными, вам всё равно потребуется перевести ваш дублирующий сайт в режим только для чтения во время обновления базы данных.

Единственный способ никогда не испытывать простоя — никогда не обновляться. Обновления через /admin/upgrade в установке на одном контейнере уже осуществляются без простоя. Обновления, выполняемые через ssh (например, когда необходимо обновить базовый образ), могут сопровождаться простоями различной продолжительности в зависимости от вашего бюджета и готовности к усложнению инфраструктуры.

Лучший способ избежать простоя — создать тестовую копию (staging). В противном случае вы рискуете столкнуться с небольшим простоем после каждого обновления, если плагины или кастомизации столкнутся с проблемами совместимости.

Хорошо. Чтобы избежать серьёзных проблем, давайте сначала проведём тестирование на staging-окружении и посмотрим на результаты… То есть я попробую описанную выше процедуру и проверю, не упадёт ли контейнер с данными?

Если это произойдёт, то в staging-окружении у нас будет 1 узел с данными и 1 веб-узел, а в production — 2 узла с данными и 2 веб-узла. В худшем случае, если мы сначала попробуем это на staging, а затем применим в production, процедура будет следующей:

  • установить режим «только для чтения»
  • cp -rp shared/data1 в shared/data2
  • обновить data2
  • остановить web2
  • связать data2 с web2
  • пересобрать web2
  • связать data2 с web1
  • пересобрать web1
  • отключить режим «только для чтения»

Имеет ли это смысл?

Это зависит от вашего определения простоя.

Если пользователи не могут получить доступ к сайту, это, очевидно, простой.

Считаете ли вы простоем ситуацию, когда они не могут зарегистрироваться, создавать сообщения, отвечать или ставить лайки?

Если это крупное сообщество, расходы на запуск нескольких контейнеров данных на SSD будут значительными. Рассматривали ли вы внешний сервер PostgreSQL, например Amazon RDS?

Детали, на которые указывает @Stephen, действительно важны. Ведь нам нужно понимать, что такое нулевое время простоя. Например, я мог бы обойти требование «нулевого времени простоя» следующим образом:

Я определяю «нулевое время простоя» как никогда не отвечать пользователю кодом, отличным от HTTP 200, при корректном запросе (оставляя коды 300 и 400 доступными при необходимости). Затем я разворачиваю Discourse на droplet за 10 долларов в одноконтейнерном решении и добавляю Add an offline page to display when Discourse is rebuilding or starting up, чтобы избежать ошибок 500. Таким образом, я не показываю сайт, который был недоступен.

Считал бы я в здравом уме, что это «нулевое время простоя»? Никогда. Работает ли это так, как предложено? Конечно. И я мог бы пойти дальше и добавить резервный сервер в другом регионе, чтобы сделать это ещё более «устойчивым к нулевому времени простоя».

Вот почему важны уточнения и семантика. Это не одно и то же — всегда показывать что-то и всегда иметь функциональность на сайте.

Просто помогите нам понять. Что вам нужно для достижения вашего определения «нулевого времени простоя»? Могут ли пользователи столкнуться с 10–30 минутами режима только для чтения? Достаточно ли вы технически подкованы, чтобы найти обходное решение? Или вы хотите предоставить нашим пользователям красивую страницу с надписью Технические работы, скоро вернёмся. Нам нужны дополнительные детали, чтобы предложить вам более точное решение, которое действительно подойдёт вам. Или хотя бы направить вас в правильном направлении.