Форум стал неработоспособным

Привет! Я пытаюсь включить резервное копирование S3 на сервер Min.IO. Когда я изменяю файл app.yml так, как, по моему мнению, это описано в документации, и затем выполняю пересборку, в браузере после завершения отображаются только четыре цветные точки в центре экрана. В консоли я вижу следующее:

Uncaught ReferenceError: I18n is not defined
    at admin?v=103a67b2358b…86c5a58d96d4e91:1:1
wizard?v=ab2295f1774…85b733472935c34a0:1 
Uncaught ReferenceError: I18n is not defined
    at wizard?v=ab2295f1774…b733472935c34a0:1:1

Мои изменения в файле app.yml следующие:

  DISCOURSE_BACKUP_LOCATION: 's3'
  DISCOURSE_USE_S3: 'true'
  DISCOURSE_S3_REGION: 'off-cloud-backup'
  DISCOURSE_S3_ENDPOINT: 'http://borg....'
  DISCOURSE_S3_ACCESS_KEY_ID: '(my uid here)'
  DISCOURSE_S3_SECRET_ACCESS_KEY: '(my key here)'
  DISCOURSE_S3_CDN_URL: 'http://borg....'
  DISCOURSE_S3_BUCKET: 'assets'
  DISCOURSE_S3_BACKUP_BUCKET: 'discourse-data'
  DISCOURSE_S3_INSTALL_CORS_RULE: 'false'

На сервере Min я настроил регион, затем создал публичный бакет с именем ‘assets’ и приватный бакет с именем ‘discourse-data’, а также соответствующие учётные данные. Я пробовал убирать кавычки вокруг переменных, так как в некоторых примерах это сделано, но изменений не последовало.

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

Если я закомментирую все записи с суффиксом _S3 в файле app.yml и выполню пересборку, всё работает нормально. (Просто резервное копирование не настроено). (Адреса ENDPOINT и CDN локально разрешаются в правильный IP-адрес).

Настройка всего остального, включая подписки, прошла относительно легко, но здесь я уперся в тупик. У кого-нибудь есть идеи, что я делаю не так?

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

У вас настроено сохранение всех ассетов в S3, но, скорее всего, вы упустили часть в начале инструкции, где описаны rake-задачи для предварительной компиляции ассетов и их загрузки в S3.

Привет, спасибо! Сейчас попробую два варианта:

  • Пересобрать с переменными ACCESS, SECRET и BACKUP_BUCKET (и, полагаю, endpoint?)
  • Попробовать добавить rake-задачи и пересобрать

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

Тем не менее, моё (очень слабое) понимание документации, из-за которого сайт кажется фактически нерабочим, может стать проблемой для новичков. Не совсем понятно, почему консоль сообщает об ошибке I18n, но, похоже, небольшое изменение в коде, вроде

if (I18n && I18n.xxx)

вместо

if (I18n.xxx)

помогло бы защитить новичков от поломки их сайтов. Стоит ли мне поискать и попробовать создать pull request, или этим должен заняться кто-то более опытный? Готов попробовать, но не хочу тратить время, если это не нужно…?

Мм, ладно, немного продвинулся: упрощённые настройки теперь позволяют странице отобразиться, однако от сервера приходит ответ «неверный запрос». Я тестирую хранилище S3 с машины Discourse с помощью утилиты «mc» от Min.io, и всё работает нормально, я могу перечислять бакеты… однако в логах вижу следующее:

Не удалось получить список резервных копий из S3: Aws::S3::Errors::BadRequest

И

