Быстрая миграция на отдельные веб-контейнеры и контейнеры данных

:warning: Внимание: Если вы не чувствуете себя уверенно в роли системного администратора Linux и у вас нет опыта работы с контейнерами Docker, переход к развертыванию с несколькими контейнерами вызовет у вас трудности. В таком случае и сотрудники, и волонтеры здесь обоснованно попросят вас вернуться к автономному развертыванию с одним контейнером, полностью управляемому скриптом launcher.

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

Рекомендуемый метод миграции с развертывания с одним контейнером на развертывание с несколькими контейнерами по сути сводится к следующему:

  • Сделайте резервную копию вашего Discourse.
  • Удалите всё без остатка.
  • Начните заново с нуля с развертыванием с несколькими контейнерами.
  • Восстановите вашу резервную копию.

Если, как и я, у вас большой сайт, восстановление которого занимает часы, вы можете задаться вопросом, есть ли более быстрый способ. Больше не нужно гадать! Я мигрировал с автономного развертывания на развертывание с тремя контейнерами (веб, данные и Redis) за время, которое обычно требуется на выполнение ./launcher rebuild app для этого сайта. (Общее время простоя составило 12 минут, тогда как перестроение приложения иногда занимало более 30 минут.) Основываясь на своем опыте, я бы в будущем оставил Redis вместе с Postgres в одном контейнере data.

Если вы сделаете это, вы берете на себя ответственность за знание того, когда нужно перестраивать ваши другие контейнеры (данные, и если вы, как и я, отделили Redis, то и Redis тоже). Вы больше не будете получать бесплатные обновления всего через ./launcher rebuild app. Если у вас нет ресурсов для управления этим процессом, используйте автономное развертывание или приобретите хостинг Discourse.

Тест

Не используйте этот процесс для миграции на несколько контейнеров, если после его прочтения вы не понимаете также, как он подскажет вам, как быстро мигрировать обратно с нескольких контейнеров на один. Если это не очевидно для вас после прочтения, значит этот пост представляет собой достаточно передовую технологию (то есть неотличимую от магии), и возможно, вы также не распознаете, если этот процесс сломается на полпути. В результате вы можете оказаться с неработающим Discourse, который вы не узнаете до тех пор, пока не станет слишком поздно. Если это произойдет, вам придется сохранить обе сломанные части. «Сломал — плати», как говорится!

Резервное копирование

Сначала сделайте резервную копию и включите резервное копирование миниатюр, чтобы не пришлось перестраивать их все при восстановлении. Если вы допустите ошибку здесь, вы легко попадете в ситуацию, когда самый простой, безопасный и быстрый способ восстановления — это переключиться на обычный метод. Будьте готовы откатиться к рекомендуемому методу, если что-то пойдет не так.

Скачайте вашу резервную копию. Команды ниже предполагают перемещение файлов в данных Discourse, и если вы допустите ошибку, возможно, вы удалите свою резервную копию. Поэтому скачайте её. И если ваша резервная копия не включает загрузки, сделайте их резервную копию тоже. Они также находятся там, где вы будете перемещать файлы.

Серьезно, сделайте резервную копию.

Когда я делал это, сначала я сделал резервную копию, затем сделал резервную копию удаленной системы, прежде чем идти дальше.

Настройка новой конфигурации с несколькими контейнерами

Вам понадобятся как минимум containers/web_only.yml и containers/data.yml, а если вы также хотите отделить Redis, то и containers/redis.yml. Начните с копирования samples/data.yml (и опционально samples/redis.yml) в директорию containers/.

Если вы разворачиваете Redis отдельно, удалите шаблон Redis из верхней части файла containers/data.yml. (Но не делайте этого без веской причины; это просто лишняя работа.)

У вас есть два способа создать web_only.yml.

  1. Скопируйте samples/web_only.yml в containers/; затем сравните оба файла с containers/app.yml, сохранив любую конфигурацию Postgres в секции params: в вашем новом файле containers/data.yml.
  • Скопируйте любые params: для Postgres из containers/app.yml в containers/data.yml.
  • Создайте уникальный пароль для замены SOME_SECRET.
  1. Альтернативно, скопируйте containers/app.yml в containers/web_only.yml и сравните его с samples/web_only.yml.
  • Удалите любые ссылки на шаблоны Postgres и Redis.
  • Удалите всю секцию params:, которая содержала только настройки Postgres.
  • Добавьте секцию links: в точности как в samples/web_only.yml или измененную (см. ниже), если вы разворачиваете Redis в отдельном контейнере.
  • Добавьте секцию базы данных из samples/web_only.yml и создайте уникальный пароль для замены SOME_SECRET.
  • Измените определения томов с standalone на web_only.

