Не удалось настроить бакет S3

Привет,

Я пытаюсь настроить загрузку в S3, и кажется, что загрузка работает корректно, но GET-запросы по какой-то странной причине не работают. Похоже, что Discourse добавляет «.cn» к URI загруженного объекта.

После загрузки изображения в мой бакет S3 публичный URL выглядит так:

https://hobig...bucket-eu.s3.eu-central-1.amazonaws.com/original/1X/5e894113...48918.jpeg

но при проверке в браузере мой форум Discourse пытается загрузить (обратите внимание на .cn):

https://hobig...bucket-eu.s3.eu-central-1.amazonaws.com.cn/original/1X/5e894113...48918.jpeg

Не знает ли кто-нибудь, почему это происходит?

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

Вы должны следовать инструкциям в разделе Настройка провайдера объектного хранилища, совместимого с S3, для загрузки файлов и/или Set up file and image uploads to S3, и внести эти настройки в ваш файл yml, а не в базу данных или интерфейс пользователя.

Вам не нужно настраивать конечную точку для AWS. Однако вам следует настроить CDN.

Привет, @pfaffman,

Кажется, вы случайно вставили одну и ту же инструкцию дважды.

Когда вы упоминаете «настройки в вашем файле yml», не могли бы вы уточнить, о каком именно YAML-файле идёт речь? Возможно, вы имеете в виду файл app.yml, расположенный в папке /var/discourse/containers?

Кроме того, если я настрою интеграцию с S3/CloudFront напрямую через YAML-файл, будут ли эти настройки переопределять те, что указаны в разделе администрирования Discourse?

Спасибо!

Извините. Одна из них должна была быть Set up file and image uploads to S3.

Смотрите связанные темы, где описывается настройка S3, но да, именно app.yml нужно изменить (так как вы не упоминали web_only.yml).

Да. Ввод этих настроек в YML-файл скрывает их из пользовательского интерфейса.

Привет, @pfaffman,

У меня настроено хранилище S3 и CloudFront, при этом источник (origin) CloudFront указывает на мой бакет S3. Вот моя текущая конфигурация app.yml:

ENV:
  DISCOURSE_USE_S3: true
  DISCOURSE_S3_REGION: eu-central-1
  DISCOURSE_S3_ACCESS_KEY_ID: AKIAWPLPUxxxxxx
  DISCOURSE_S3_SECRET_ACCESS_KEY: PaXQu7pKxxxx
  DISCOURSE_S3_CDN_URL: https://dsuxxxhrz2qn.cloudfront.net
  DISCOURSE_S3_BUCKET: hobigxxxxbucket-eu

После пересборки приложения командой ./launcher rebuild app при посещении сайта отображается только загрузчик, и ничего не загружается. При проверке вкладки Network в инструментах разработчика я обнаружил, что не могут быть получены предварительно скомпилированные статические ресурсы (в основном .js-файлы). Я предполагаю, что это связано с тем, что их нет в моём бакете S3. Вы можете проверить это здесь: forum.hobiguru.com.

Я также попытался запустить задачу миграции rake, но безрезультатно:

root@ubuntu-s-1vcpu-1gb-fra1-01-app:/var/www/discourse# rake uploads:migrate_to_s3 --trace



** Invoke uploads:migrate_to_s3 (first_time)
** Invoke environment (first_time)
** Execute environment



