Hello there,
We are wondering if zero downtime upgrades are possible. We are using the discourse_docker installation using separate web and data containers, so the issue is more around the old application code (v2.1) running against a migrated v2.3.0 database schema. This happens between the time we bootstrap the image (which will run the migrations) and the moment the web servers get restarted (updated) to run the upgraded image. Are there any recommendation for this?
我们成功在几个月前完成了升级。我将我们的经验发布在这里,供将来可能遇到同样问题的人参考。
Discourse 通过部署后迁移在一定程度上支持零停机升级。据我们理解,整体流程可分为两个步骤。
步骤 1:升级到新版本并运行安全迁移:
- 更新所有插件和主题以兼容新版本。(根据具体设置,这实际上是一项不小的工作量)。
- 生成包含以下内容的
web_only.yml 文件:
version: <NEW_VERSION>
SKIP_POST_DEPLOYMENT_MIGRATIONS=1
- 引导启动(
./launcher bootstrap web_only)
- 重启服务器
步骤 2:运行部署后迁移(高风险迁移,例如列和表的删除等)。此时此步骤应该是安全的,因为所有服务器都已运行新版本的代码,不应依赖于将被删除的数据:
- 生成包含以下内容的
web_only.yml 文件:
version: <NEW_VERSION>
SKIP_POST_DEPLOYMENT_MIGRATIONS=0
- 引导启动(
./launcher bootstrap web_only)
- 重启服务器
复杂情况:
我们决定在不同日期执行步骤 1和步骤 2,这导致了一些问题。在 2.1 和 2.3 版本之间,polls 模型经历了一次重大的重构。似乎最初大多数投票数据是以 JSON 对象的形式存储在 post_custom_fields 表中的。到了 2.3 版本,它们被移到了独立的 polls 表中。这需要一些数据迁移,该迁移是作为部署后迁移(步骤 2)的一部分完成的。
我们的具体问题在于,在升级到 2.3 之后,升级前创建的投票出现了故障,很可能是因为渲染它们的代码假设了新的数据模型。一些用户注意到了这一点,并尝试通过 UI 手动更新投票,结果在 polls 表中创建了记录。我们后来不幸地发现,此类记录在引导启动过程中会触发 Postgres 唯一约束,从而导致引导启动失败。
为了规避这个问题,我们决定应用一个补丁,如果某个特定的投票迁移在数据库中已存在,则跳过该迁移。这并不是一个完美的解决方案,因为某些 post_custom_fields 中的数据可能永远不会被迁移。但在我们的案例中,这仍然是一个不错的权衡,因为系统范围内此类情况非常少(我们观察到的只有 2 个实例),并且使我们能够继续执行引导启动过程。现在,测试和应用该补丁又引发了两个问题:
-
我们如何在提交 PR 之前测试更改?
我们希望在代码实际运行的相同条件下进行测试,这意味着需要在引导启动过程中进行测试。这不像测试运行时代码更改那样简单,后者可以通过在本地运行独立的 Discourse 应用来完成。
-
我们如何将更改整合到系统中?
我们不想等待补丁进入官方的 Discourse 发布版本,因为这可能是一个漫长的过程,并且基本上会迫使我们进行另一次升级。我们的客户已经对现有投票问题提出了投诉,等待时间越长,客户手动修改投票的可能性就越大,从而加剧数据完整性问题。
因此,我们找到了一种方法来测试我们引入的更改,即更改引导启动脚本所使用的仓库来源。这需要一些尝试和错误,因为我们对围绕此过程的 pups 和其他工具并不熟悉。最终,我们做了类似这样的操作。
这使我们能够验证我们的修复是否按预期工作。我们还能够从包含该补丁的我们自己修改的 Discourse 版本中,在生产环境引导启动一个新的镜像,而无需等待官方的 Discourse 发布。