恢复失败 - S3(兼容)备份

我一直在尝试恢复备份,但遇到了错误。看起来问题出在 S3 备份上。

需要说明的是,这里使用的是与 S3 兼容的服务(Scaleway)。不过我不确定这个错误是否仅针对兼容服务。设置过程非常顺利,之前一直运行正常。如果这确实是 Scaleway 特有的问题,我可能会考虑停止使用该服务,因为我了解到官方仅正式支持 AWS S3。

我是按照这份指南进行设置的:Configure an S3 compatible object storage provider for uploads app.yml 文件中。

  after_assets_precompile:
    - exec:
        cd: $home
        cmd:
          - sudo -E -u discourse bundle exec rake s3:upload_assets

我在 app.yml 文件中也使用了相同的配置来设置 Scaleway(未在管理员界面中设置,因为看起来没有必要):Scaleway 配置

我尝试了在当前服务器的管理界面和命令行中执行恢复,也尝试了配置新服务器(复制了 app.yml 文件)并通过命令行进行恢复,但都遇到了相同的错误。

[STARTED]
'system' 已开始恢复!
标记恢复为运行中...
确保 /var/www/discourse/tmp/restores/default/2020-07-16-131434 存在...
正在将归档文件下载到临时目录...
#<Thread:0x000055c73a831df8@/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/aws-sdk-s3-1.66.0/lib/aws-sdk-s3/file_downloader.rb:116 run> 因异常而终止(report_on_exception 为 true):
Traceback (most recent call last):
	1: from /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/aws-sdk-s3-1.66.0/lib/aws-sdk-s3/file_downloader.rb:120:in `block (3 levels) in thread_batches'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/aws-sdk-s3-1.66.0/lib/aws-sdk-s3/file_downloader.rb:128:in `write': undefined method `split' for nil:NilClass (NoMethodError)
EXCEPTION: undefined method `split' for nil:NilClass
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/aws-sdk-s3-1.66.0/lib/aws-sdk-s3/file_downloader.rb:128:in `write'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/aws-sdk-s3-1.66.0/lib/aws-sdk-s3/file_downloader.rb:120:in `block (3 levels) in thread_batches'
正在尝试回滚...
无需回滚
正在清理...
正在删除临时目录 '/var/www/discourse/tmp/restores/default/2020-07-16-131434'...
正在恢复 sidekiq...
标记恢复为完成...
正在通知 'system' 恢复已结束...
#<Thread:0x000055c73a831510@/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/aws-sdk-s3-1.66.0/lib/aws-sdk-s3/file_downloader.rb:116 run> 因异常而终止(report_on_exception 为 true):
Traceback (most recent call last):
	1: from /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/aws-sdk-s3-1.66.0/lib/aws-sdk-s3/file_downloader.rb:120:in `block (3 levels) in thread_batches'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/aws-sdk-s3-1.66.0/lib/aws-sdk-s3/file_downloader.rb:128:in `write': undefined method `split' for nil:NilClass (NoMethodError)
#<Thread:0x000055c73a8316c8@/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/aws-sdk-s3-1.66.0/lib/aws-sdk-s3/file_downloader.rb:116 run> 因异常而终止(report_on_exception 为 true):
Traceback (most recent call last):
	1: from /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/aws-sdk-s3-1.66.0/lib/aws-sdk-s3/file_downloader.rb:120:in `block (3 levels) in thread_batches'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/aws-sdk-s3-1.66.0/lib/aws-sdk-s3/file_downloader.rb:128:in `write': undefined method `split' for nil:NilClass (NoMethodError)
#<Thread:0x000055c73a8319e8@/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/aws-sdk-s3-1.66.0/lib/aws-sdk-s3/file_downloader.rb:116 run> 因异常而终止(report_on_exception 为 true):
Traceback (most recent call last):
	1: from /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/aws-sdk-s3-1.66.0/lib/aws-sdk-s3/file_downloader.rb:120:in `block (3 levels) in thread_batches'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/aws-sdk-s3-1.66.0/lib/aws-sdk-s3/file_downloader.rb:128:in `write': undefined method `split' for nil:NilClass (NoMethodError)
完成!
[FAILED]
恢复结束。

也许错误仅出现在下载备份的过程中?:face_with_monocle:

听起来确实如此。

我建议在 app.yml 中将备份位置改为本地,然后重新构建,手动下载备份文件,并从控制台进行恢复。

啊,这说得通。谢谢 @Falco:slight_smile:

我明天早上试试,然后回来汇报~

谢谢 @Falco,非常感谢!整个过程非常顺利 :smiley:

我迁移到了新服务器,看来其实留在原服务器也没问题。

以防其他人日后需要参考,以下是更详细的步骤(注意:我的 S3 设置仅按照此处的说明写在 app.yml 文件中,管理后台设置中未做任何自定义):

  1. 在源站点上,如果不是回滚操作,请启用“禁用邮件”(可能并非必需)并开启只读模式(记得在迁移完成后在新实例上重新关闭这些设置)。创建备份,完成后可以考虑停止旧实例(./launcher stop app)。无论是否回滚,都请更新 DNS A 记录,将其指向新服务器的 IP。你可以用更优雅的方式或顺序来最小化停机时间,但在我的案例中(回滚操作,论坛尚未上线),停机时间并非问题。

  2. 在新服务器上安装 Discourse,并将 app.yml 中的所有自定义配置(包括 S3 设置)迁移过去,确保 Discourse 版本相同或非常接近。

  3. 注释掉以下两条记录(app.yml 中的其他 S3 设置可保持不变):
    DISCOURSE_S3_BACKUP_BUCKET: BucketName
    DISCOURSE_BACKUP_LOCATION: s3

  4. 手动从 S3 或兼容 S3 的服务下载所需的备份文件。

  5. 导航到 /var/discourse/shared/standalone/backups,如果不存在则创建一个名为 ‘default’ 的新文件夹(如果是新安装,该文件夹默认不存在)。然后,在 backups 目录下运行以下命令(这将更改文件夹权限以匹配 Discourse 创建本地备份时通常拥有的权限——不确定是否必需):
    chown -R 1000:www-data default

  6. 使用 SFTP 客户端将备份文件上传到 backups/default 文件夹,请勿重命名备份文件。

  7. 重建应用:
    cd /var/discourse
    ./launcher rebuild app

  8. 进入应用,启用备份恢复功能并执行恢复(重命名为 BackupFileName.tar.gz):

./launcher enter app
discourse enable_restore
discourse restore BackupFileName.tar.gz
  1. 完成后,取消注释步骤 2 中 app.yml 里的两条 S3 备份文件相关行,并重建应用。

  2. 你可以删除本地的 backups/default 文件夹及其包含的备份文件(/var/discourse/shared/standalone/backups)。

参考: