Обходной путь для страницы технического обслуживания — можно ли это сделать?

Да, я бы сделал это поэтапно:

  1. взять немного более мощный сервер
  2. настроить установку двух контейнеров

если на этом этапе вы довольны результатом, остановитесь здесь, или:

  1. реализуйте страницу технического обслуживания, используя отличное руководство @Lilly, приведённое выше. :+1:

Ха-ха, я рад, что вы спросили, потому что я не удосужился объяснить эту часть (мне следовало это сделать — здесь есть что рассказать, и Cloudflare довольно сложен!).

Когда настроен маршрут для Workers, каждая загрузка изображения и просмотр страницы на форуме проходят через этого Worker.

Бесплатный тарифный план CDN от Cloudflare включает лимит в 100 000 запросов в день на маршрут Worker.

Таким образом, если у вас относительно загруженный форум, чтобы не исчерпать лимит бесплатного тарифа за один день, имеет смысл не держать этот маршрут включенным постоянно. Речь идет именно о маршруте Worker, а не о странице обслуживания — страницу обслуживания можно оставить включенной всё время; она не будет вызываться, пока не активирован маршрут Worker. Речь идет только о Шаге 2, где вы назначили маршрут (который легко настроить и удалить). Если вы не используете платный план Cloudflare, то хорошим тоном считается держать его включенным только во время проведения собственного обслуживания.

  1. Перейдите на страницу маршрутов Workers для вашего домена в Cloudflare и нажмите кнопку справа от маршрута.

  1. В нижней части экрана редактирования нажмите кнопку remove (удалить), чтобы отвязать страницу Worker от маршрута.

  1. Не волнуйтесь, сам код Worker не будет удален, только правило маршрутизации. В следующий раз, когда вы будете выполнять пересборку или обновление, вы сможете просто добавить его снова, как в Шаге 2 выше.

Если вы используете платный план Cloudflare, то вам не о чем беспокоиться. Однако в этом случае вы можете использовать страницы ошибок Cloudflare вместо страницы Workers… (Я уже упоминал, что Cloudflare довольно сложен? ЛОЛ).

:warning: ниже приведена расширенная конфигурация для администраторов

Если вы хотите полностью автоматизировать обновления на бесплатном плане, вам следует использовать токен API Cloudflare, ваш zone-id и команду curl, чтобы получить route id (идентификатор маршрута) для Workers. Затем отредактируйте скрипт /root/update-web.sh, добавив туда немного «веселой» логики для автоматического включения и выключения маршрута Worker:

#!/bin/bash
cd /var/discourse

CF_TOKEN="your_actual_token_here" #<---Токен API Cloudflare
ZONE_ID="xxxx" #<---Взят со страницы профиля Cloudflare
ROUTE_ID="xxxx"
WORKER_NAME="my-site-maintenance-page"

echo "➡️ Загрузка последних скриптов Docker Discourse..."
git pull

echo "➡️ Инициализация нового веб-контейнера в фоновом режиме..."
./launcher bootstrap web_only

