Смена s3-бакета для загрузки файлов

Привет!

Мы мигрируем все наши загрузки/изображения между двумя разными сервисами, совместимыми с S3 (оба — DigitalOcean Spaces, если это имеет значение), и я пришел к выводу, что мы застряли в довольно плачевном состоянии.

Начну с объяснения того, как проводилась миграция:

  1. Мы клонировали/синхронизировали исходный бакет в новый с помощью rclone.
  2. Все ссылки на странице «Files» в администрировании Discourse были обновлены на новые конечные точки.
  3. Был выполнен пересчет (re-bake).

К сожалению, это не дало желаемого результата, и теперь все изображения «исчезли» с форума. Они по-прежнему находятся в бакете S3 (и, к счастью, также в старом бакете), но ни один пост не может найти свое изображение.

Размер бакета составляет около 60 ГБ, что, хотя и не экстремально, является довольно большим объемом данных.

Я пересобрал контейнер, пытался восстановить данные из tombstone, сделал практически всё, что мог придумать или найти на форуме поддержки и в задачах rake.
Также я пробовал замену базы данных (через discourse remap).

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

<img src="https://xxxx.xxxxx.xx/images/transparent.png" alt="image" data-orig-src="upload://h8UudilPhVsGnNmvlJ5lQYEr8PT.jpeg" width="375" height="500">

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

Кто-нибудь уже сталкивался с этим? Все ли изображения потеряны навсегда? (Да-да, у меня есть резервная копия и старые изображения, так что я знаю, что выход есть).

Стоит упомянуть, что я также пытался использовать URI CDN, предоставленный для бакета Spaces (с повторной пересборкой).

Вывод для отсутствующих загрузок:

rake posts:missing_uploads
Поиск отсутствующих загрузок на: default
Исправление отсутствующих загрузок:
🚫
Отсутствуют загрузки для 17075 постов.

Отсутствует 16906 загрузок.
1 из 16906 — загрузка по старой схеме.
Затронуты 14646 из 139801 поста.

В таблице post_uploads 3448 записей
В таблице optimized_images 25681 запись
В таблице uploads 5764 записи

Вы можете посмотреть Moving from one S3 bucket to another

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

Это было бы очень полезно, большое спасибо!

Привет @Jite!

Посмотрите, подходит ли вам этот вариант. Если всё работает, я займусь созданием полноценного руководства howto.

Старые бакеты

Это предполагает, что вы можете установить и настроить инструмент для переноса данных из вашего старого бакета на локальную машину, а затем выполнить аналогичные действия с локальной машины в новый бакет. См. aws cli sync (который можно настроить для не-AWS бакетов) и gsutil rsync для получения информации. Если у вас огромный объём данных или вы переносите данные между бакетами одного провайдера, возможно, стоит изучить методы, позволяющие переносить данные напрямую между бакетами.

Перейдите в каталог, подходящий для временного хранения (например, mkdir temp-bucket; cd temp-bucket), прежде чем выполнять что-то вроде следующего. В этих примерах используются флаги -n и --dry-run, чтобы показать, что произойдёт. Если результат вас устраивает, запустите команду снова без этих флагов.

Перенос старых данных из старого бакета в локальное хранилище

    gsutil  rsync -r -n  gs://=OLD= .

или

    aws s3 sync s3://=OLD= .

Перенос данных из локального хранилища в новый бакет

    gsutil rsync -r -n . gs://=NEW=

или

    aws s3 sync . s3://=NEW=

Обновление базы данных для использования нового бакета

Эти команды выполняются в консоли Rails. Чтобы попасть туда, выполните:

cd /var/discourse
./launcher enter app
rails c

Для нового бакета загрузите изображение с новой конфигурацией и выполните:

Upload.last.url

Вы должны увидеть что-то вроде:

=> "//discourse-bucket.s3.dualstack.us-east-2.amazonaws.com/`original/2X/7/12345fbea574afc4e02db80107e6682430aede2c.png"

Затем получите discourse-bucket.s3.dualstack.us-east-2.amazonaws.com для нового бакета. Аналогичным образом получите имя хоста старого бакета из предыдущего вывода.

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

Upload.order(Arel.sql('RANDOM()')).limit(10).pluck(:id, :url)

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

DbHelper.remap("//=OLDHOST=/","//=NEWHOST=/")

Переход на AWS может потребовать очистки s3_endpoint.

ПРИМЕЧАНИЕ: Если у вас определён s3_endpoint в SiteSettings в базе данных и вы переходите на AWS (где endpoint не требуется), вам нужно очистить эту настройку сайта после сборки нового контейнера с обновлёнными настройками (или после восстановления базы данных, где она установлена).

Перепечка постов, ссылающихся на бакет, а не на S3 CDN

Если у вас есть посты, которые ссылаются напрямую на новый бакет S3 (возможно, у вас ранее не был определён s3_cdn_url), вот как перепечь только те посты, которые в этом нуждаются.

Получите посты:

  posts=Post.where("cooked like '%=NEWHOST=%'")

Посмотрите, сколько их:

  posts.count

Перепеките эти посты:

  posts.each do |p| p.rebake! end

Или просто замените бакет на CDN:

posts.each do |p|
  p.cooked.gsub!(/=NEWHOST=/,"=CDN=")
  p.save!
end

Спасибо за ответ.

В целом я делал то же самое в прошлый раз, но попробовал повторить это снова. Проблема в том, что posts.count возвращает 0. У всех постов файл transperent.png присутствует в обработанном (cooked) содержимом, а в необработанном (uncooked) содержится хэш.
Есть ли способ заставить систему корректно разрешать изображение во время обработки (bake)?

Хм. Верно. Это временное решение работает только для предотвращения пересборки. Если пересборка не удаётся, значит, что-то ещё не так. Возможно, ресурсы не там, где их ищет Discourse?

Ну, это возможно, но «перемещение» было практически точной копией всех файлов в бакете, хе-хе…

То есть вы можете заменить старый URL ведра на новый, и всё работает?

Правильно ли выглядят значения в разделе «Загрузки»?

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

После выполнения задачи rake toombstone recovery и затем задачи rake fix_missing_uploads, я наконец добился того, чтобы процесс начал «исправлять» изображения.
Кажется, что они скачиваются и загружаются заново, что занимает очень много времени и требует значительных ресурсов, но, по крайней мере, пользователи вернут свои изображения!

Спасибо за помощь @pfaffman :slight_smile: