从托管到自托管的迁移:过去的上传仍然引用 discourse 基础设施

已检查:https://meta.discourse.org/t/images-lost-when-migrating-to-self-hosting/52643,`posts:rebake` 没有任何效果。

问题
我们遵循了官方说明,创建了一个 Lightsail 实例,然后从 Discourse UI 下载了数据库,并应用了它,完成了 80% 的工作。我们的想法是在保持旧论坛正常运行的同时迁移到自托管实例。

一旦我们有了旧论坛的实时副本,我们就可以开始迁移图片。为此,我们首先取消订阅,然后迁移我们的图片。

当新图片上传到自托管实例时,我们只需要从迁移日期之前的托管实例上传。这意味着我们从未真正使用过我们图片和取消订阅附带的数据库转储;因为我们已经完成了迁移,所以它已经过期了。

我观察到与这个时间点相关的三种行为。

  1. 备份(特别是 SQL 转储)中引用的资源指向 Discourse 基础架构
  2. 备份中自创建以来引用的资源,例如新帖子的图片,已正确引用并在我们的基础架构上找到。

因此,如果我重新上传一个具有相同哈希值的资源,它将链接到 Discourse 基础架构。例如:尝试通过上传相同的图标来修复图标不起作用。但我可以上传任何其他随机图片,它会起作用。

当前状态
据我所知,upload://<X> 会经过 b62 解码(和 sha1?)位来映射到 public/uploads 文件夹。我们拥有所有这些图片:

Discourse 团队提供的转储包含一个带有 default/original/1X 的 zip 文件,它目前可以在 /var/www/discourse/public/uploads/default/original/1X 中看到。后者现在包含 329 个项目,而给定的转储包含 249 个项目——这对我来说听起来不错。

这意味着数据应该是可发现的,即使我无法直接在文件夹中找到上传的文件。我希望了解这种关系,以便以某种方式修复映射。最初,它似乎只是一个简单的字符串替换,这对某些图片有效。但现在有些图片已被替换为 transparent.png,而之前只是无法访问的图片。

如果重新烘焙失败,您应该尝试 remap 来搜索/替换对 Discourse 基础架构的所有引用,并用相对链接替换它们。

谢谢你,Richard!

为了澄清,通过: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
Remapping
0 posts remapped!

以前,托管论坛中的链接是 https://europe1.discourse-cdn.com/standard21/uploads/everviz/。这当然是相同的东西,只是通过 CDN 进行了限制。让我们尝试重新映射。

1 post remapped.

我觉得这张图片很奇怪:

当然,这是在运行今天完成的所有这些命令并在此处发帖之前。它在运行一些 rake 任务等之前被发送给了 Discourse 团队。

你这样做过吗?他们必须启用一个隐藏的设置,该设置会从 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> 是如何生成的。

本地下载已启用。

对于链接的文件,“官方”的 goodbye dump 不包含相对路径。

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

在某些地方,这个确切的文件引用也指向 cdck…

这听起来有点疯狂,但我现在可以做一个备份。然后,在 dumpfile 本身中丢弃对 Discourse 基础架构的本地路径的引用,并重新上传。

最后一个文件可能引用 transparent.png,因为我重新烹饪了帖子,并且源文件在 Discourse 基础架构中不再可发现。我不认为我们正在面临数据完全丢失。

如果您的网站已上线,那么您只需进入 Rails 中进行修复,只要有可能的话。

但是那个 <img 是一个已处理的帖子,对吧?不是原始帖子?

数据库转储包含此 <img>。我猜是已处理过的。原始帖子将 b62 引用为 upload://

当前已处理的为:

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

到目前为止,我使用 rake 来查找和修复缺失的上传、重新映射和重新烘焙帖子并不成功。

感谢 Jay 的所有帮助!

已渲染帖子中引用的文件可以正常工作。那没有问题。

如果你在数据库转储的已渲染帖子中查找,那么你就找错地方了。

你现在有一个在线站点,所以你需要从那里着手。

你在原始帖子中看到了什么?在重新烘焙该帖子后,已渲染帖子显示了什么与你预期不符的内容?

如果不确切知道你做了什么,以及帖子(原始和已渲染)中包含什么,就很难提供帮助。由于你开始时使用的是一个预期数据不正确的数据库,因此此主题对其他人将没有用处。

我做了大家告诉我不该做的事:篡改数据库及其转储文件。目前,大部分功能都正常,除了以下几种情况:

<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

现在尝试从 /var/www/discourse/public/uploads 中 find 它:

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

是的!


但为什么在帖子中是 transparent.png?我运行了 rake uploads:recover_from_tombstonerake posts:rebake


我是怎么到这步的?

数据库中,对于 url 表的 uploads 列,仍然会显示 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 文件夹。尽管如此,我们仍然可以确认我们拥有所需的一切。

所以我们从 UI 下载数据库的副本,然后在 VSCode 中打开它,并逐步替换 cdck(存储桶)引用和 europe1(CDN 的存储桶)引用。

我所说的“逐步”是指在某些情况下你会看到 //...,而在其他情况下你会看到 https://。因此,你必须先匹配并替换 //...,否则文件中会出现多余的 https:

然后重新上传修改后的转储文件。使这一切变得棘手的其中一部分是 base62 步骤,这使得从原始表示到实际图像 URL 的过程稍微困难一些。

任务完成

在仔细检查了 uploads 表的大小后,我注意到缺少了几百条条目。我不知道它们是从哪个步骤丢失的。我将过去的数据库备份与临时表的基本 SQL join 合并了。

正如我上面可能提到的,请求图像的 URL 存储在 uploads 表的 url 列中。从 rails 控制台,我通过 uploads 表上的 SQL 将这些 CDN 引用重新映射到我们的本地域。

为什么不使用 rake 任务

可能有一些是可行的,并且它们的某种组合会起作用。然而,当你能够观察到当前的行为,知道你想要什么,并且知道如何到达那里——那么我觉得限制是任意的。

我想感谢 Discourse 团队和这里的志愿者,他们都给了我发现解决方案所需的信息,而这个解决方案最终包含了一些步骤。

1 个赞

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.