快速迁移到将 Web 和数据容器分开的方案

:warning: 警告: 如果您不习惯担任 Linux 系统管理员,且没有使用 Docker 容器的经验,迁移到多容器部署将会给您带来困难。届时,工作人员和志愿者将合理地要求您回退到由 launcher 脚本完全管理的独立单容器部署。

如果您迁移到多容器部署且系统因此崩溃,您很可能会面临“两个坏部件都得留着”的局面。如果您阅读了下面的说明,却感觉像是在施展魔法,而不是在阐明容器内部的实际运作方式,那么请立刻前往最近的默认独立部署,这将是您为自己做的一件好事。

从单容器部署迁移到多容器部署的推荐方法 本质上如下:

  • 备份您的 Discourse
  • 彻底删除所有内容
  • 从头开始使用多容器部署
  • 恢复您的备份

如果您像我一样拥有一个需要数小时才能恢复的大型站点,您可能会想知道是否有更快的方法。无需再想!我从独立部署迁移到包含 Web、数据和 Redis 的三容器部署所花费的时间,甚至比通常对该站点执行 ./launcher rebuild app 的时间还要短。(总停机时间为 12 分钟,而重建应用有时需要 30 分钟以上。)根据我的经验,未来我会建议将 Redis 与 Postgres 保留在单个 data 容器中。

如果您这样做,您就需要自行负责了解何时需要重建其他容器(数据容器,以及如果您像我一样愚蠢地分离了 Redis,则还包括 Redis 容器)。 您将不再能通过 ./launcher rebuild app 免费获得所有组件的升级——如果您没有资源来管理此过程,请使用独立部署或购买托管 Discourse 服务。

测试

除非在阅读本文后,您同时也明白了如何从多容器快速迁移回单容器,否则请勿使用此过程迁移到多容器。如果阅读后这还不明显,那么这篇文章的技术含量就足够高(即“与魔法无异”),您可能无法识别此过程是否在中间步骤出错了,从而导致您得到一个很久之后才意识到的损坏的 Discourse。如果发生这种情况,您就得“两个坏部件都得留着”了。正如人们常说的:弄坏了,就得负责!

备份

首先进行备份,并先开启缩略图备份,这样在恢复时就不需要重新生成它们。如果您在此处出错,很容易陷入一种境地,即最简单、最安全且最快的恢复方式是切换回正常方法。请随时准备在出现问题时回退到 推荐方法

下载您的备份。下面的命令涉及在 Discourse 数据中移动文件,如果您出错,可能会删除您的备份。所以请下载它。此外,如果您的备份不包含上传文件,请也备份它们。它们也位于您将要移动文件的位置。

说真的,请务必备份。

当我执行此操作时,首先我进行了备份,然后进行了远程系统备份,之后才继续下一步。

设置新的多容器配置

您至少需要 containers/web_only.ymlcontainers/data.yml,如果您还想分离 Redis,还需要 containers/redis.yml。首先将 samples/data.yml(以及可选的 samples/redis.yml)复制到 containers/ 目录。

如果您单独部署 Redis,请从 containers/data.yml 文件顶部移除 Redis 模板。(但如果没有充分理由请不要这样做;这只是额外的工作。)

您有两种创建 web_only.yml 的方法。

  1. samples/web_only.yml 复制到 containers/;然后将两者与 containers/app.yml 进行比较,在您的新 containers/data.yml 中保留 params: 中的任何 Postgres 配置
  • containers/app.yml 中 Postgres 的任何 params: 复制到 containers/data.yml
  • 创建一个唯一的密码来替换 SOME_SECRET
  1. 或者,将 containers/app.yml 复制到 containers/web_only.yml 并将其与 samples/web_only.yml 进行比较
  • 移除任何对 Postgres 和 Redis 模板的引用
  • 移除仅包含 Postgres 设置的整个 params: 部分
  • 添加 links: 部分,内容完全照搬 samples/web_only.yml 或根据您的情况进行修改(见下文,如果您将 Redis 部署在单独的容器中)
  • samples/web_only.yml 添加数据库部分,并创建一个唯一的密码来替换 SOME_SECRET
  • 将卷定义从 standalone 更改为 web_only