if [ $? -eq 0 ]; then
    echo "✅ Инициализация успешна!"
    
    # ВКЛЮЧАЕМ Worker для страницы обслуживания Cloudflare
    echo "🚧 Включение страницы обслуживания..."
    curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/workers/routes/$ROUTE_ID" \
         -H "Authorization: Bearer $CF_TOKEN" \
         -H "Content-Type: application/json" \
         --data '{"pattern":"*your-site.com/*","script":"'$WORKER_NAME'"}' > /dev/null

    # Замена контейнеров (окно простоя 30 секунд)
    echo "🔄 Замена контейнеров..."
    ./launcher destroy web_only && ./launcher start web_only
    
    # ВЫКЛЮЧАЕМ Worker для страницы обслуживания Cloudflare
    echo "🌍 Отключение страницы обслуживания..."
    curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/workers/routes/$ROUTE_ID" \
         -H "Authorization: Bearer $CF_TOKEN" \
         -H "Content-Type: application/json" \
         --data '{"pattern":"*your-site.com/*","script":null}' > /dev/null

    echo "🚀 Готово! Сайт обновлен без видимого простоя."
else
    echo "❌ Инициализация не удалась! Прерываем замену, чтобы текущий сайт оставался в сети."
fi 

Я использую предыдущую версию скрипта, потому что мне не хочется автоматизировать всё подряд, и мне нравится присутствовать при выполнении обновлений/пересборок. Я просто добавляю маршрут Workers прямо перед обновлением, а затем удаляю его после. Это занимает всего несколько секунд.

Мои общие шаги:

  1. Добавить маршрут Workers в Cloudflare
  2. Подключиться к Hetzner по SSH
  3. Выполнить системные обновления (например: sudo apt update && sudo apt upgrade -y, затем перезагрузить сервер, если необходимо)
  4. Подключиться по SSH снова, если была перезагрузка
  5. Запустить ./update-web.sh
  6. Удалить маршрут Workers в Cloudflare

Я совершенно не разбираюсь в программировании и мире разработки, если не считать одного единственного эксперимента с «Hello World» на Visual Basic, который я когда-то давно проводил. Однако я могу кое-что сделать, потому что лучше разбираюсь в администрировании своих серверов WordPress и Mastodon/Pixelfed, а также, как-никак, своего Discourse. Плюс есть такая штука, как ИИ (которая, кстати, для новичка оказывается не такой простой, как это рекламируется).

Я не знаю, возможно ли это в принципе в Discourse из-за Docker, но в обычном мире Nginx-Varnish-WordPress я создал систему, при которой сервер Plesk получает информацию об ошибках 50x и показывает страницу ошибки. На самом деле у меня есть три варианта настройки: фронтенд-сервер Nginx показывает сгенерированный снимок контента, если Varnish недоступен; Varnish начинает использовать снимок для некэшированного контента, если бэкенд, связанный с WordPress, недоступен; и третий вариант — страница ошибки, если фронтенд-сервер Nginx не отвечает.

Решения с Varnish не подходят для Discourse, но я не вижу причин, по которым нельзя было бы построить подобную «паутину» и в мире Docker, где любая ошибка 50x приводила бы к отображению страницы ошибки.

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

К тому же есть самый очевидный ответ, конечно: использовать, например, Nginx перед Discourse. Я использовал такой подход, прежде чем перешел на двухконтейнерную конфигурацию.

Наконец-то я нашёл время, чтобы снова установить Discourse. Подумав о том, где я сейчас нахожусь, и сколько обслуживания требуют два контейнера, я решил пока остаться с одним. Если в будущем мне понадобятся два контейнера, я пересмотрю всё, что было сказано здесь. Кроме установки плагинов, в которой, кажется, я буду нуждаться не так часто, как в управлении компонентами, то, что сообщество будет недоступно 20 минут в период, когда онлайн меньше людей, а также баннер, предупреждающий о дате и времени простоя, кажется вполне разумным решением на данный момент.

Посмотрим, как всё пойдёт.

Требует столько же, сколько и один контейнер :flushed_face:

И меньше душевных мук :slight_smile:

Можете ли вы уточнить, как это происходит?

Не уверен(а), ты отвечал(а) мне или @Jagster? Что ты имеешь в виду?

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

Хорошо, значит, вы рекомендуете использовать оба варианта, и именно поэтому это «меньше головной боли».
Так, как человек без опыта в этом вопросе, я полагаю, что наличие двух контейнеров не означает наличие двух экземпляров Discourse, верно?

Я читаю эту тему:

и этот пост:

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

Хочу похвалить за публикацию о настройке с двумя контейнерами. Я использовал один контейнер, и обычно это занимало 3–5 минут (на выделенном сервере с 64 ГБ ОЗУ).

Подскажите, пожалуйста, на простых и понятных примерах, когда нужно обновлять оба контейнера в двойной установке? Имею в виду, какие обновления Discourse требуют перезапуска обоих контейнеров, а какие — только недавно созданного web_container?

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

./launcher bootstrap web_only && ./launcher destroy web_only && ./launcher start web_only ) 2>&1 | tee ~/$(date +%Y-%m-%d_%H-%M-%S)-upgrade.log'

Часть с tee нужна только для логирования, так как просматривать её (мне) удобнее, чем поток в tmux, который я использую.

Но по сути это абсолютно то же самое, что использование app.yml и пересборка, только это гораздо меньше беспокоит пользователей. Конечно, есть и data-контейнер, но он требует внимания и заботы очень редко — а если вы будете выполнять более сложные манипуляции с контейнером, вы, скорее всего, и так знаете, что и когда делать с контейнерами.

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

Так что только запуск требует немного больше усилий, но инструкции довольно ясны. Я бы сказал, что использование mail-reveiver — более сложная задача, если вы используете Amazon SES.

Например, я не могу просто проигнорировать комментарий такого рода, поскольку, судя по всему, обновление/апгрейд перестаёт быть таким простым, как нажатие кнопки, и требует больше внимания и сосредоточенности. Для опытного человека это может показаться лёгким и очевидным, но для новичка — не обязательно:

Можно ли сказать, что инструкции в этой теме всё ещё актуальны в 2026 году, учитывая, что она была создана в 2015-м?

Мне не сложно попробовать, так как я только что снова установил Discourse. Если что-то пойдёт не так, я всегда смогу вернуться к одному контейнеру. Просто хочу убедиться, что, дойдя до середины процесса, я не начну выполнять действия, которые больше не актуальны в 2026 году…

Для меня экономия в несколько минут составляет более 20 минут. Утверждение о том, что это происходит раз в месяц, верно, если обновляться раз в месяц, но я обновляю систему как минимум дважды в неделю. А если какой-то плагин не сработал и приходится делать несколько попыток (ведь мы, конечно, работаем с боевыми инстансами :wink:), то такой длительный простой просто невыносим.

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

Я в замешательстве…

С одной стороны, вы говорите:

А с другой, ваш ответ выше звучит так, будто работы будет больше, когда вы пишете:

Само по себе это звучит так, будто два контейнера действительно сложнее в обслуживании, а не так же, как один. Да, я понимаю всё насчёт простоя и так далее, но обслуживание самих контейнеров кажется более сложным и более подверженным ошибкам, чем простой апгрейд с одним контейнером. Или я что-то упускаю?

это верно:

Контейнер 1 = веб-сайт и nginx
Контейнер 2 = база данных и redis

(я думаю, что я всё правильно понял)

Содержимое Контейнера 1 меняется очень часто

Содержимое Контейнера 2 — крайне редко.

И вы можете обновить Контейнер 1, не обновляя Контейнер 2.

И что ещё лучше, вы можете подготовить замену для Контейнера 1, а затем заменить его за несколько секунд (эта подготовка называется «bootstrapping»)

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

В случае с двумя контейнерами вы пересобираете только “web”, а не контейнер с данными. Если всё прошло гладко, старый контейнер будет уничтожен и запущен новый. Если же что-то пойдёт не так, ваш старый и работоспособный “web” продолжит функционировать.

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

Конечно, вариант с одним контейнером тоже возможен. Но главная мысль в том, что при создании двух контейнеров единственное реальное отличие заключается в имени уровня сложности, которое используется при обновлении, — а для этого есть alias :wink:

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

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

Однако это происходит раз в несколько лет, и база пересоздаётся, когда вы явно пересобираете её, а CDCK, похоже, некоторое время сохранял совместимость со старыми версиями pgsql. Так что это никогда по-настоящему не доставляло мне хлопот. Пока что.

Я очень люблю настройку с двумя контейнерами (или даже больше!) для себя, но я всё же оговариваюсь, потому что это не самое простое решение для всех. Мне трудно судить, для кого развёртывание с двумя контейнерами будет ощущаться как «ну конечно, это же просто», а для кого — как «фу, я просто хочу нажать на кнопку».