回滚按钮并不会把配置一起恢复
一句话总结
把 Deployment 回滚到旧 revision,与恢复旧运行环境不是一回事。即使回滚后的 Pod 模板仍引用同名 ConfigMap,如果该名称背后的内容已经改变,下一个 Pod 仍会以不同配置启动。
为什么需要它
支付服务的新部署未能就绪。运维人员回滚到旧 revision,rollout status 成功,服务也有响应。原以为问题结束,但不久后替换一个 Pod,相同故障再次出现。明明已经回滚,为何还会重现?
为了不把这个问题停留在记忆层面,我们在真实个人集群中复现了它。镜像与应用代码保持不变,只修改配置。最初两个 Pod 把正常配置读入环境变量。即使把 ConfigMap 内容改成错误值,现有进程的环境变量仍不变;但新 Pod 会从同名 ConfigMap 读取新值,并因 readiness 检查失败。
第一次回滚后,旧 Pod 仍存活,因此看起来正常。替换其中一个后,新 Pod 再次获得错误配置。命令没有撒谎,是我们期待的恢复范围超出了命令实际回滚的范围。
它如何工作
区分对象名称、内容与读取时间
Pod 模板的 envFrom.configMapRef.name 是配置对象名称,不是配置内容的副本或指纹。通过环境变量使用 ConfigMap 的容器在启动时读取值。编辑 ConfigMap 不会自动修改已经运行的进程环境变量。
因此,由同一 Pod 模板创建的两个 Pod 可能运行不同配置:先创建的持有变更前值,后创建的持有变更后值。“清单相同,所以运行结果相同”的推断遗漏了读取配置的时间。配置更新方式取决于传递方式,不要把环境变量的行为直接套用到卷挂载。
revision 历史包含什么
Deployment revision 与 Pod 模板变更关联。镜像、配置引用名称、模板标签或 annotation 变化都可能产生新部署。仅修改外部 ConfigMap 内容,不属于 Deployment Pod 模板变更。
回到旧 revision 时,只会选中旧模板。如果该模板仍引用 settings,而 settings 内容仍是错误值,故障源就仍然存在。只记录 revision 编号的部署记录,无法充分说明实际运行的是哪份配置。
把配置纳入部署制品
比较实验把正常配置与错误配置分别保存为 settings-v1 和 settings-v2,为每个对象设置 immutable: true,并让 Deployment 引用名称随版本变化。现在回滚到旧 Pod 模板时,配置引用名称也会一同回滚。
关键不是在名称后添加数字,而是保留旧运行所需的配置内容,并把所选配置与 Pod 模板连接为同一部署单元。实际测试中,修改正常不可变配置的请求被 API 拒绝。从错误版本恢复到旧引用后,即使替换 Pod,新 Pod 也会读取正常配置。
实际现场中的表现
团队说“把同一镜像从开发环境晋级到生产环境”时,如果只记录镜像 digest,解释可能只完成了一半。随环境变化的配置也必须接受评审与跟踪。即使镜像相同,连接目标、功能开关和就绪条件不同,行为也会改变。本例用一个简单的正常状态值展示了差异。
不可变对象仍可被删除后以同名重建,因此还需要管理删除权限、旧配置保留期与部署来源的变更历史。示例名称只是便于理解的版本名,不是内容寻址或签名,也不保证管理员无法篡改。Secret 不应放入 ConfigMap。
此外,回滚应用模板不会回滚数据库模式或已经处理的外部请求。部署前必须区分可回滚变更与需要单独恢复的变更。平台的恢复按钮不应隐藏边界,而应展示所需证据与限制。
下一篇阅读将检查什么
我们会分析服务有响应与新部署完成为何是不同证据,阅读旧 Pod 仍在接收流量而新 Pod 已损坏的状态,并建立恢复后还要验证替代 Pod 的标准。