公正地说,我应该先说明:我刚刚接触这个平台和代码库,因此完全不了解 rebuild 目前在底层是如何工作的。不过,我目前的理解是,rebuild 会执行以下步骤:
- 停止当前容器
- 根据源码树中的数据构建新容器
- 等待您启动新容器
从 DevOps 的角度来看,为什么不能在旧容器仍在运行时构建新容器(例如在另一个分支或临时目录中)?这样做似乎能让新旧容器的切换过程快得多(至少就停机时间而言),可能只需几秒钟而不是几分钟。
如果容器使用的存储卷在容器重建时不会被销毁,我甚至不确定配置或数据库变更(例如新消息)是否需要针对此用例进行特殊处理。这意味着容器的构建不应与容器状态如此紧密耦合。
这仅仅是因为还没有人关注这个问题,还是存在某种现有的架构决策,要求必须先停止一个容器才能构建另一个容器?
Falco
(Falco)
2
Rebuild 是一个综合性的更新,它可以:
- 更新 Discourse 源代码
- 更新操作系统级别的依赖项,例如 Ruby 主版本
- 更新到更新且不兼容的 PostgreSQL 版本,它会自动处理为新版本更新数据磁盘格式
- 更新 Docker 镜像。举个例子,今年早些时候我们从 Ubuntu 16.04 切换到了最新的 Debian,这对用户完全透明,只需输入
./launcher rebuild app 即可。
Rebuild 并非每次都需要执行,仅在每年发生大型依赖项更新时才必须执行。对于其他所有更新,您可以通过点击管理界面中的 Web 更新器实现零停机更新。
如需了解更多“运维”相关内容,您可以尝试:
以及更多内容,请查看 #howto:sysadmin
我可能错了,但我认为 @CodeGnome 关于零停机重建的问题仍值得进一步探讨。
如果我对 Docker 的理解正确,Discourse 的以下方面可以在后台于新容器中重建,而现有容器仍在运行:
- 更新 Discourse 源代码
- 更新操作系统级别的依赖项,例如 Ruby 主版本
- 更新 Docker 镜像。仅举一例,今年早些时候我们从 Ubuntu 16.04 切换到最新的 Debian,对用户而言完全透明,只需输入
./launcher rebuild app 即可。
至于破坏性的 PostgreSQL 变更,由于数据量较大,处理起来更为棘手,我假设这些数据卷在旧容器和新容器之间是共享的。
或许可以在重建开始时将站点设为只读模式,让旧容器保留其现有数据卷,而正在构建的新数据库则运行在一个新的 Docker 数据卷中?
关于更新 Discourse 源码、操作系统级依赖、Docker 基础镜像、Ruby gems 等,可以通过两步构建来实现,并在第一步中执行上述任务。
这一步与具体环境无关,甚至可以在 CI 环境中运行(因此您可以在测试环境和生产环境中使用几乎相同的镜像,避免因在不同日期重新构建而可能产生的错误,更不用说减少了停机时间)。
数据库迁移和 assets:precompile 任务仍需在目标机器上执行。数据库迁移在大多数情况下速度很快。另一方面,assets:precompile 是个问题,因为它是耗时最长的步骤。我认为这是因为某些资源需要依赖数据库中定义的环境信息(例如一些 CSS 规则)才能执行。
如果能够将此任务拆分为两部分,其中所有不依赖环境的资源先运行(可以在 CI 环境中执行),第二步仅编译那些依赖数据库等环境信息的资源,那将非常理想。不过,我不清楚从技术角度实现这一方案会有多大难度。
我在以下主题中讨论了分两步引导应用容器的方法:
我所做的更改仅涉及将 Discourse Web 模板拆分为三个文件,但任务本身保持不变。不过,如果 Discourse 团队能够原生支持这一方案,我将无需因 Web 模板的未来变更而手动更新这些内容。