更改用于上传的 s3 存储桶

你好!

我们正在将所有的上传文件/图片在两个兼容 S3 的服务之间进行迁移(如果这有影响的话,两者都是 DigitalOcean Spaces),但我发现我们目前陷入了一个相当糟糕的境地。

我先解释一下迁移是如何进行的:

  1. 我们使用 rclone 将初始存储桶克隆/同步到了新存储桶。
  2. 更新了 Discourse 管理后台“文件”页面中所有指向新端点的引用。
  3. 执行了重新烘焙(re-bake)。

遗憾的是,这并没有达到我们的预期,现在论坛中的所有图片都“消失”了。它们仍然存在于 S3 存储桶中(幸运的是,旧存储桶中也还有),但任何帖子都无法找到对应的图片。

存储桶的大小约为 60GB,因此即使不算极端,这也是相当大量的数据。

我已经重建了容器,尝试从墓碑(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 可能已损坏,或者图像的 SHA 因某种原因发生了变化。

有人之前做过类似的操作吗?所有的图片都永远丢失了吗?(是的,我有备份和旧图片,所以我知道是有办法解决的。)

2 个赞

值得一提的是,我也尝试使用了为 Spaces 存储桶提供的 CDN URI(并进行了重新生成)。

1 个赞

缺失上传的输出:

rake posts:missing_uploads
正在查找默认站点上的缺失上传:
修复缺失的上传:
🚫
缺少 17075 个帖子上传。

缺少 16906 个上传。
其中 1 个属于旧方案上传。
139801 个帖子中有 14646 个受到影响。

post_uploads 有 3448 条记录
optimized_images 有 25681 条记录
uploads 有 5764 条记录

1 个赞

你可以查看 Moving from one S3 bucket to another

我认为我已经起草了一份操作指南,打算明天发布。

5 个赞

那会非常有帮助,非常感谢!

1 个赞

@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

注意:如果你在数据库的 SiteSettings 中定义了 s3_endpoint 并切换到 AWS(AWS 不需要端点),那么在使用更新后的设置构建新容器后(或在恢复包含该设置的数据库后),你需要清除该站点设置。

重新烘焙引用存储桶而非 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

8 个赞

感谢您的回复。

这基本上是我上次做过的事情,但我再次尝试了。问题是 posts.count 返回 0。所有帖子在 cooked 部分都包含 transperent.png 文件,而在 uncooked 部分包含哈希值。

是否有任何方法可以在 bake 期间正确解析该图片?

1 个赞

嗯,没错。那个临时修复只是为了避免重新生成。如果重新生成失败,那说明还有其他问题。也许是资源文件不在 Discourse 预期的位置?

1 个赞

嗯,这是有可能的,不过这次“迁移”基本上是把存储桶中的所有文件原样移动了一遍,嘿嘿……

2 个赞

所以你可以用新的 Bucket URL 替换旧的,然后就能正常工作了?

Uploads 中的值看起来对吗?

1 个赞

我有点担心,如果改回旧的存储桶,可能会触发一个任务,将所有内容标记为“已删除”(tombstone),因为它们现在被视为“旧”数据。不过,是的,数据库似乎确实指向了正确的(新位置的)图片,问题基本上只是旧帖子无法解析到正确的图片(我猜是这样……)。

1 个赞

运行完 toombstone 恢复 rake 任务,接着运行 fix_missing_uploads rake 任务后,我终于让它开始“修复”图片了。
看起来它正在下载图片并重新上传,这需要耗费大量时间,也会占用大量资源,但至少用户能找回他们的图片了!

感谢你的帮助 @pfaffman :slight_smile:

3 个赞

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