** Execute uploads:migrate_to_s3
Обратите внимание: миграция на S3 в настоящее время необратима!
[CTRL+c] для отмены, [ENTER] для продолжения
Миграция загрузок в S3 для 'default'...
Некоторые загрузки не были перенесены в новую схему. Запускаю миграцию, это может занять некоторое время...
rake aborted!
FileStore::ToS3MigrationError: Некоторые загрузки не удалось перенести в новую схему. Вам необходимо исправить это вручную. (FileStore::ToS3MigrationError)
/var/www/discourse/lib/file_store/to_s3_migration.rb:156:in `migrate_to_s3'
/var/www/discourse/lib/file_store/to_s3_migration.rb:59:in `migrate'
/var/www/discourse/lib/tasks/uploads.rake:126:in `migrate_to_s3'
/var/www/discourse/lib/tasks/uploads.rake:106:in `block in migrate_to_s3_all_sites'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rails_multisite-6.1.0/lib/rails_multisite/connection_management/null_instance.rb:49:in `with_connection'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rails_multisite-6.1.0/lib/rails_multisite/connection_management/null_instance.rb:36:in `each_connection'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rails_multisite-6.1.0/lib/rails_multisite/connection_management.rb:21:in `each_connection'
/var/www/discourse/lib/tasks/uploads.rake:104:in `migrate_to_s3_all_sites'
/var/www/discourse/lib/tasks/uploads.rake:100:in `block in <main>'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/task.rb:281:in `block in execute'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/task.rb:281:in `each'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/task.rb:281:in `execute'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/task.rb:219:in `block in invoke_with_call_chain'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/task.rb:199:in `synchronize'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/task.rb:199:in `invoke_with_call_chain'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/task.rb:188:in `invoke'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/application.rb:188:in `invoke_task'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/application.rb:138:in `block (2 levels) in top_level'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/application.rb:138:in `each'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/application.rb:138:in `block in top_level'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/application.rb:147:in `run_with_threads'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/application.rb:132:in `top_level'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/application.rb:83:in `block in run'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/application.rb:214:in `standard_exception_handling'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/application.rb:80:in `run'
bin/rake:13:in `<top (required)>'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.18/lib/bundler/cli/exec.rb:58:in `load'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.18/lib/bundler/cli/exec.rb:58:in `kernel_load'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.18/lib/bundler/cli/exec.rb:23:in `run'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.18/lib/bundler/cli.rb:455:in `exec'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.18/lib/bundler/vendor/thor/lib/thor/command.rb:28:in `run'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.18/lib/bundler/vendor/thor/lib/thor/invocation.rb:127:in `invoke_command'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.18/lib/bundler/vendor/thor/lib/thor.rb:527:in `dispatch'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.18/lib/bundler/cli.rb:35:in `dispatch'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.18/lib/bundler/vendor/thor/lib/thor/base.rb:584:in `start'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.18/lib/bundler/cli.rb:29:in `start'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.18/exe/bundle:28:in `block in <top (required)>'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.18/lib/bundler/friendly_errors.rb:117:in `with_friendly_errors'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.18/exe/bundle:20:in `<top (required)>'
/usr/local/bin/bundle:25:in `load'

Моя первоначальная цель заключалась в использовании S3 только для хранения пользовательских загрузок, и я добавил CDN исключительно для этих целей. Однако теперь я столкнулся с новой проблемой — статические ресурсы самого приложения также раздают через CDN, чего я не планировал. :confused:

Есть ли способ загружать все статические ресурсы в бакет S3 при запуске приложения, а затем раздавать их через CDN? Или, возможно, есть способ раздавать через CDN только загрузки пользователей? Или есть какое-то лучшее решение?

Возможно, я что-то очевидное упустил? Не знаю.
Спасибо за помощь!

Я подозреваю, что это потому, что вы не последовали инструкциям.

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

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

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

Тем не менее, загрузка файлов пользователями всё ещё работает некорректно. После загрузки в бакет S3 (правильно) изображение обслуживается по адресу:

//my-bucket-eu.my-bucket-eu/original/1X/7f242572bdb45b65ded727c13366fe490541358f.jpeg
что, разумеется, не является корректным путём к S3 или CDN.

В руководстве, на которое вы ссылаетесь, есть раздел, который кажется актуальным:

DISCOURSE_CDN_URL — это CDN, указывающий на ваш хост Discourse и кэширующий запросы. Он будет использоваться в основном для «pullable» ресурсов: CSS и других тематических ресурсов.

DISCOURSE_S3_CDN_URL — это CDN, указывающий на ваш бакет объектного хранилища и кэширующий запросы. Он будет использоваться в основном для «pushable» ресурсов: JS, изображений и загрузок пользователей.

Мы рекомендуем, чтобы эти значения были разными, и администраторам следует настроить оба параметра.

Однако я не уверен, что установить в качестве DISCOURSE_CDN_URL. Должен ли я задать то же значение, что и DISCOURSE_S3_CDN_URL: https://dsxxxxx2qn.cloudfront.net, или нужно создать отдельный экземпляр CDN?

Хотя, возможно, проблема совершенно в другом :confused:

Большое спасибо за всю помощь!

Вам нужно настроить CDN и привязать его к нужному домену на стороне AWS. Также это требуется в DNS.

Но зачем? На практике эту URL-адрес почти никто не видит.

Привет, Джейк, я не совсем уверен, что правильно понял, что ты имеешь в виду. Не мог бы ты немного подробнее объяснить?

Возможно, ты имел в виду, что вместо того, чтобы указывать S3-бакет в качестве источника для CDN, мне следует указать домен forum.hobiguru.com? Если это так, то я не думаю, что это что-то изменит, поскольку именно форум Discourse генерирует эти URL-адреса, ведущие в никуда, например: //my-bucket-eu.my-bucket-eu/original/1X/7f242572bdb45b65ded727c13366fe490541358f.jpeg.

Я добавил также переменную DISCOURSE_CDN_URL: https://dsuxxxhrz2qn.cloudfront.net, и теперь жду, пока приложение пересоберётся :crossed_fingers:

ОБНОВЛЕНИЕ: нет, это тоже не сработало :confused:

Я очень ценю твою помощь.
Спасибо

Вы не можете просто назвать поддомен только в app.yml. Никто не сможет его использовать без правильной DNS-информации. И поскольку ваши файлы обслуживаются через AWS, вам также нужно настроить эту сторону, если вы хотите использовать CDN.

Но, опять же. Пользователи видят URL-адрес Discourse, если они хотят его увидеть. Очень редко кто-то, кроме администратора, что-то делает. И пользователи практически никогда не видят URL-адреса медиафайлов или других статических файлов.

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

Я живу в Финляндии. Я не получаю никакой реальной выгоды, если сайт на другой стороне света, в Австралии, использует CDN (с сервера, расположенного в 1000 км от меня). Настоящее узкое место возникает из-за того, как построен этот сайт, например, если используется много ненужных PHP-вызовов без достаточных ресурсов.

Но в целом вы не можете использовать URL-адрес cdn.example.tld, не добавив cdn хотя бы в DNS.

Привет, @Jagster,

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

Моя проблема возникла, когда я попытался настроить S3 (специфически для обслуживания ассетов, а не загрузок), и @pfaffman предложил мне следовать руководству Настройка провайдера объектного хранилища, совместимого с S3, для загрузок и настроить CDN.

Что касается вашего комментария:

«Вы просто не можете указать только поддомен в app.yml. Никто не сможет его использовать без правильной DNS-информации. И поскольку файлы обслуживаются из AWS, вам также нужно настроить эту сторону, если вы хотите использовать CDN».

Извините, но я не совсем понял, что вы имели в виду в этом абзаце. Не могли бы вы немного подробнее объяснить или прояснить? Вы имеете в виду, что мне нужно настроить DNS-записи для моего бакета S3, или что-то конкретное нужно изменить на стороне AWS?

Заранее спасибо за помощь!

Всем привет,

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

Что работает сейчас

  • Загрузки пользователей корректно обслуживаются из моего S3-бакета через CDN (CloudFront), так что это отлично!

Однако у меня всё ещё есть проблема с предварительно скомпилированными ассетами

Предварительно скомпилированные ассеты по-прежнему не обслуживаются корректно через CDN.

Когда я устанавливаю DISCOURSE_CDN_URL на URL CloudFront (то есть https://dsuqioxhrz2qn.cloudfront.net), URL-адреса предварительно скомпилированных ассетов становятся следующими:

•	https://dsuqioxhrz2qn.cloudfront.net/stylesheets/color_definitions_shades-of-blue_7_1_e6f11758f9c015d1e5ed9b08c437e9c5c267c932.css?__ws=forum.hobiguru.com
•	https://dsuqioxhrz2qn.cloudfront.net/stylesheets/discourse-presence_308d905aa5c03567866fec50e9a28d8721ab0463.css

Проблема в том, что эти пути не существуют в моём S3-бакете. Предварительно скомпилированные ассеты загружаются в папку /assets/* в S3 (например, /assets/locales, /assets/plugins, /assets/scripts), но папки /stylesheets/ там нет, и, конечно, попытки загрузить эти URL приводят к ошибке 403 Forbidden.

Однако, если я изменю DISCOURSE_CDN_URL на https://forum.hobiguru.com, мой форум будет работать корректно, но ассеты теперь будут обслуживаться с сервера (например, https://forum.hobiguru.com/), а не через CDN (например, https://forum.hobiguru.com/stylesheets/admin_308d905aa5c03567866fec50e9a28d8721ab0463.css?__ws=forum.hobiguru.com).

Моя текущая конфигурация (для контекста):

app.yaml

DISCOURSE_USE_S3: true
DISCOURSE_S3_REGION: eu-central-1
DISCOURSE_S3_ACCESS_KEY_ID: AKIA......LQMB
DISCOURSE_S3_SECRET_ACCESS_KEY: PaXQu7pKN.....fJNY
DISCOURSE_S3_CDN_URL: https://dsuqioxhrz2qn.cloudfront.net  # Убедитесь, что URL CDN указывает на CloudFront
DISCOURSE_CDN_URL: https://forum.hobigur.com # ОБРАТИТЕ НА ЭТО ВНИМАНИЕ!
DISCOURSE_S3_BUCKET: hobiguru-s3-bucket-eu

и хуки компиляции:

hooks:
  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

Кажется, что после компиляции ассеты загружаются в S3 в определённую структуру, но при загрузке через CDN пути к объектам немного не совпадают.