Миграция с хостинга на самохостинг: предыдущие загрузки по-прежнему ссылаются на инфраструктуру Discourse

Проверено: Images lost when migrating to self-hosting, команда posts:rebake не даёт положительного результата.

Проблема
Мы следовали официальным инструкциям и создали экземпляр Lightsail. Оттуда мы сделали выгрузку базы данных через интерфейс Discourse и применили её, чтобы достичь 80% готовности. Идея заключалась в переходе на собственный хостинг при сохранении работающей предыдущей версии.

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

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

Я наблюдаю три поведения, связанных с этим моментом времени:

  1. Ссылки на ресурсы в резервной копии (дамп SQL) указывают на инфраструктуру Discourse.
  2. Ссылки на ресурсы, созданные после создания резервной копии (например, изображения в новых постах), корректно указывают на нашу инфраструктуру и находятся там.

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

Текущее состояние
Насколько я понимаю, путь upload://<X> проходит декодирование b62 (и, возможно, sha1) для сопоставления с папкой public/uploads. У нас есть все эти изображения:

Дамп, предоставленный командой Discourse, содержит zip-архив с папкой default/original/1X, и в настоящее время он виден в /var/www/discourse/public/uploads/default/original/1X. Последняя папка теперь содержит 329 элементов, а в предоставленном дампе было 249 элементов — это кажется мне правильным.

Это означает, что данные должны быть доступны, даже если я не могу напрямую найти конкретную загрузку в папке. Я пытаюсь понять эту связь, чтобы каким-то образом исправить сопоставление. Изначально это казалось простой заменой строки, и это сработало для некоторых изображений. Однако некоторые из них теперь заменены на прозрачный transparent.png, тогда как раньше это были просто недоступные изображения.

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

Спасибо, Ричард!

Для уточнения, по ссылке: Replace a string in all posts

Используя

rake posts:remap["find","replace","string",true]

выполните

rake posts:remap[
  "https://cdck-file-uploads-europe1.s3.dualstack.eu-west-1.amazonaws.com/standard21/uploads/everviz/",
  "/uploads/default/"
]

Альтернативой замене на относительную ссылку было бы использование "https://forum.everviz.com/uploads/default/"

Имеете ли вы в виду относительную ссылку?

e: исправление относительного URL с /

Однострочная команда:

rake posts:remap["https://cdck-file-uploads-europe1.s3.dualstack.eu-west-1.amazonaws.com/standard21/uploads/everviz/", "/uploads/default/"]

выглядит хорошо! вам нужно добавить слэш перед

/uploads/default/

Вы выбрали опцию «Включить все загрузки» при создании резервной копии с вашего хостинга? Если вы размещались на CDCK, у них ранее была скрытая настройка, которую необходимо было включить, чтобы вы могли создать резервную копию со всеми загруженными файлами. Не уверен, изменилось ли это сейчас, но вам обязательно нужно согласовать действия с вашим хостинг-провайдером перед переездом, чтобы убедиться, что вы создаете полную резервную копию (а не просто дамп SQL).

Мой хостинг-провайдер — Discourse, мы были на месячном плане. В интерфейсе хостинга указано обращаться в team@discourse.com для получения загруженных файлов. В ответ они сообщили, что мне нужно отменить подписку, чтобы получить файлы.

Но да, как уже упоминалось, я получил uploads/original/1X.

Хороший совет, но я, возможно, уже сделал это:

root@...:/var/www/discourse$ rake posts:remap["//cdck-file-uploads-europe1.s3.dualstack.eu-west-1.amazonaws.com/standard21/uploads/everviz/","/uploads/default/"]
Вы уверены, что хотите заменить все вхождения строки '//cdck-file-uploads-europe1.s3.dualstack.eu-west-1.amazonaws.com/standard21/uploads/everviz/' на '/uploads/default/'? (Y/n)
Y
Переназначение
0 постов переназначено!

Ссылки в размещённом форуме ранее выглядели так: https://europe1.discourse-cdn.com/standard21/uploads/everviz/. Это, конечно, те же данные, только проходящие через CDN. Давайте попробуем переназначить.

1 пост переназначен.

Мне кажется любопытным это изображение:

Конечно, это было до выполнения всех этих команд сегодня и до публикации здесь. Я отправил это команде Discourse до запуска некоторых задач rake и подобных операций.

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

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

Я отменил операцию и получил файлы. Хотя, похоже, исходная резервная копия базы данных Discourse ссылается на путь в S3. По сути, у меня есть всё необходимое в /var/www/discourse/uploads/original/1X.

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

Для наглядности:


