一个部署平台的口碑,来自它最糟糕的那次失败,而不是功能列表。最糟的失败往往是安静的:健康检查在一个已经死掉的容器上通过,证书在凌晨三点续期失败,回滚目标已经被回收。
![]()
我们在做 Levelrail,一个自托管的部署平台。2026年9月27日的一次本地内部试用中,我们自己的代码里就出现了这样一次安静的失败。
测试本身很简单:推一个健康路由返回 500 的提交,然后确认平台拒绝这次部署,旧版本继续服务。
60秒后,就绪检查以 ReadinessFailed 条件失败。到这里都是对的。接下来是意外:入口网关还是把流量路由到了那个新的、正在失败的容器。上一个容器仍在运行,但没有流量。平台把这次部署尝试记录为成功。
也就是说,系统知道这个容器不健康,还是把用户送了过去。
两个各自合理的部件
应用控制器正确跟踪了就绪状态,写下了 Ready 条件。入口网关在系统的另一部分,用一条更简单的规则挑选路由目标:容器以目标镜像命名,只要它跑起来就选它。是“运行中”,不是“就绪”。
两者之间没有任何连接。就绪结论存在,路由器从没读过它。部署尝试记录在容器启动时就写下了,所以后来就绪失败时,它也不会变成失败。
教训是:两个各持一半安全保证的组件,加起来不等于一个保证。必须有人对“探针失败”到“没有流量”这条完整路径负责。
修复方式
两处改动,放在同一个合并请求里:
- 路由步骤现在以应用控制器存储的 Ready 条件为门槛。新版本没就绪,就回退到仍在运行的上一版本,而不是提前切换。
- 就绪探针失败现在会把部署尝试翻转为失败,历史记录显示真实发生的事。
两处都补了测试:一个让就绪失败并检查路由选择,一个检查就绪失败的新部署会记录为失败,还有一个在存储层检查最新的成功尝试会翻转为失败。
同一次运行里发现的相邻问题
同一次运行还翻出了附近的问题。回滚到一个拼错的镜像标签返回了退出码 0。容器起不来,入口网关丢掉路由,应用下线,而旧容器还在运行。现在命令行工具会拒绝本地不存在的标签,列出它认识的标签,并指向正确的命令。
一次环境变量导入之后,一个 www 重定向也消失了,因为每次保存应用都会删除并重新插入域名记录,而重定向和证书设置都挂在这些记录上。这个也修了。
这些问题都不会出现在功能列表里。它们出现,是因为我们拿真实应用跑这个平台,并且故意让它失败。
平台现在检查什么
除了按就绪状态路由,控制器还会校验运行中容器的镜像是否匹配部署预期的固定摘要。不匹配时,应用报告 Ready: False 和 ImageDigestMismatch,上一版本继续服务。只要运行内容和发布内容不一致,它就不会报告已部署。
部署结果可以从命令行查看,退出码告诉你结果:
- 0 表示健康;
- 7 表示失败、取消、被取代或被阻塞;
- 6 表示等待超时。
仍未闭环的部分
我们还没做完。写这篇时,那次运行留下的一项仍未关闭:端到端确认 apps deploys wait 在尝试翻转为失败后能正确报告就绪失败。我们预期它会作为修复的副作用正常工作,但没有独立验证过。
Levelrail 还很年轻。项目把单服务器部署标为生产可用,较新的功能仍是测试阶段。把它放在现有环境旁边,跑满一个业务周期、带上真实流量——那些无聊的失败才会浮出来。
Levelrail 以 Apache 2.0 协议开源,缺陷和需求提交到问题追踪器。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.