bigywater.tech
Kubernetes · 66

不可变 ConfigMap 与 Secret:对 watch 数量的影响

immutable: true 为什么能减轻 apiserver 压力?它到底锁了什么?删了重建会怎样?这篇改了又改、删了又建,再用 apiserver 的 /metrics 数 watch 连接,看到差别。

+20 vs +2
20 个 Pod 各挂一个 ConfigMap 时,按名字 watch ConfigMap 的连接数增量(可变 / immutable)
只能 false → true
immutable 标志的方向是单向的
100 秒
删除重建同名 immutable 对象后,运行中的 Pod 等 100 秒仍是旧值

锁住的是 data

实测 · 本机执行输出
  改 data:退出码 1;The ConfigMap "fixed" is invalid: data: Forbidden: field is immutable when `immutable` is set
  新增一个键:退出码 1;The ConfigMap "fixed" is invalid: data: Forbidden: field is immutable when `immutable` is set
  把 immutable 改回 false:退出码 1;The ConfigMap "fixed" is invalid: immutable: Forbidden: field is immutable when `immutable` is set
  改 labels/annotations:退出码 0;configmap/fixed patched(元数据仍可改)
  可变的 ConfigMap 补上 immutable: true:退出码 0;configmap/mutable patched(可以单向锁定)
    锁定之后再改 data:退出码 1

给 ConfigMap 加 immutable: true 后,改 data 返回 Forbidden: field is immutable when `immutable` is set,新增键同样被拒,把 immutable 改回 false 也被拒;但 labels、annotations 这些元数据仍可修改。可变的 ConfigMap 可以随时补上 immutable: true,方向只能是 false → true。

改内容只能新建

实测 · 本机执行输出
  初始:/f/level='info'(immutable);/m/level='info'(可变)
  删除重建 immutable 的 fixed(值 debug),同时 patch 可变的 mutable 为 debug:可变的那个 87 秒后 /m/level=debug
    等了 100 秒:/f/level='info'(immutable 的 ConfigMap 被删后重建,挂载的文件依然是旧值);/m/level='debug'

Pod 挂着可变的 mutable 和 immutable 的 fixed。把 fixed 删掉重建成新值 debug,同时 patch mutable:mutable 在 87 秒后 /m/level 变 debug;等了 100 秒,/f/level 仍是 info——kubelet 把 immutable 对象视为不会变,不再同步,新建的同名对象也不会替换运行中的 Pod 已挂载的内容。要用新值只能换名字并滚动更新 Pod。

少了多少 watch

实测 · 本机执行输出
  基线:按名字 watch 单个 ConfigMap 的长连接数(apiserver_longrunning_requests,verb=WATCH、scope=resource) 16
  可变的 20 个 ConfigMap + 20 个 Pod(1 秒全部 Running):按名字 watch ConfigMap 的连接数 16 → 36(增加 20)
  immutable的 20 个 ConfigMap + 20 个 Pod(1 秒全部 Running):按名字 watch ConfigMap 的连接数 14 → 16(增加 2)
  差别:可变 +20,immutable +2

kubelet 对可变的 ConfigMap 为每个被挂载的对象保持一个按名字的 watch。20 个 Pod 各挂一个自己的 ConfigMap:可变版本让 apiserver_longrunning_requests{verb="WATCH",resource="configmaps",scope="resource"} 从 16 增加到 36(+20);immutable 版本从 14 增加到 16(+2)。那 +2 应该是新命名空间里本来就有的可变对象(比如 kube-root-ca.crt),我没有逐个确认。在节点和 Pod 很多的集群里,这是 apiserver 的压力来源之一。

分步演示

不可变
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / kind(Docker 里的单节点或多节点真实集群,节点是 Docker Desktop 虚拟机里的容器)/ kubectl;用空的 kubeconfig 之外的独立 kubeconfig,不碰用户自己的集群;计时用 date +%s%N / kubectl 事件时间戳,数字每次运行会有小幅抖动。三节点 kind 集群 kx-main(Kubernetes v1.37.0);watch 数取自 apiserver /metrics 里 apiserver_longrunning_requests 中 verb=WATCH、resource=configmaps、scope=resource 的总和(按名字 watch 单个对象的连接);每次创建 20 对 ConfigMap + Pod 并等全部 Running 后再等 10 秒读指标;可变与 immutable 各一次,在不同命名空间里先后进行;每种情形各一次
    • 没有验证:Secret 上的 immutable 是否同样的 watch 效果(机制相同,本文只数了 ConfigMap);kubelet 的 configMapAndSecretChangeDetectionStrategy 取其他值时的差别;immutable 对 apiserver CPU/内存/etcd 的实际下降量;那 +2 具体是哪两个;大规模(数千个)对象下的差别
    京ICP备2026067502号-1京公网安备11010502063487号