Вот секция links:, которую следует использовать, если вы отделяете Redis в собственный контейнер вместо разумного по умолчанию объединения его с Postgres в контейнере данных:

# Используйте ключ 'links' для связывания контейнеров, то есть используйте флаг Docker --link.
links:
  - link:
      name: data
      alias: data
  - link:
      name: redis
      alias: redis

Ссылка redis не нужна, если вы объединяете контейнеры Redis и Postgres в один контейнер данных; это показано для примера того, что нужно делать.

Вот копия текущих настроек Postgres в env в samples/data.yml, в которых вам нужно заменить SOME_SECRET:

  ## TODO: настройте подключение к базам данных
  DISCOURSE_DB_SOCKET: ''
  #DISCOURSE_DB_USERNAME: discourse
  DISCOURSE_DB_PASSWORD: SOME_SECRET
  DISCOURSE_DB_HOST: data
  ## Если вы используете единый контейнер data+redis, следующее значение будет "data"
  DISCOURSE_REDIS_HOST: redis

Обратите внимание, что для обычного развертывания (не мульти-сайта) вам не нужно изменять никакие другие строки. DISCOURSE_DB_SOCKET предназначен для Unix-доменного сокета для Postgres, это не номер порта.

Вот пример изменения определения томов в конце web_only.yml, которое вам нужно будет использовать, если вы копируете его из app.yml, а не из samples/web_only.yml:

@@ -75,10 +80,10 @@
 ## Контейнер Docker не имеет состояния; все данные хранятся в /shared
 volumes:
   - volume:
-      host: /var/discourse/shared/standalone
+      host: /var/discourse/shared/web_only
       guest: /shared
   - volume:
-      host: /var/discourse/shared/standalone/log/var-log
+      host: /var/discourse/shared/web_only/log/var-log
       guest: /var/log

Теперь установите тот же секретный пароль, который вы использовали в containers/web_only.yml, в containers/data.yml вместо SOME_SECRET.

Теперь вы готовы к миграции.

Сейчас самое время сделать и скачать вашу финальную резервную копию перед попыткой быстрой миграции. Помните, если что-то пойдет не так здесь, вы немедленно переходите к рекомендуемому методу. Я не могу это подчеркнуть достаточно сильно.

Отдельные контейнеры для данных (Postgres) и Redis:

cd /var/discourse

./launcher stop app
cd  shared
mkdir data
mkdir redis
mv standalone/postgres_* data/
mv standalone/redis_data/ redis/
mv standalone web_only
mkdir -p data/log/var-log
mkdir -p redis/log/var-log

cd ..

./launcher destroy app

./launcher bootstrap data
./launcher bootstrap redis
./launcher start redis
./launcher start data

./launcher bootstrap web_only
./launcher start web_only

Объединенный контейнер данных Postgres+Redis:

cd /var/discourse

./launcher stop app
cd  shared
mkdir data
mv standalone/postgres_* data/
mv standalone/redis_data/ data/
mv standalone web_only
mkdir -p data/log/var-log

cd ..

./launcher destroy app

./launcher bootstrap data
./launcher start data

./launcher bootstrap web_only
./launcher start web_only

Также обратите внимание, что если вы ранее настроили внешний nginx, вам нужно будет изменить путь proxy_pass, чтобы он соответствовал новому расположению сокета web_only; например, с http://unix:/var/discourse/shared/standalone/nginx.http.sock: на http://unix:/var/discourse/shared/web_only/nginx.http.sock:.

Для меня, на ВМ с 2 ядрами и 4 ГБ ОЗУ и сайте с резервными копиями объемом 600 МБ без загрузок, этот процесс привел к 12 минутам простоя. У вас время может отличаться.

Обратите внимание, что ничего из вышеперечисленного пока не обновляет launcher. Возможно, вы не используете актуальную версию. (Например, я выполнил это после того, как стало доступно обновление Postgres 12, но до того, как применил его. Этот процесс оставил мне Postgres 10. Затем следующим моим действием было перестроение приложения данных, что обновило launcher и успешно провело меня через процесс обновления Postgres 12.)

Что делать при будущих обновлениях

После этой миграции, если вам нужно обновить Redis или данные, вам сначала нужно остановить веб-приложение. Это будет выглядеть примерно так:

./launcher stop web_only
./launcher rebuild data # и/или redis
./launcher rebuild web_only

