Deployment 在意总数,DaemonSet 在意覆盖面:新节点一进池子,同一个服务立刻就在那里。节点级关切——发日志、暴露硬件指标、跑网络 fabric、执行策略——必须处处有,不然等于处处没有。用逐节点脚本或每个 Pod 塞 sidecar 去凑合,立刻就烂:新节点漏掉、版本漂移,没人答得出"哪些节点跑着 agent"而不审计。

DaemonSet 控制器用声明式覆盖弥合这个缝。你把守护进程描述一次,控制器永远把现实收敛到每合格节点一个 Pod,扩集群自动扩守护舰队。覆盖从 runbook 条目变成系统维护的不变量。

每节点一个、天生如此

你把守护进程描述一次,控制器就给每个节点都挂一份副本,这正是节点级日志、指标 agent 与 kube-proxy 这类流量的天然归属。没有需要手工调大小的伸缩旋钮。没有旋钮是特性:副本数一经手压就会从意图漂走,而"每合格节点一个"不会漂——它按节点列表持续重算。新节点注册时 gain Pod,离场释放,被 cordon 的除非 drain 都留着。

因为放置按节点不按容量,DaemonSet Pod 一般要优先级和抢占 headroom,才能在满节点上活下来。给高 PriorityClass、诚实而克制的资源 requests:节点再满它们也必须调度上去,因为过载节点上缺席的监控 agent,恰在最需要 visibility 时致盲。没有需要手工调大小的伸缩旋钮,但调度要做对。

覆盖优先于数量

因为期望副本数本就隐含,一次滚动更新会触及每个成员:往池子里加一个节点,守护进程不用额外动作就自动出现。这是任何逐节点脚本都拼不过的保证。更新用 maxUnavailable 限 disruption 在舰队铺开——设 1 就逐节点刷新,舰队永不断覆盖。节点脚本的慢性病版本漂移,在结构上不可能:控制器把每节点收敛到同一模板,kubectl rollout status ds/agent 告诉你收敛何时完成。

异构舰队用 nodeSelector 与亲和延伸这份保证:一类节点一个 DaemonSet,各收敛各的子集。GPU 节点装 device plugin daemon,边缘节点装轻量 forwarder,各控制器只管自己的覆盖。心智模型保持"这类节点永远跑这个 daemon",被强制执行而不只是被希望。

跟着节点生命周期走

用 toleration 让 DaemonSet 能进那些一般工作负载被 taint 挡在门外的专用节点,从而保住全集群一致。典型例子是 master 的 control-plane taint 和 GPU/spot taint:没有 toleration,最有意思的节点恰恰没有 agent,舰队视图的洞长得跟特殊硬件一个形状。再用 nodeSelector 挑哪些子集该装,同时让每个够资格的节点都保持同步——按标签选子集保持声明式,给节点重打标签就在 daemon 舰队之间搬家,不碰任何控制器。

反过来也要尊重驱逐与 drain 语义。DaemonSet Pod 按设计无视普通调度压力,但 drain 时还是要优雅退出:terminationGracePeriodSeconds 诚实配置,SIGTERM 好好处理,不然节点维护变成日志断档和指标窟窿。覆盖意味着 churn 中也在场,而优雅关闭决定节点的滚动升级在监控里看不看像故障。 新节点池上线第一件事就是对 daemon 覆盖数:期望数与就绪数按池分组看,分叉立刻补 toleration。把这个检查写进节点池交付清单,而不是靠故障发现。 守护镜像的更新先灰度一个池,观察一轮无异常再全量铺开。

灰度期间重点看三组数字:新旧两个版本的 Pod 就绪数是否都稳定、节点侧日志量是否连续无断档、该池的 CPU 与内存占用是否明显抬升。任何一组抖动都先暂停全量,把有问题的镜像钉死在灰度池里排查,而不是带着疑问继续铺。灰度通过后再放开剩余池子,并保留旧版镜像标签一周,方便回滚时一步到位。

坏掉的样子

最经典的是悄悄没覆盖的节点:新节点池带了没人告诉 DaemonSet 的 taint,agent 处处有、除了那四十台新机器——而正在查的恰恰是它们。用各池的节点数对 daemon Pod 数诊断:每 DaemonSet 的 desiredNumberScheduled 对 numberReady 按节点标签分组。数字分叉的池子,缺的 toleration 或 selector 当场现形。

第二种是坏 daemon 更新铺满舰队:坏 agent 镜像配过大的 maxUnavailable,一次带走多节点的日志,致盲的恰是日志本要服务的调查。可观测 daemon 的 maxUnavailable 钉 1,先在 canary 池暂停验证(nodeSelector 限定的 DaemonSet 天然是 canary),记住回滚 DaemonSet 是一条命令——用得要快,因为没有 agent 的每一分钟都是缺证据的一分钟。

快速验证

期望覆盖对现实:

kubectl get ds -A -o custom-columns=NAME:.metadata.name,DESIRED:.status.desiredNumberScheduled,READY:.status.numberReady
kubectl get pods -o wide -l app=log-agent | awk '{print $7}' | sort | uniq -c | wc -l
kubectl get nodes --no-headers | wc -l

第一条看每 daemon 的覆盖缺口,Pod 节点数对节点数证明每台机器真有它的副本。

来源