Конфигурация развертывания Discourse по мнению MKJ

В обновлении произошла ошибка

api_key = "a quick brown fox"
fetch("https://api.example.com/data", headers: { 'Authorization' => api_key })

Пожалуйста, помогите мне это исправить.up/backup-config

restic --cache-dir=/var/restic
backup
/etc
/root
/var/discourse
/opt/backup
–exclude /var/discourse/shared/data/postgres_data

restic --cache-dir=/var/restic forget
–prune --keep-hourly 24 --keep-daily 7 --keep-monthly 3
EOF

chmod +x backup


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

```shell
# cat > backup-config <<EOF
### Эти параметры зависят от выбранной вами целевой системы restic, поэтому измените их
export AWS_ACCESS_KEY_ID=yours-here
export AWS_SECRET_ACCESS_KEY=same
export RESTIC_PASSWORD_FILE=/root/restic-password
export RESTIC_REPOSITORY=see-the-restic-documentation
EOF
# {$EDITOR:-nano} /root/restic-password

Вам необходимо сохранить копию содержимого файла /root/restic-password, иначе вы не сможете прочитать резервные копии! Используйте ваш менеджер паролей.

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

# cat > /etc/systemd/system/backup.service <<EOF
[Unit]
Description=Back up to remote target
Wants=network-online.target
After=network-online.target

[Service]
Type=oneshot
StandardOutput=file:/var/log/backup.out
StandardError=file:/var/log/backup.err
WorkingDirectory=/var/discourse
ExecStart=/opt/backup/backup

[Install]
WantedBy=multi-user.target
EOF
# cat > /etc/systemd/system/backup.timer <<EOF
[Unit]
Description=Regular system backups

[Timer]
Persistent=true
OnCalendar=00/4:30:00
Unit=backup.service

[Install]
WantedBy=timers.target
EOF

# systemctl daemon-reload
# . /opt/backup/backup-config
# restic init
# /opt/backup/backup
# systemctl enable backup.timer

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

# restic snapshots

Я успешно использовал резервные копии restic, созданные таким образом, для переноса сервера Discourse с одной системы на другую с помощью команды restic restore.

Потоковое резервное копирование изображений в minio

В качестве альтернативы Restic, хотя резервные копии базы данных можно хранить в S3, отдельного резервного копирования изображений в S3 (отдельно от обслуживания изображений из S3) не существует. Альтернативой является использование minio-client для копирования изображений в любое хранилище, совместимое с S3. Это может быть множество целей, совместимых с S3, включая S3 и minio, но не DigitalOcean Spaces, поскольку они построены на основе файловой системы Ceph, которая не реализует API ListObjectsV2 так же, как S3.

В S3 создайте бакет, который блокирует публичный доступ (PermissionsBlock public access — это простой способ сделать это правильно в AWS).

Установите minio-client (mc) каким-либо образом. Вот один из вариантов.

curl https://dl.min.io/client/mc/release/linux-amd64/mc > /usr/local/bin/mc && chmod +x /usr/local/bin/mc

Настройте minio-client с псевдонимом backup, используя команду, подобную этой:

# mc alias set backup https://s3.amazonaws.com ACCESSKEY SECRETKEY --api S3v4
# mc mirror /var/discourse/shared/standalone/uploads backup/UPLOADS-BACKUP-BUCKET

Затем создайте службу /etc/systemd/system/backup-uploads.service следующим образом:

[Unit]
Description=Neartime remote backup sync of discourse uploads
After=network.target
StartLimitIntervalSec=0

[Service]
Type=simple
Restart=always
RestartSec=600
User=root
ExecStart=/usr/local/bin/mc mirror --overwrite -a --watch /var/discourse/shared/app/uploads backup/UPLOADS-BACKUP-BUCKET

[Install]
WantedBy=multi-user.target

Обратите внимание, что UPLOADS-BACKUP-BUCKET здесь должен быть отличным от бакета s3_backup_bucket, в который вы настраиваете Discourse для загрузки резервных копий базы данных. Также обратите внимание, что путь будет /var/discourse/shared/web_only/uploads, если вы используете стандартное многоконтейнерное развертывание.

# systemctl enable backup-uploads
# systemctl start backup-uploads
# journalctl -fu backup-uploads

Загрузите тестовое изображение и убедитесь, что видите строки об успешном резервном копировании оригинальных и оптимизированных изображений. Ctrl+C завершит режим слежения в journalctl.

Восстановление

На момент написания этой статьи мне никогда не приходилось тестировать этот план. В этом резюме может упускаться что-то.

  • Восстановите все резервные копии файлов в общем случае
  • Запустите nginx (теперь будет отображаться страница технического обслуживания)
  • Выполните обычное развертывание Discourse, используя восстановленные файлы в /var/discourse/containers
  • Установите minio-client в /usr/local/bin/mc, если вы не восстановили его из резервных копий
  • Если вы не сделали резервную копию /root/mc, настройте псевдоним резервного копирования # mc alias set backup https://s3.amazonaws.com ACCESSKEY SECRETKEY --api S3v4
  • # mc cp backup/UPLOADS-BACKUP-BUCKET /var/discourse/shared/app/uploads
  • Восстановите последнюю резервную копию базы данных; я рекомендую вам Restore a backup from the command line
  • Только после того, как вы подтвердите работоспособность сайта, снова настройте резервное копирование загруженных файлов в S3, как описано выше.

Потоковое резервное копирование postgresql

В будущем я, возможно, создам, протестирую и предоставлю конфигурацию для использования непрерывного архивирования WAL для потоковой передачи практически мгновенных резервных копий Postgres с помощью minio-client, используя archive-command в postgresql, аналогично потоковому резервному копированию загруженных файлов.

Мониторинг производительности

Существует как минимум два подхода к мониторингу производительности.

Контейнер Prometheus

Настройте prometheus, разместив логи prometheus в /var/discourse/shared/prometheus, если вы запускаете его на той же системе. Файлы Prometheus могут стать большими, и вы не хотите, чтобы они заполнили корневую файловую систему; также, вероятно, вы захотите перенести их, если перейдете на новую систему хоста (либо при обновлении до более крупной ВМ, либо при переходе на ВМ с новой установкой операционной системы).

Если вы развертываете prometheus на системе discourse (или где-либо еще в публичном интернете), настройте безопасность перед ним. При такой установке одним из вариантов может быть конфигурация nginx, подобная этой:

  location /prometheus/ {
    auth_basic "Prometheus";
    auth_basic_user_file /etc/nginx/prometheus-htpasswd;
    proxy_pass http://localhost:9090/;
  }

Sysstat

Если Prometheus слишком сложен, рассмотрите возможность использования sysstat вместо него.

  • dnf install sysstat (или apt install sysstat на debian и его производных)
  • systemctl enable --now sysstat
  • systemctl enable --now sysstat-collect.timer
  • systemctl enable --now sysstat-summary.timer
  • systemctl edit sysstat-collect.timer и измените OnCalendar=*:00/10 на OnCalendar=*:00/2
  • Если существует /etc/default/sysstat, измените false на true

После этого команда sar сможет сообщить вам, не заканчиваются ли у вас ресурсы время от времени.

Другие ресурсы

Вот дополнение (и более компактное) обсуждение использования Discourse внутри компании в качестве основной формы внутренней коммуникации.

54 лайка

Привет, спасибо за эту инструкцию

Какие у вас сейчас процессор (количество ядер) и оперативная память?
Какие у вас текущие настройки:

  db_shared_buffers: "x ГБ"
  db_work_mem: "x МБ"
  UNICORN_WORKERS:

2 vCPU (L5640 Xeon), 4 ГБ ОЗУ — но благодаря массовому импорту у нас больше контента на одного одновременного пользователя, чем в типичном Discourse, который был создан полностью органически. У нас редко бывает больше 5 одновременных пользователей.

Сейчас я не установил db_work_mem в data.yml, но похоже, что он установлен на 10 МБ в /etc/postgresql/13/main/postgresql.conf. В моём data.yml я установил db_shared_buffers: "768MB", но теперь вижу, что в /etc/postgresql/13/main/postgresql.conf в моём контейнере данных указано shared_buffers = 512MB, что меня удивляет. Похоже, я не пересобрал контейнер данных после последнего изменения. :roll_eyes: Я внес изменение в конфигурацию до добавления prometheus (который использует больше памяти), поэтому перед изменением этого параметра, вероятно, перенесу prometheus с этого сервера.

В приложении я установил UNICORN_WORKERS: 4

1 лайк

Спасибо @mcdanlj за все эти полезные материалы. Есть ли какие-то рекомендации по периодическому или запланированному обслуживанию? Например, еженедельные или ежемесячные перезагрузки? Или мониторинг состояния (вверх/вниз) с автоматической перезагрузкой? Есть ли ещё какие-либо периодические ручные или автоматизированные задачи по обслуживанию?

1 лайк

@jaffadog Следите за тегом release-notes (это колокольчик в правом верхнем углу; я использую опцию «Следить за первым сообщением») и/или добавьте https://meta.discourse.org/tag/release-notes.rss в свой RSS-канал, чтобы узнавать о новых выпусках. Обычно обновления приложения выходят раз в месяц, что соответствует ежемесячной перезагрузке. Я не планирую перезагрузки чаще. Также:

Если вы используете letsencrypt и mail_receiver, вероятно, стоит настроить перезапуск mail_receiver после получения нового сертификата.

На данный момент больше ничего не приходит на ум. Спасибо за вопрос, и я добавил информацию о том, как следить за тегом release-notes, а также более конкретные сведения о перезагрузке, в основной текст. Думаю, теперь всё полностью охвачено в исходном сообщении.

Я дополнил инструкции по обновлению, чтобы они включали обновление в /var/discourse для изменения версии базового образа, поскольку, ознакомившись с Update base image for polkit vulnerability, я понял, что отсутствие явного указания этого шага может вводить в заблуждение. Ранее я считал это частью базовой документации. Скрипт launcher содержит конкретную ссылку на версию базового образа, и пока вы не выполните git pull, вы будете собирать образ на основе старой версии базового образа, а не той, которая была протестирована. (Ищите image= в верхней части файла.)

1 лайк

Дело ещё хуже: по умолчанию он настроен на удаление неактивных учётных записей уровня 0 через определённый период. В моём случае это было совсем не то, что я хотел! Установите галочку «Очистить неактивных пользователей после N дней» и задайте значение ноль или очень большое число.

2 лайка

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

Нет, «неактивный» здесь не означает active=false.

Это означает, что к пользователям применяются все нижеперечисленные условия:

  • уровень доверия 0
  • нет сообщений
  • не администратор, не модератор
  • последний раз виделись более X дней назад.

Да, такая формулировка действительно сбивает с толку, хотя в настройках это отчасти объясняется («уровень доверия 0 без каких-либо сообщений»).

8 лайков

На самом деле я перепутал разные настройки и имел в виду «Очистка неиспользуемых пользователей, находящихся в стадии подготовки, через N дней». Я уже давно установил значение «Очистка неактивных пользователей через N дней» равным нулю на форуме Maker, но забыл упомянуть об этом здесь; вероятно, я упустил это при проверке изменённых настроек сайта, когда искал темы, которые могли бы представлять общий интерес. Спасибо вам обоим, @Ed_S и @RGJ! Я обновил пост, добавив ещё один абзац о возможности наблюдения за обсуждениями без участия. :smiling_face:

4 лайка

Привет, @mcdanlj, спасибо за ваши отличные идеи, которыми вы делитесь здесь. Что касается установки в два контейнера, я не совсем понимаю, как это даёт преимущество в сокращении времени простоя при выполнении обновлений. На моей тестовой установке обновление через графический интерфейс /admin/upgrade#/upgrade/all действительно занимает несколько минут, как вы и описываете, но сайт остаётся доступным для пользователей на протяжении всего процесса.

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

2 лайка

Как обычно, @pfaffman оказался быстрее меня и отлично разбирается в теме. :smiley:

Я никогда не делаю обновления через графический интерфейс. Таким образом, при каждом обновлении я включаю любые системные обновления безопасности в базовые контейнеры, на которых работает Discourse. Это не означает, что использование графического интерфейса — это плохо, и я не рекомендую это всем остальным. Обновление через графический интерфейс обеспечивает немного меньшее время простоя (перезапуск веб-контейнера временно прерывает работу сервиса, что является одной из нескольких причин рассмотреть его использование вместе с внешним nginx), так что это компромисс, и я выбрал менее проторенную дорожку.

Одноконтейнерная установка чаще приводит к более длительным простоям, если вы регулярно обновляетесь в целях безопасности, а также для периодических обновлений версий базы данных, поскольку Discourse использует новые возможности PostgreSQL. Без анализа фактических данных у меня есть интуитивное ощущение, что есть смысл пересобирать систему 3–4 раза в год. Если такой объем простоя для вас приемлем, то нет особых причин усложнять задачу и переходить на развертывание с двумя контейнерами.

4 лайка

Это очень любезно с вашей стороны, но речь идёт о ваших мнениях. :wink:

Я тоже. За исключением моего дашборда, в контейнере которого находится множество дополнительных компонентов (например, Ansible, и я точно не помню, что ещё). Если кто-то выполняет обновление через dashboard.literatecomputing.com, а я затем уничтожаю этот контейнер, процесс восстановления прерывается, что может создать проблемы. Поэтому в последнее время я чаще использую docker_manager для обновлений, и они работают довольно гладко.

Не совсем так. В большинстве случаев, если появляется новое базовое изображение, docker_manager заставит вас его получить (по крайней мере, попытается).

Это примерно верно. К слову, я не рекомендую этого делать, но я общался с множеством людей, которые годами не выполняли никаких обновлений и не сталкивались с проблемами.

1 лайк

Да, сомнений нет — обновления внутри контейнера реализованы отлично!

Да, именно это я и имел в виду. :tada:

2 лайка

Привет снова, спасибо вам обоим за ваши комментарии. Я всё ещё пытаюсь решить, как настроить мою продакшн-среду. В теории я понимаю, почему установка с двумя контейнерами приводит к меньшему времени простоя. Но я всё ещё вижу практически нулевой простой при обновлении через графический интерфейс. Я только что засёк время: у меня было обновление docker-manager, и Discourse отставал на 22 коммита. Весь процесс занял менее 5 минут, и в течение всего этого времени форум был полностью работоспособен. Конечно, на этот раз обновлений PostgreSQL не было, но если бы потребовалось обновить и его, то даже с методом двух контейнеров я бы столкнулся с максимальным временем простоя, верно? Если я правильно понимаю, метод двух контейнеров сокращает время простоя только тогда, когда необходим вход по SSH и пересборка контейнера приложения из-за изменения конфигурации (добавление/удаление плагинов и т. д.)? Я не планирую частых изменений в конфигурации моей продакшн-среды, поэтому в моём случае не вижу потенциального сокращения времени простоя. Или мне также нужно заходить по SSH и пересобирать контейнеры для применения определённых видов обновлений функций или безопасности?

Это нормально.

Да, вы получаете полный простой каждый раз при обновлении PostgreSQL (раз в год или два, полагаю, плюс обновления безопасности самого PostgreSQL, хотя они не были особенно частыми).

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

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

Мне нравится быстро пересобирать контейнер приложения в своём обычном режиме для получения обновлений безопасности для контейнера приложения, когда они доступны, чтобы никогда не откладывать это на 10-минутный простой для пересборки всего. Поэтому git pull в лаунчере — это первая часть моего процесса применения каждого обновления; так, чтобы если базовый образ с такими вещами, как программы обработки изображений, был обновлён, эти изменения применялись без необходимости даже думать о том, есть ли обновления безопасности для применения. :smiling_face:

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

2 лайка

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

Хм, так это всё ещё актуально?

В любом случае, исходя из моего опыта работы с традиционными форумами, установленными без контейнеризации на стеке LAMP/LEMP, типичная уязвимость или вектор атаки, приводящие к реальному взлому веб-сайтов, почти всегда кроются в коде самого веб-приложения или в одном из его фреймворков для веб-разработки. Поэтому я склонен проявлять большую срочность в отношении обновлений кодовой базы Discourse, которые, как кажется, обрабатываются через GUI, так что, думаю, я склоняюсь к этому варианту.


Кстати, касательно простоя: небольшая реклама Clear Linux. Я начал его тестировать из-за его низкоуровневых оптимизаций для чистой числовой обработки, чтобы попытаться сократить время моего огромного процесса импорта форума на несколько часов. Возможно, в этом конкретном случае действительно есть прирост скорости, но в целом, о боже, он безумно быстр при перезагрузке, особенно как гость KVM. На самом дешёвом тарифе VPS я могу перезагрузить систему и снова войти по SSH буквально за 5 секунд. Так что я с нетерпением жду возможности использовать его, когда потребуются важные обновления хостовой ОС.

Да. Но несколько раз в год вам приходится выполнять пересборку через командную строку, поскольку какой-то компонент в контейнере был обновлён. И тогда у вас будет 5–15 минут простоя. Я почти всегда выполняю обновления через командную строку (за исключением моей панели управления, где я могу обновлять плагин панели несколько раз в день), и у меня есть несколько клиентов, для которых я делаю такие обновления через командную строку, когда это необходимо (предположительно, они обновляют через веб-интерфейс, но часто этого не делают).

2 лайка

Уведомляет ли панель управления Discourse конкретно о необходимости таких обновлений? Или мне следует следить за PSAs от Debian?