![](upload://3Qa5S9sUTcc42dT4EFAbz5K0iJP.gif) = 1aec065017da50538fe5866ae91a6396185234e1.gif

https://forum.everviz.com/uploads/default/original/1X/1aec065017da50538fe5866ae91a6396185234e1.gif

http://cdck-file-uploads-europe1.s3.dualstack.eu-west-1.amazonaws.com/standard21/uploads/everviz/original/1X/1aec065017da50538fe5866ae91a6396185234e1.gif

<img src="https://forum.everviz.com/images/transparent.png" alt="" data-orig-src="upload://3Qa5S9sUTcc42dT4EFAbz5K0iJP.gif" role="presentation" width="1" height="1" style="aspect-ratio: 1 / 1;" loading="lazy">

Выше приведён особый случай, где предыдущая ссылка на cdck… указывает просто на transparent.png. В любом случае, вы можете открыть ссылку и убедиться, что файл существует.

Так что, вероятно, у меня возникнут проблемы.

В том, что я предполагаю, является raw-постом, который вы включили, с базой данных из поставляемых файлов, я ожидаю, что ![](upload://3Qa5S9sUTcc42dT4EFAbz5K0iJP.gif) будет ссылаться на ваше локальное хранилище. Однако, если кто-то явно вставил ссылку на изображение из своего хранилища, потребуется какое-то действие для исправления этого. Если изображение существует и у вас включена настройка «скачивать в локальное хранилище», то изображение из хранилища будет загружено (при условии, что оно соответствует критериям настроек).

Я не совсем понимаю, как мог быть сгенерирован последний тег <img в вашем примере.

Загрузка на локальное устройство включена.

Для связанного файла «официальный» дамп прощания не включает относительные пути.

<img src="https://europe1.discourse-cdn.com/standard21/uploads/everviz/original/1X/1aec065017da50538fe5866ae91a6396185234e1.gif" alt="" data-base62-sha1="3Qa5S9sUTcc42dT4EFAbz5K0iJP" ...

Эта же ссылка на файл в некоторых местах указывает на cdck…

Мне это звучит немного безумно, но я могу сейчас сделать резервную копию. Затем удалить из самого файла дампа ссылки на инфраструктуру Discourse для локального пути и снова загрузить его.

Последний файл может ссылаться на transparent.png, потому что я переработал сообщение, и исходный файл больше не был обнаружен в инфраструктуре Discourse. Я не думаю, что мы имеем дело с полной потерей данных.

Если ваш сайт работает в режиме онлайн, вы просто зайдёте и исправите проблемы в Rails, насколько это возможно.

Но этот тег <img — это обработанный пост, верно? Не сырой пост?

Изображение взято из дампа базы данных. Предполагаю, что оно уже обработано. В исходном посте ссылка на b62 имеет вид upload://

Текущая обработанная версия:

<img src="https://forum.everviz.com/images/transparent.png" alt="" data-orig-src="upload://3Qa5S9sUTcc42dT4EFAbz5K0iJP.gif" ...

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

Спасибо, Джей, за всю вашу помощь!

Файл, на который ссылается обработанный пост, работает. С этим проблем нет.

Если вы ищете информацию в обработанных постах внутри дамп базы данных, то вы смотрите не туда.

У вас сейчас работает живой сайт, поэтому нужно работать с ним.

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

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

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

<img src="https://forum.everviz.com/images/transparent.png"
alt="image" data-orig-src="upload://npqpp5O0wbL89nR9OXtP7Btu4hc.png"
width="517" height="90" style="aspect-ratio: 517 / 90;" loading="lazy">

Давайте вычислим b62 и получим его в шестнадцатеричном виде

npqpp5O0wbL89nR9OXtP7Btu4hc = 0x a411c90267cafca7a1cbcd7c8f4f9b8db17e51ba

Теперь попробуйте найти его с помощью find в директории /var/www/discourse/public/uploads:

find . -name '*a411c90267cafca7a1cbcd7c8f4f9b8db17e51ba*'
./default/original/1X/a411c90267cafca7a1cbcd7c8f4f9b8db17e51ba.png

Да!


Но почему в посте это transparent.png? Я выполнил rake uploads:recover_from_tombstone и rake posts:rebake


Как я оказался в этой ситуации?

Колонка uploads в базе данных для таблицы url всё ещё показывала cdck как часть исходного URL для изображений. Я подключился к базе данных изнутри контейнера:

postgres psql discourse

Затем выполнил:

UPDATE uploads
SET url = REPLACE(
           url, 
           '//cdck-file-uploads-europe1.s3.dualstack.eu-west-1.amazonaws.com/standard21/uploads/everviz/', 
           '/uploads/default/'
         )
WHERE url LIKE '//cdck-file-uploads-europe1.s3.dualstack.eu-west-1.amazonaws.com/standard21/uploads/everviz/%';

Это дало многообещающие результаты: большинство оригинальных изображений и миниатюр снова появились.

Ещё один шаг: модификация дамп-файлов

Предположение состоит в том, что Discourse не имеет состояния*, и единственное, о чём нам нужно заботиться, — это то, что находится внутри базы данных. Я не хотел возиться с задачами rake или Ruby, так как не очень хорошо знаком ни с ними, ни с внутренним устройством Discourse. Мне нужны были быстрые результаты.

кроме папки public, содержащей наши изображения. Тем не менее мы можем подтвердить, что у нас есть всё необходимое.

Итак, мы скачали копию базы данных через интерфейс, открыли её в VSCode и последовательно заменили ссылки на cdck (бакет) и europe1 (бакет из CDN).

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

Затем мы загрузили модифицированный дамп-файл обратно. Часть того, что делало всё это сложным, — это шаг base62, который немного усложняет переход от сырого представления к реальному URL изображения.

Задача выполнена

После повторной проверки размера таблицы uploads я обнаружил, что у нас отсутствует несколько сотен записей. Не знаю, на каком этапе они были утеряны. Я объединил резервную копию базы данных с предыдущей версией с помощью простого SQL-join по временной таблице.

Как я, возможно, упоминал выше, URL-адрес, запрашиваемый для изображения, берётся из столбца url таблицы uploads. Из консоли Rails я перенастроил эти ссылки на CDN на наш локальный домен с помощью SQL-запросов к таблице uploads.

Почему не использовать rake-задачу

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

Хочу поблагодарить команду Discourse и волонтёров здесь, которые предоставили мне всю необходимую информацию для поиска решения, которое в итоге состояло из нескольких шагов.