DaemonSet 是怎么做到“每个节点一个”的?它的 Pod 为什么能在节点有压力时还留着?给节点打标签、打污点会发生什么?更新是一次换几个?这篇在 5 节点集群里把这些问题逐个测了一遍。
DaemonSet ds 创建后 Pod 所在节点:['worker', 'worker2', 'worker3', 'worker4'](控制面有污点,没有被选中)
status:desiredNumberScheduled=4 currentNumberScheduled=4 numberReady=4 updatedNumberScheduled=4
某个 Pod 的 spec.nodeName=worker2;控制器加的 affinity:{"nodeAffinity": {"requiredDuringSchedulingIgnoredDuringExecution": {"nodeSelectorTerms": [{"matchFields": [{"key": "metadata.name", "operator": "In", "values": ["kx-sched-worker2"]}]}]}}}
控制器加的 tolerations:node.kubernetes.io/not-ready:NoExecute; node.kubernetes.io/unreachable:NoExecute; node.kubernetes.io/disk-pressure:NoSchedule; node.kubernetes.io/memory-pressure:NoSchedule; node.kubernetes.io/pid-pressure:NoSchedule; node.kubernetes.io/unschedulable:NoSchedule创建 DaemonSet 后 4 个 worker 各有 1 个 Pod,控制面因为有污点没被选中。每个 Pod 其实由 DaemonSet 控制器“指派”:spec.affinity 里被加上 nodeAffinity required、matchFields: metadata.name In [kx-sched-worker2],再交给默认调度器放置;同时自动带上 6 个容忍——not-ready、unreachable(NoExecute)与 disk-pressure、memory-pressure、pid-pressure、unschedulable(NoSchedule),所以节点有压力或被 cordon 时它仍然留着。
DaemonSet dsel(nodeSelector k42=yes),还没有节点有这个标签:Pod 在 [] 给 worker2 打标签后 0.1 秒,Pod 出现在 ['worker2'] 再给 worker3 打标签,然后去掉 worker2 的标签:0.1 秒后 Pod 在 ['worker3'](不匹配的节点上的 Pod 被删除)
DaemonSet 带 nodeSelector: {k42: "yes"}:没有节点有标签时 0 个 Pod;给 worker2 打标签 0.1 秒后 Pod 出现;再给 worker3 打标签并去掉 worker2 的,0.1 秒后只剩 worker3,不再匹配的节点上的 Pod 被删掉。控制器一直在监听节点变化。(第一次写这个实验时 YAML 里的 yes 被解析成布尔值,DaemonSet 没创建成功,别踩同样的坑。)
worker 打上 k42=x:NoSchedule:已有的 Pod 还在:['worker', 'worker2', 'worker3', 'worker4']
换成 NoExecute 污点:0.1 秒后 worker 上的 Pod 被驱逐,DaemonSet 没有把它重建(新建的 Pod 同样容忍不了):Pod 在 ['worker2', 'worker3', 'worker4']
DaemonSet 状态:desired=3 current=3(控制器知道 worker 不再符合条件)
去掉污点后 0.5 秒,worker 上又有了 Pod:['worker', 'worker2', 'worker3', 'worker4']给 worker 打 NoSchedule 污点,已有的 Pod 不动;换成 NoExecute,0.1 秒后 worker 上的 Pod 被驱逐,DaemonSet 不再重建它,status 变成 desired=3——控制器认为 worker 已经不符合条件。去掉污点后 0.5 秒 Pod 又回来了。自带的容忍里没有自定义污点,要让 DaemonSet 上有污点的节点必须自己写容忍。
ru1(maxUnavailable=1):改了环境变量触发更新,(updatedNumberScheduled, numberReady, numberUnavailable) 的变化:(0, 4, 0)@0.1s → (1, 3, 1)@3.2s → (1, 4, 0)@6.3s → (2, 3, 1)@9.5s → (2, 4, 0)@12.9s → (3, 3, 1)@16.3s → (3, 4, 0)@19.9s → (4, 3, 1)@23.1s → (4, 4, 0)@27.2s;共 27.2 秒 ru2(maxUnavailable=2):改了环境变量触发更新,(updatedNumberScheduled, numberReady, numberUnavailable) 的变化:(0, 4, 0)@0.1s → (2, 2, 2)@3.6s → (2, 3, 1)@7.1s → (2, 4, 0)@7.7s → (3, 3, 1)@10.3s → (4, 2, 2)@10.8s → (4, 3, 1)@13.6s → (4, 4, 0)@13.9s;共 13.9 秒 OnDelete:改了模板 6 秒后 updatedNumberScheduled=0/4,Pod 没变(旧 Pod 全在:True) 手动删掉其中一个 Pod 之后:updatedNumberScheduled=1/4(只有被删掉重建的那个换成了新模板)
RollingUpdate 一次换 maxUnavailable 个节点上的 Pod,换完且就绪才继续:maxUnavailable: 1 的 4 个节点花了 27.2 秒(updated/ready/unavailable 依次 1/3/1 → 1/4/0 → 2/3/1 …),maxUnavailable: 2 只要 13.9 秒。几百个节点的集群如果还是默认的 1,更新要很久。OnDelete 完全不自动换:改了模板 6 秒后 updated=0/4,手动删掉一个 Pod,重建出来的那个才用上新模板。