14.3 配置管理与漂移检测
一句话
配置管理的目标不是 “有个地方存配置”,而是 “声明的配置 = 实际运行的配置”;两者一旦分叉就是漂移——漂移不会自己消失,只会在下次发布时把线上改回旧值,或把手工修复悄悄抹掉。
配置的三种形态
| 形态 | 例子 | 风险 |
|---|---|---|
| 代码内配置 | 常量、feature flag 默认值 | 改配置要发版 |
| 配置中心 | etcd/Nacos/Apollo | 需权限与审计,否则谁都能改 |
| 环境变量/挂载文件 | K8s ConfigMap/Secret | 与代码版本不同步,易漂移 |
原则:配置要版本化、可审计、可回滚;密钥不进配置(见 13.4 密钥与凭证管理)。
实测:漂移检测的最小实现
对 “期望配置” 与 “实际配置” 做规范化后比对(哈希/逐字段):
| 检查 | 结果 |
|---|---|
| 期望哈希 vs 实际哈希 | 不一致 → 漂移 |
| 差异字段 | 如 replicas: 3 → 5、image: v1.2 → v1.3 |
| 漂移数量 | 本次 2 个字段,其中 1 个是 “手工扩容” |
# 声明式对比:期望(Git)vs 实际(集群)
kubectl diff -f deploy/ # 直接给出将发生的变更(含漂移)
# 只看漂移(不含本次要发布的变更):先 apply --dry-run,再 diff
terraform plan -detailed-exitcode # 0=无变化 1=有错误 2=有差异
判据:plan/diff 长期不为空 = 有漂移,必须查明来源(手工改?其他工具?云厂商默认值?)。
漂移的三种来源与对策
| 来源 | 例子 | 对策 |
|---|---|---|
| 手工改控制台 | 紧急扩容、改安全组 | 变更回写 IaC;或明确 “临时变更需登记 + 到期回收” |
| 其他工具/脚本 | 运维脚本改了配置 | 收敛到单一入口(IaC 或配置中心) |
| 云侧默认值/自动行为 | 托管服务自动升级、默认参数 | 显式声明,不依赖默认值 |
反模式
| 反模式 | 后果 |
|---|---|
| 配置只存在控制台 | 无法版本化、无法回滚、无法审计 |
| 漂移不告警 | 下次 apply 把手工修复抹掉 |
| 配置与代码分开发布 | 版本不匹配,出现 “只有旧代码能跑” |
| 密钥写进 ConfigMap | 明文泄露(见 13.4 密钥与凭证管理) |
| 不记录 “谁改了什么” | 出事无法追责/回滚 |
| 环境间复制配置文件 | 一处改动扩散到所有环境 |
三条铁律
🔑 配置必须有唯一来源(Git 或配置中心),不能 “两处都能改”。
🔑 漂移即告警;
plan/diff长期不为空就是问题。
🔑 密钥与配置分离,配置可公开评审,密钥不可。
自检
Q1 为什么 “手工改控制台” 会造成漂移事故?
▸ 答案:因为 IaC 的 “期望状态” 没变:下次 apply 会把手改改回去。如果手改是应急修复,就会被静默抹掉,表现为 “修好的问题又回来了”。正确流程是 “改代码 → 再 apply”,临时变更要登记并限期回收。
Q2 terraform plan -detailed-exitcode 的退出码怎么用?
▸ 答案:0 表示无变化、1 表示出错、2 表示有差异。CI 里可以 “定期跑 plan,退出码为 2 就告警”,从而把 漂移检测自动化;发布流水线里则用它确认 “本次变更与预期一致”。
Q3 配置中心与 IaC 的分工是什么?
▸ 答案:IaC 管 “基础设施与部署形态”(网络、副本数、资源规格),配置中心管 “运行期可变参数”(开关、阈值、名单)。两者都要版本化与审计,但变更频率与审批级别不同;不要用配置中心去改 “本该 IaC 管” 的东西。
Q4 为什么 “配置与代码分开发布” 容易出事?
▸ 答案:因为会出现版本不匹配:新配置配旧代码(字段不认)、旧配置配新代码(缺默认值)。解法是 “配置随制品版本化”(同一 commit 生成配置与镜像),或让代码对缺失配置有安全默认。
Q5 漂移检测会不会产生大量噪音?
▸ 答案:会,如果没做规范化:云厂商默认值、自动生成的字段、时间戳都会造成 “假漂移”。先把 “可忽略字段” 排除(如 status、creationTimestamp),再比对;否则团队会很快忽略告警。
Q6 多环境配置怎么避免 “复制粘贴”?
▸ 答案:用同一份模板 + 环境 values(如 Helm values / Terraform tfvars),模板里不写死环境差异;差异只允许出现在 values 文件里,并进代码评审。复制整份配置会在某次改动后 “三套环境不一致”。
Q7 怎么证明 “配置管理真的有效”?
▸ 答案:三条:plan/diff 长期为空(无漂移)、任何一次线上变更都能追溯到 Git/配置中心的记录、回滚能在分钟级完成。三者都成立,才算 “配置被管理”,而不是 “配置有个地方存着”。