如果您将 Redis 分离到其自己的容器中,而不是使用将其与 Postgres 捆绑在数据容器中的合理默认设置,请使用以下 links: 部分:

# 使用 'links' 键将容器链接在一起,即使用 Docker --link 标志。
links:
  - link:
      name: data
      alias: data
  - link:
      name: redis
      alias: redis

如果您将 Redis 和 Postgres 容器合并为单个数据容器,则不需要 redis 链接;这里展示的是如果您需要分离时应做的操作。

以下是 samples/data.ymlenv 里当前的 Postgres 设置副本,您需要在此处更改 SOME_SECRET

  ## TODO: 配置数据库连接
  DISCOURSE_DB_SOCKET: ''
  #DISCOURSE_DB_USERNAME: discourse
  DISCOURSE_DB_PASSWORD: SOME_SECRET
  DISCOURSE_DB_HOST: data
  ## 如果您使用单个 data+redis 容器,以下内容将是 "data"
  DISCOURSE_REDIS_HOST: redis

请注意,对于正常部署(非多站点),您不需要修改任何其他行。DISCOURSE_DB_SOCKET 是用于 Postgres 的 Unix 域套接字,它不是端口号。

以下是 web_only.yml 末尾卷定义变更的示例,如果您是从 app.yml 而不是 samples/web_only.yml 复制该文件,则需要使用此变更:

@@ -75,10 +80,10 @@
 ## Docker 容器是无状态的;所有数据都存储在 /shared 中
 volumes:
   - volume:
-      host: /var/discourse/shared/standalone
+      host: /var/discourse/shared/web_only
       guest: /shared
   - volume:
-      host: /var/discourse/shared/standalone/log/var-log
+      host: /var/discourse/shared/web_only/log/var-log
       guest: /var/log

现在,在 containers/data.yml 中设置与 containers/web_only.yml 中使用的相同秘密密码,替换 SOME_SECRET

现在您已准备好进行迁移。

现在,在您尝试快速迁移之前,请进行并下载您的最终备份。 请记住,如果此处出现任何问题,请立即前往 推荐方法我再怎么强调这一点都不为过。

分离数据(Postgres)和 Redis 容器:

cd /var/discourse

./launcher stop app
cd  shared
mkdir data
mkdir redis
mv standalone/postgres_* data/
mv standalone/redis_data/ redis/
mv standalone web_only
mkdir -p data/log/var-log
mkdir -p redis/log/var-log

cd ..

./launcher destroy app

./launcher bootstrap data
./launcher bootstrap redis
./launcher start redis
./launcher start data

./launcher bootstrap web_only
./launcher start web_only

合并 Postgres+Redis 数据容器:

cd /var/discourse

./launcher stop app
cd  shared
mkdir data
mv standalone/postgres_* data/
mv standalone/redis_data/ data/
mv standalone web_only
mkdir -p data/log/var-log

cd ..

./launcher destroy app

./launcher bootstrap data
./launcher start data

./launcher bootstrap web_only
./launcher start web_only

另外请注意,如果您之前设置过外部 Nginx,则需要更改 proxy_pass 路径以匹配新的 web_only 套接字位置;例如从 http://unix:/var/discourse/shared/standalone/nginx.http.sock: 更改为 http://unix:/var/discourse/shared/web_only/nginx.http.sock:

对我来说,在拥有 2 核 CPU、4GB RAM 的虚拟机上,对于一个没有下载内容、备份大小为 600MB 的站点,此过程导致的停机时间为 12 分钟。您的情况可能有所不同。

请注意,到目前为止,这些操作都没有更新 launcher。您可能不是最新版本。(例如,我在 Postgres 12 更新可用之后但在应用之前运行了此操作。此过程使我的 Postgres 版本停留在 10。然后我做的第一件事就是重建数据应用,这更新了 launcher 并成功带我完成了 Postgres 12 更新过程。)

未来更新时该做什么

在此迁移之后,如果您需要更新 Redis 或数据,首先需要停止 Web 应用。操作如下:

./launcher stop web_only
./launcher rebuild data # 和/或 redis
./launcher rebuild web_only