/var/www/discourse/lib/backup_restore/s3_backup_store.rb:140:in `rescue in unsorted_files' 
/var/www/discourse/lib/backup_restore/s3_backup_store.rb:131:in `unsorted_files' 
/var/www/discourse/lib/backup_restore/backup_store.rb:23:in `files' 

Я специально скопировал настройки из app.yml в конфиг «mc», чтобы убедиться, что нет опечаток… поэтому сейчас немного растерян. Попробую ещё раз завтра…

Оно пытается перечислить содержимое бакета.

Вам не нужна задача Rake, связанная с активами.

Оно пытается перечислить содержимое ведра.
Вам не нужна задача rake, связанная с ресурсами.

Хорошо, спасибо за помощь. Я это заметил, но это не очень помогает. Я пробовал Min.io и SeaweedFS, оба настроил локально так, что мог записывать файлы в S3 с помощью инструмента командной строки с машины Discourse, но ни один из вариантов не хочет работать внутри Discourse. После анализа затраченного времени я полагаю, что если резервные копии хранятся онлайн в S3, то вариант прямого резервного копирования в S3 действительно удобен. Однако, если ваши резервные копии находятся «вне облака» и вам нужно эмулировать хранилище S3 только для использования этой опции, для меня это становится слишком затратным по времени.

Кстати, я заметил, что кто-то упомянул, что теперь работает CloudFlare S3, что может подойти некоторым пользователям. CloudFlare, похоже, добавила 10 ГБ S3 в свой бесплатный тариф, но для меня мои резервные копии обычно хранятся вне облака на сервере резервного копирования Borg.

Вместо этого я добавил хост-машину Discourse в свою VPN для резервного копирования, установил borg и borgmatic для резервного копирования каталогов /var/discourse/shared/standalone/backups и /var/discourse/shared/standalone/log на хосте, а затем добавил это в cron через 30 минут после запланированного локального резервного копирования.

Вопрос: Можете ли вы уточнить, покрывают ли локальные резервные копии всё необходимое, или мне нужно добавить что-то ещё для резервного копирования загруженных файлов? (Необходимы ли дополнительные задачи rake только для S3?)

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

Вы следовали специфичным для MinIO инструкциям здесь? Configure an S3 compatible object storage provider for uploads

Если вы просто меняете эти переменные окружения, то можно выполнить

  ./launcher destroy app; ./launcher start app

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

Вы следовали инструкциям, специфичным для MinIO, приведённым здесь?

Да, я следовал. Я с готовностью признаю, что мог допустить ошибки или не всё запомнить, но поиск соответствующей документации в Google — точно не одна из них.. :wink:

./launcher destroy app; ./launcher start app

Хорошо, это полезно для будущих ссылок. Я пытался выполнить остановку и запуск, а не был знаком с тем, как Docker создаёт переменные окружения при загрузке.

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

Конечно, это тот момент, который вызвал у меня небольшую путаницу. Я добавлю их. Просто задавался вопросом, почему эти файлы не включены в резервную копию по умолчанию. Я знаю, что есть проблема с местом, но моё ожидание состояло в том, что в целом людям нужна резервная копия всего их контента? (И поскольку большинство людей, похоже, не проверяют содержимое, возможно, безопаснее перестраховаться и включить всё?)

Хм, я сначала попробовал это на своём тестовом экземпляре (!) .. Я скопировал и вставил две строки из документации .. Неужели где-то что-то устарело?

I, [2023-09-04T18:39:51.544973 #1]  INFO -- : > cd /var/www/discourse/plugins && sudo -E -u discourse bundle exec rake s3:upload_assets
bundler: failed to load command: rake (/var/www/discourse/vendor/bundle/ruby/3.2.0/bin/rake)
/var/www/discourse/vendor/bundle/ruby/3.2.0/gems/bundler-2.4.13/lib/bundler/definition.rb:524:in `materialize': Could not find css_parser-1.16.0, oj-3.16.1, rotp-6.3.0, globalid-1.2.0, google-protobuf-3.24.2-x86_64-linux in locally installed gems (Bundler::GemNotFound)
        from /var/www/discourse/vendor/bundle/ruby/3.2.0/gems/bundler-2.4.13/lib/bundler/definition.rb:197:in `specs'
        from /var/www/discourse/vendor/bundle/ruby/3.2.0/gems/bundler-2.4.13/lib/bundler/definition.rb:254:in `specs_for'
        from /var/www/discourse/vendor/bundle/ruby/3.2.0/gems/bundler-2.4.13/lib/bundler/runtime.rb:18:in `setup'
        from /var/www/discourse/vendor/bundle/ruby/3.2.0/gems/bundler-2.4.13/lib/bundler.rb:162:in `setup'
        from /var/www/discourse/vendor/bundle/ruby/3.2.0/gems/bundler-2.4.13/lib/bundler/setup.rb:23:in `block in <top (required)>'
        from /var/www/discourse/vendor/bundle/ruby/3.2.0/gems/bundler-2.4.13/lib/bundler/ui/shell.rb:159:in `with_level'
        from /var/www/discourse/vendor/bundle/ruby/3.2.0/gems/bundler-2.4.13/lib/bundler/ui/shell.rb:111:in `silence'
        from /var/www/discourse/vendor/bundle/ruby/3.2.0/gems/bundler-2.4.13/lib/bundler/setup.rb:23:in `<top (required)>'
        from /var/www/discourse/vendor/bundle/ruby/3.2.0/gems/bundler-2.4.13/lib/bundler/cli/exec.rb:56:in `require_relative'
        from /var/www/discourse/vendor/bundle/ruby/3.2.0/gems/bundler-2.4.13/lib/bundler/cli/exec.rb:56:in `kernel_load'
        from /var/www/discourse/vendor/bundle/ruby/3.2.0/gems/bundler-2.4.13/lib/bundler/cli/exec.rb:23:in `run'
        from /var/www/discourse/vendor/bundle/ruby/3.2.0/gems/bundler-2.4.13/lib/bundler/cli.rb:492:in `exec'
        from /var/www/discourse/vendor/bundle/ruby/3.2.0/gems/bundler-2.4.13/lib/bundler/vendor/thor/lib/thor/command.rb:27:in `run'
        from /var/www/discourse/vendor/bundle/ruby/3.2.0/gems/bundler-2.4.13/lib/bundler/vendor/thor/lib/thor/invocation.rb:127:in `invoke_command'
        from /var/www/discourse/vendor/bundle/ruby/3.2.0/gems/bundler-2.4.13/lib/bundler/vendor/thor/lib/thor.rb:392:in `dispatch'
        from /var/www/discourse/vendor/bundle/ruby/3.2.0/gems/bundler-2.4.13/lib/bundler/cli.rb:34:in `dispatch'
        from /var/www/discourse/vendor/bundle/ruby/3.2.0/gems/bundler-2.4.13/lib/bundler/vendor/thor/lib/thor/base.rb:485:in `start'
        from /var/www/discourse/vendor/bundle/ruby/3.2.0/gems/bundler-2.4.13/lib/bundler/cli.rb:28:in `start'
        from /var/www/discourse/vendor/bundle/ruby/3.2.0/gems/bundler-2.4.13/exe/bundle:45:in `block in <top (required)>'
        from /var/www/discourse/vendor/bundle/ruby/3.2.0/gems/bundler-2.4.13/lib/bundler/friendly_errors.rb:117:in `with_friendly_errors'
        from /var/www/discourse/vendor/bundle/ruby/3.2.0/gems/bundler-2.4.13/exe/bundle:33:in `<top (required)>'
        from /usr/local/bin/bundle:25:in `load'
        from /usr/local/bin/bundle:25:in `<main>'
I, [2023-09-04T18:39:52.163459 #1]  INFO -- : 
I, [2023-09-04T18:39:52.164462 #1]  INFO -- : Terminating async processes

Мои хуки выглядят так;

hooks:
  after_code:
    - exec:
        cd: $home/plugins
        cmd:
          - sudo -E -u discourse bundle exec rake s3:upload_assets
          - sudo -E -u discourse bundle exec rake s3:expire_missing_assets
          - sudo -E -u discourse git clone https://github.com/discourse/docker_manager.git
          - sudo -E -u discourse git clone https://github.com/discourse/discourse-whos-online
          - sudo -E -u discourse git clone https://github.com/discourse/discourse-solved.git
          - sudo -E -u discourse git clone https://github.com/discourse/discourse-reactions.git
          - sudo -E -u discourse git clone https://github.com/discourse/discourse-subscriptions.git
          - sudo -E -u discourse git clone https://github.com/discourse/discourse-topic-voting.git
          - sudo -E -u discourse git clone https://github.com/discourse/discourse-calendar.git
          - sudo -E -u discourse git clone https://github.com/sylque/discourse-home-page.git
          - sudo -E -u discourse git clone https://github.com/sylque/discpage.git
          - sudo -E -u discourse git clone https://github.com/discourse/discourse-onboarding-banner.git

Эти задачи Rake не должны размещаться там.

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

Ммм, я ранее отмечал, что кто-то уже говорил о том, чтобы помещать вещи в неправильный раздел, а потом сам всё равно сделал то же самое, ой (!)

Так что, после более внимательного прочтения, у меня всё ещё кажется, что есть проблема. Вот что у меня есть:

hooks:
  after_code:
    - exec:
        cd: $home/plugins
        cmd:
          - git clone https://github.com/discourse/docker_manager.git
          - git clone https://github.com/discourse/discourse-whos-online
          - git clone https://github.com/discourse/discourse-solved.git
          - git clone https://github.com/discourse/discourse-reactions.git
          - git clone https://github.com/discourse/discourse-subscriptions.git
          - git clone https://github.com/discourse/discourse-topic-voting.git
          - git clone https://github.com/discourse/discourse-calendar.git
          - git clone https://github.com/sylque/discourse-home-page.git
          - git clone https://github.com/sylque/discpage.git
          - git clone https://github.com/discourse/discourse-onboarding-banner.git

  after_assets_precompile:
    - exec:
        cd: $home
        cmd:
          - sudo -E -u discourse bundle exec rake s3:upload_assets
          - sudo -E -u discourse bundle exec rake s3:expire_missing_assets

Там сказано вставить это в app.yml в раздел hooks… Выглядит ли это правильно или я всё ещё не там? Ошибка, которую я получаю сейчас, следующая:

FAILED
--------------------
Pups::ExecError: cd /var/www/discourse && sudo -E -u discourse bundle exec rake s3:upload_assets failed with return #<Process::Status: pid 1845 exit 1>
Location of failure: /usr/local/lib/ruby/gems/3.2.0/gems/pups-1.1.1/lib/pups/exec_command.rb:117:in `spawn'
exec failed with the params {"cd"=>"$home", "cmd"=>["sudo -E -u discourse bundle exec rake s3:upload_assets", "sudo -E -u discourse bundle exec rake s3:expire_missing_assets"]}
bootstrap failed with exit code 1

Я просматриваю логи в поисках дополнительных деталей, но ничего не вижу. К сожалению, я никогда не программировал на Ruby, поэтому не совсем понимаю, что передо мной и что искать. Есть какие-то идеи?

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