Обратите внимание, что если вы перестраиваете контейнер data (или postgres, или redis), вам нужно будет создать новый веб-контейнер, чтобы переподключить его к новому контейнеру данных. Вы можете сделать это либо путем перестроения web_only, либо, если вы не считаете, что его нужно перестраивать, команда ./launcher destroy web_only; ./launcher start web_only сделает своё дело (и если вы получите ошибку о «отсутствующем контейнере данных» или подобную, это именно то, что нужно сделать).

Однако, когда ни Postgres, ни Redis не требуют обновления, гораздо быстрее не перестраивать эти контейнеры, и большинство перестроений приложения — это просто ./launcher rebuild web_only.

Альтернативно, для еще меньшего простоя (сообщается разное время от 15 секунд до 2 минут):

./launcher bootstrap web_only
./launcher destroy web_only && ./launcher start web_only

Снова, перейдя к развертыванию с несколькими контейнерами, отслеживание того, когда это уместно, теперь ваша задача. Вы будете получать уведомления в консоли администратора об обновлениях, но они будут применяться только к контейнеру web_only. Ничто не подскажет вам, когда нужно обновлять Postgres или Redis. Если вы делаете это, читайте категорию «Объявления» перед каждым обновлением версии, которое вы выполняете, и читайте примечания к выпуску для каждой новой версии, до которой или через которую вы обновляетесь. То есть, если вы пропускаете обновление версии, не пропускайте чтение примечаний к выпуску для версии, до которой вы пропустили обновление. (Рассмотрите возможность настройки отслеживания примечаний к выпуску или подписки вашего читателя RSS на https://meta.discourse.org/tag/release-notes.rss, чтобы быть в курсе.)

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

Проверка резервного копирования

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

Проверьте вашу реализацию удаленного резервного копирования, чтобы убедиться, что она делает резервную копию загрузок в /var/discourse/shared/web_only, а не в /var/discourse/shared/standalone, чтобы ваши резервные копии были актуальны в вашей новой реализации с несколькими контейнерами.

22 лайка

Привет, mcdanlj! Я новичок здесь. Я заметил, что у Discourse есть два способа развёртывания: один — это автономный режим через app.yml, а другой — ваш метод, при котором база данных и кэш Redis разделяются на многоконтейнерный режим с использованием web-only.yml, data.yml и redis.yml. Однако я также обнаружил, что app.yml можно подключить к Redis и базе данных, изменив параметры DISCOURSE_DB_HOST и DISCOURSE_REDIS_HOST. Тогда зачем нужно разделять app.yml на web-only.yml, data.yml и redis.yml?

Если у вас уже есть база данных и Redis (например, RDS и ElastiCache, или вы создали их самостоятельно другим способом), то вам не нужно создавать свои собственные.

Обратите внимание, что для каждого экземпляра Discourse требуется свой отдельный Redis.

1 лайк

Спасибо, Джей, за ваше доброе объяснение! Но я всё ещё путаюсь. Из руководства Falco я заметил, что легко использовать AWS RDS и Elasticache без необходимости настраивать файлы web-only.yml, data.yml и redis.yml. В руководстве Falco редактируются только параметры в app.yml. Однако руководство mcdanlj отличается. Это потому, что его форум слишком большой? Поэтому он не может использовать простой способ, предложенный Falco?

Использование RDS и запуск собственного сервера баз данных — это две разные вещи. Если у вас много денег и опыта, RDS — отличный выбор. Если вы ничего не знаете, установка в одном контейнере — замечательное решение. Если у вас мало денег, но вы хотите уменьшить время простоя, подход с двумя контейнерами — хороший вариант.

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

1 лайк

Спасибо большое! Возможно, одиночный контейнер — это лучший вариант для меня :rofl: Я не понимал разницы между RDS и собственным сервером баз данных, пока вы мне не сказали :joy:

1 лайк

@ShawnLi Если система из двух контейнеров кажется вам сложной, это хороший знак: для вас оптимальным выбором будет стандартная одноконтейнерная конфигурация. Развёртывание с двумя контейнерами экономит несколько минут простоя примерно раз в месяц при обновлениях, но требует более глубокого понимания и обязывает вас вручную следить за деталями в объявлениях при каждом новом релизе.

Именно поэтому я начал с этого:

:grinning:

2 лайка

Спасибо, mcdanlj! Ваш урок отличный, и я действительно многому научился благодаря ему. Я решил выбрать простую настройку по умолчанию с одним контейнером. Да, я запускаю :rofl:

2 лайка