请注意,如果您重建 data(或 postgres,或 redis)容器,则需要创建一个新的 Web 容器以将其与新数据容器重新连接。您可以通过重建 web_only 来实现,或者,如果您认为不需要重建它,执行 ./launcher destroy web_only; ./launcher start web_only 即可(如果您收到关于“缺少数据容器”或类似的错误,这就是您需要做的)。

然而,当 Postgres 和 Redis 都不需要更新时,不重建这些容器会快得多,大多数应用重建只需 ./launcher rebuild web_only

或者,为了进一步减少停机时间(据报告在 15 秒到 2 分钟之间):

./launcher bootstrap web_only
./launcher destroy web_only && ./launcher start web_only

再次强调,通过迁移到多容器部署,跟踪何时进行更新现在是您的工作。 您会在管理控制台中收到有关更新的通知,但它们仅适用于 web_only 容器。没有任何提示会告诉您何时需要更新 Postgres 或 Redis。如果您这样做,请在每次版本升级之前阅读 公告类别,并在每次升级到或经过的新版本时阅读 发布说明。也就是说,如果您跳过了某个版本更新,请不要跳过阅读您跳过的该版本的发布说明。(考虑在发布说明上设置关注,或将您的阅读器订阅到 https://meta.discourse.org/tag/release-notes.rss 以保持最新。)

请注意,重建 web_only 容器要求数据库正在运行,因此您无法通过并行重建所有两个或三个容器来加快速度。如果您打算每次都重建所有容器,请坚持使用标准的推荐独立部署;这比同时管理多个容器要快。

备份审查

如果您将上传文件与数据库分开备份,我希望您有一个基于文件的远程备份机制用于上传文件,以便在发生灾难时将其备份并恢复。

审查您的远程备份实现,确保它会将 /var/discourse/shared/web_only 中的上传文件而不是 /var/discourse/shared/standalone 中的文件进行备份,以便在新的多容器实现中保持备份的更新。

22 个赞

您好,mcdanlj!我是新来的。我发现 Discourse 有两种部署方式:一种是 app.yml 的独立模式,另一种是您的方法,即将数据库和 Redis 缓存拆分为 web-only.ymldata.ymlredis.yml 的多容器模式。但同时,我也发现可以通过修改参数 DISCOURSE_DB_HOSTDISCOURSE_REDIS_HOST 来连接 Redis 和数据库,所以为什么我们需要将 app.yml 拆分为 web-only.ymldata.ymlredis.yml 呢?

如果您已经拥有数据库和 Redis(例如,通过 RDS 和 ElastiCache,或以其他方式自行创建),则无需自行搭建。

请注意,每个 Discourse 实例都需要自己的 Redis。

1 个赞

感谢 Jay 提供的详细解释!但我仍然感到困惑。从 Falco 的教程 中我注意到,可以轻松使用 AWS 的 RDS 和 Elasticache,而无需配置 web-only.yml、data.yml 和 redis.yml。Falco 的教程只编辑 app.yml 中的参数。但是 mcdanlj 的教程却不同。是因为他的论坛太大了吗?因此他不能使用 Falco 提供的简单方法?

使用 rds 和运行您自己的数据库服务器是两回事。如果您有很多钱和专业知识,rds 是很棒的。如果您一无所知,单个容器安装就非常棒。如果您钱不多,并希望减少停机时间,则双容器方法是不错的选择。

总而言之,您应该使用对您最有意义的任何一种。

1 个赞

非常感谢!也许单个容器对我来说是最好的方式 :rofl: 在你告诉我之前,我没有意识到 rds 和自己的数据库服务器之间的区别 :joy:

1 个赞

@ShawnLi 如果双容器系统看起来很复杂,这表明单容器默认设置是您的好选择。双容器部署在每月更新时可节省几分钟的停机时间,但需要更多的理解,并且要求您在每个新版本发布时手动遵循公告中的详细信息。

这就是我首先说的:

:grinning:

2 个赞

谢谢 mcdanlj!您的教程很棒,我从中获益匪浅。我决定选择简单的单容器默认设置。是的,我运行了 :rofl:

2 个赞