一、DaemonSet 控制器:概念、原理解读
1.1 什么是 DaemonSet?
DaemonSet 是 Kubernetes 中的一个工作负载控制器,用于确保集群中的每个节点上都运行一个指定的 Pod 副本。
核心行为:
- 节点加入:当新节点加入集群时,DaemonSet 会自动在新节点上创建 Pod
- 节点删除:当节点被删除时,对应的 Pod 会被回收
- 节点移除:当节点被从集群中移除时,其上的 DaemonSet Pod 也会被清理
1.2 工作原理
DaemonSet 控制器通过以下机制实现其功能:
- 监听 API Server:实时获取当前集群的节点列表
- 对比状态:将当前节点列表与已创建的 Pod 进行对比
- 自动调度:发现某个节点上没有对应的 Pod 时,通过调度器(或直接指定节点)创建 Pod
关键特性:
- 每个节点有且只有一个该 DaemonSet 管理的 Pod(默认行为)
- Pod 的名称由 DaemonSet 自动生成,格式为
<daemonset-name>-<随机后缀> - 当节点标签变化导致不再匹配 selector 时,Pod 会被自动删除
1.3 应用场景
节点守护类(每个节点都需要运行的组件)
| 类别 | 典型组件 |
|---|---|
| 日志收集 | Fluentd、Filebeat、Logstash |
| 监控代理 | Prometheus Node Exporter、Datadog Agent、Zabbix Agent |
| 网络插件 | Calico、Flannel、Cilium 的 Agent 组件 |
| 存储插件 | CSI(Container Storage Interface)节点驱动 |
| 安全扫描 | Falco、Sysdig、Aqua Agent |
系统服务类
| 组件 | 说明 |
|---|---|
| kube-proxy | 每个节点都需要运行,实现 Service 的网络代理 |
| Calico | 网络插件,提供跨节点 Pod 通信能力 |
| 节点网络配置 | 如 Macvlan、Multus 等 CNI 插件 |
为什么 DaemonSet 适合这些场景?
- 日志收集需要在每个节点上采集所有容器的日志
- 监控代理需要采集每个节点的系统指标
- 网络插件需要在每个节点上配置网络规则和路由
- 存储驱动需要在每个节点上挂载存储卷
二、DaemonSet 使用案例
2.1 每个节点上部署日志采集(Fluentd)
完整 YAML 示例
[root@hd1 ~]# cat daemonset.yamlapiVersion:apps/v1kind:DaemonSetmetadata:name:fluentd-elasticsearchnamespace:kube-system# 部署在 kube-system 命名空间(与系统组件统一管理)labels:k8s-app:fluentd-loggingspec:selector:matchLabels:name:fluentd-elasticsearchtemplate:#pod模板metadata:labels:# Pod 标签,必须被 selector 匹配name:fluentd-elasticsearchspec:tolerations:-key:node-role.kubernetes.io/control-plane# 针对 master/control-plane 节点的污点effect:NoSchedule# 允许 Pod 调度到有该污点的节点上containers:-name:fluentd-elasticsearchimage:docker.io/library/fluentd:v2.5.1imagePullPolicy:IfNotPresentresources:#容器的资源限制limits:memory:200Mirequests:cpu:100mmemory:200MivolumeMounts:#挂载点-name:varlog# 引用下方 volumes 中定义的卷mountPath:/var/log# 挂载到容器内的 /var/log 目录terminationGracePeriodSeconds:30#优雅终止时间volumes:#存储卷定义-name:varlog# 卷名称(被 volumeMounts 引用)hostPath:path:/var/log# 宿主机上的 /var/log 目录,该目录下包含了所有容器和系统组件的日志文件YAML 完整字段解析
| 字段 | 说明 |
|---|---|
kind: DaemonSet | 资源类型,表示为 DaemonSet 控制器 |
namespace: kube-system | 通常部署在系统命名空间,与系统组件统一管理 |
selector.matchLabels | 标签选择器,用于匹配 DaemonSet 管理的 Pod |
template | Pod 模板,定义要部署的 Pod 规格 |
tolerations | 容忍度配置,允许调度到控制平面节点(master 节点) |
resources | 资源限制,保证日志采集不占用过多资源 |
volumeMounts | 挂载宿主机的/var/log目录到容器中,采集容器日志 |
hostPath | 使用宿主机路径挂载,直接读取节点上的日志文件 |
# ============================================================# DaemonSet:在每个节点上部署 Fluentd 日志采集器# ============================================================apiVersion: apps/v1 kind: DaemonSet metadata: name: fluentd-elasticsearch# DaemonSet 名称namespace: kube-system# 部署在 kube-system 命名空间(与系统组件统一管理)labels: k8s-app: fluentd-logging# 便于通过标签筛选该 DaemonSetspec:# ---------- 标签选择器 ----------selector: matchLabels: name: fluentd-elasticsearch#必须与 template.metadata.labels 保持一致# 否则 Kubernetes 拒绝创建# ---------- Pod 模板 ----------template: metadata: labels: name: fluentd-elasticsearch# Pod 标签,必须被 selector 匹配spec:# ---------- 容忍度(允许调度到 master 节点) ----------tolerations: - key: node-role.kubernetes.io/control-plane# 针对 master/control-plane 节点的污点effect: NoSchedule# 允许 Pod 调度到有该污点的节点上# 让日志采集器也能采集 master 节点的日志# ---------- 容器定义 ----------containers: - name: fluentd-elasticsearch image: docker.io/library/fluentd:v2.5.1 imagePullPolicy: IfNotPresent# 镜像拉取策略:本地存在则不拉取# ---------- 资源限制 ----------resources: limits: memory: 200Mi# 最大可用内存 200Mi(防止日志采集占用过多资源)requests: cpu: 100m# 保证至少 0.1 核 CPUmemory: 200Mi# 保证至少 200Mi 内存# ---------- 挂载点 ----------volumeMounts: - name: varlog# 引用下方 volumes 中定义的卷mountPath: /var/log# 挂载到容器内的 /var/log 目录# 这样 Fluentd 就能读取宿主机上所有容器的日志文件# ---------- 优雅终止时间 ----------terminationGracePeriodSeconds:30# Pod 收到 SIGTERM 信号后,最多等待 30 秒# 让 Fluentd 有机会将缓冲区中的日志发送完毕再退出# ---------- 存储卷定义 ----------volumes: - name: varlog# 卷名称(被 volumeMounts 引用)hostPath:# hostPath 类型:挂载宿主机的目录path: /var/log# 宿主机上的 /var/log 目录# 该目录下包含了所有容器和系统组件的日志文件部署与验证
[root@hd1 ~]# kubectl apply -f daemonset.yamldaemonset.apps/fluentd-elasticsearch created# 查看 DaemonSet 状态,需要指定命名空间[root@hd1 ~]# kubectl get ds -n kube-systemNAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE fluentd-elasticsearch33333<none>23m# 查看 Pod 在各节点的分布情况[root@hd1 ~]# kubectl get pods -n kube-system -o wide | grep fluentdfluentd-elasticsearch-d22wn1/1 Running022m10.244.59.173 hd2 fluentd-elasticsearch-pmqzx1/1 Running022m10.244.169.95 hd3 fluentd-elasticsearch-tm8rz1/1 Running022m10.244.66.67 hd1验证要点:每个节点上正好运行一个 Fluentd Pod,数量和节点数一致。
2.2 DaemonSet 滚动更新
DaemonSet 支持两种更新策略:
| 策略 | 说明 | 适用场景 |
|---|---|---|
| RollingUpdate(默认) | 各个节点逐步替换 Pod(先删旧 Pod,再建新 Pod),可配置maxUnavailable控制同时不可用的 Pod 数量(例如 10% 或 1 个) | 生产环境,需要平滑升级 |
| OnDelete | 只有当用户手动删除旧的 Pod 时,才会创建新版本的 Pod | 需要精细控制更新节奏的场景 |
查看更新策略定义
[root@hd1 ~]# kubectl explain ds.spec.updateStrategyFIELDS: rollingUpdate<Object>type<string># 查看 rollingUpdate 支持的参数[root@hd1 ~]# kubectl explain ds.spec.updateStrategy.rollingUpdateFIELDS: maxUnavailable<string># 可以指定为数字或百分比更新策略的工作机制
由于 DaemonSet 保证每个节点最多运行一个 Pod,因此滚动更新时采用“先删后建”的策略:
- 先删除旧 Pod
- 等待旧 Pod 完全终止
- 再创建新 Pod
这与 Deployment 的滚动更新(先建新 Pod,再删旧 Pod)不同,因为节点资源限制不允许两个 Pod 同时存在。
三、系统自动污点与 DaemonSet 特殊容忍度(Tolerations)
3.1 什么是污点和容忍度?
| 概念 | 说明 |
|---|---|
| 污点(Taint) | 标记在节点上的属性,用于排斥Pod 调度到该节点 |
| 容忍度(Toleration) | 标记在 Pod 上的属性,允许 Pod 被调度到具有特定污点的节点上 |
关系:节点有污点,Pod 有容忍度才能调度上去。容忍度是 Pod 对节点污点的“免疫”声明。
3.2 节点自动污点(系统污点)
Kubernetes 集群会在节点出现特定问题时,由节点控制器(Node Controller)或kubelet自动为其添加污点,用于标记节点状态,从而触发 Pod 的驱逐或阻止新 Pod 调度。这是一种保障集群整体稳定性的自愈机制。
常见的系统自动污点
| 污点名(Taint) | 触发条件(Node Condition) | 效果(Effect) | 主要触发组件 |
|---|---|---|---|
node.kubernetes.io/not-ready | 节点未就绪(Ready=False) | NoExecute | 节点控制器 |
node.kubernetes.io/unreachable | 节点无法访问(Ready=Unknown) | NoExecute | 节点控制器 |
node.kubernetes.io/memory-pressure | 节点内存有压力 | NoSchedule | kubelet |
node.kubernetes.io/disk-pressure | 节点磁盘有压力 | NoSchedule | kubelet |
node.kubernetes.io/pid-pressure | 节点PID有压力 | NoSchedule | kubelet |
node.kubernetes.io/network-unavailable | 节点网络不可用 | NoSchedule | kubelet / 云厂商控制器 |
node.kubernetes.io/unschedulable | 节点被标记不可调度(kubectl cordon) | NoSchedule | kubectl / 控制器 |
node.kubernetes.io/out-of-disk | 节点磁盘空间已满 | NoSchedule | kubelet |
node.cloudprovider.kubernetes.io/uninitialized | 节点刚启动,未完成初始化 | NoSchedule | kubelet(外部云环境) |
3.3 污点效果(Effect)说明
| 效果 | 说明 |
|---|---|
NoSchedule | 阻止新的 Pod 调度到该节点,但不影响已在运行的 Pod |
NoExecute | 不仅阻止新 Pod 调度,还会驱逐节点上已运行且没有对应容忍度的 Pod |
PreferNoSchedule | 软性限制,尽量避免调度到该节点,但无法避免时也会调度 |
3.4 普通 Pod 的默认容忍度
Kubernetes 会为每个 Pod自动添加对以下污点的容忍度(默认 300 秒):
| 污点 | 容忍时间 |
|---|---|
node.kubernetes.io/not-ready | 300 秒 |
node.kubernetes.io/unreachable | 300 秒 |
设计目的:当节点出现短暂网络问题(5 分钟内恢复)时,上面的 Pod 不会被立即驱逐,避免了因网络抖动而引发的大规模 Pod 重调度。
生效逻辑:
- 节点在 300 秒内恢复 → Pod 继续运行,无感知
- 节点超过 300 秒未恢复 → Pod 被驱逐,调度到其他健康节点
3.5 DaemonSet Pod 的特殊容忍度
DaemonSet 管理的 Pod 天生对这些节点问题污点具有无限(无穷大)的容忍时间,因此:
- 节点失联时:DaemonSet Pod 不会被驱逐
- 目的:确保节点出现故障时,日志收集、监控、网络代理等系统级组件依然能够工作(例如:即使节点处于
NotReady状态,Fluentd 依然能收集已有的日志并尝试发送)
关键区别:
- 普通 Deployment Pod:节点失联 300 秒后被驱逐
- DaemonSet Pod:节点失联后无限等待,不驱逐
四、Pod 优先级(QoS Class)
4.1 什么是 QoS(Quality of Service)?
QoS(Quality of Service,服务质量)是 Kubernetes 对 Pod 资源请求(requests)和限制(limits)的分类机制,用于在资源压力较大时决定 Pod 的驱逐优先级(哪些 Pod 优先被杀死以释放资源)。
4.2 QoS 等级对比
QoS 等级不是一个你可以手动设置的字段,而是由 Kubernetes 根据 Pod 里的resources.requests和resources.limits字段自动计算出来的标签
| 等级(QoS) | 保证程度 | 驱逐优先级(高压力下) | 典型使用场景 | 判定标准(Pod 内所有容器需满足) |
|---|---|---|---|---|
| Guaranteed(保证) | 最高保证:资源完全隔离,性能最稳定 | 最低:最后被驱逐 | 核心关键业务:数据库、支付、订单服务等 | 所有容器同时满足: 1. 都设置了 requests和limits2. 所有 requests和limits的值都相等3. requests值必须大于 0 |
| Burstable(可突发) | 部分保证:保证requests,额外资源尽力而为 | 中等:在 BestEffort 之后被驱逐 | 常规在线业务:大部分微服务,能容忍小幅资源竞争 | 1. 不满足 Guaranteed 的条件 2.至少一个容器设置了 requests或limits |
| BestEffort(尽力而为) | 无任何保证:资源紧缺时最脆弱 | 最高:最先被驱逐 | 低优先级批处理任务:测试环境、数据处理、离线分析等 | Pod 内所有容器均未设置requests和limits |
4.3 QoS 判定规则(关键原则)
最严格容器决定 Pod 等级:一个 Pod 包含多个容器时,取最严格的等级作为整个 Pod 的 QoS 等级
- 如果有一个容器是
BestEffort,整个 Pod 就是BestEffort - 如果有容器是
Guaranteed,也有容器是Burstable,整个 Pod 就是Burstable
- 如果有一个容器是
资源单位说明:
m:毫核,千分之一核心,例如200m= 0.2 个 CPU 核心Mi:Mebibyte(二进制写法,兆比字节),例如200Mi= 200 × 1024 × 1024 字节
4.4 QoS 示例
Guaranteed Pod
[root@hd1 ~]# cat pod-guaranteed.yamlapiVersion:v1kind:Podmetadata:name:"my-guaranteed"labels:app:"mynginx"spec:containers:-name:mycontainersimage:"docker.io/library/nginx:latest"imagePullPolicy:IfNotPresentresources:#资源限制字段,limits:cpu:"200m"memory:200Mirequests:cpu:"200m"# 与 limits.cpu 相等memory:200Mi# 与 limits.memory 相等判定:requests=limits,且均大于 0 →Guaranteed(保证)
#应用[root@hd1 ~]# kubectl apply -f my-guaranteed.yamlpod/my-guaranteede created# 查看 Pod 的 QoS 等级[root@hd1 ~]# kubectl describe pod my-guaranteed | grep -i QosQoS Class: GuaranteedBurstable Pod
[root@hd1 ~]# cat pod-burstable.yamlapiVersion:v1kind:Podmetadata:name:"my-burstable"labels:app:"mynginx"spec:containers:-name:mycontainersimage:"docker.io/library/nginx:latest"imagePullPolicy:IfNotPresentresources:limits:cpu:"300m"memory:300Mirequests:cpu:"200m"# 与 limits.cpu 不相等memory:200Mi# 与 limits.memory 不相等判定:不满足 Guaranteed 条件,且有 requests 设置 →Burstable(可突发)
#应用[root@hd1 ~]# kubectl apply -f pod-burstable.yamlpod/my-burstable created# 查看 Pod 的 QoS 等级[root@hd1 ~]# kubectl describe pod my-burstable | grep -i QosQoS Class: BurstableBestEffort Pod
[root@hd1 ~]# cat pod-besteffort.yamlapiVersion:v1kind:Podmetadata:name:"my-besteffort"labels:app:"mynginx"spec:containers:-name:mycontainersimage:"docker.io/library/nginx:latest"imagePullPolicy:IfNotPresent# 没有 resources 设置判定:所有容器均未设置requests和limits→BestEffort
#应用[root@hd1 ~]# kubectl apply -f pod-besteffort.yamlpod/my-besteffort created# 查看 Pod 的 QoS 等级[root@hd1 ~]# kubectl describe pod my-besteffort | grep -i QosQoS Class: BestEffort4.5 驱逐顺序总结(由低到高)
资源压力增大时驱逐顺序: Last Evicted ←───────────────────────────→ First Evicted ↑ ↑ Guaranteed BestEffort (最稳定) (最脆弱)| 驱逐优先级 | QoS 等级 | 说明 |
|---|---|---|
| 最低(最后被驱逐) | Guaranteed | 核心业务,必须保障 |
| 中等 | Burstable | 常规业务,适当保障 |
| 最高(最先被驱逐) | BestEffort | 非核心任务,随时可牺牲 |
五、核心知识点速查
DaemonSet 核心要点
| 知识点 | 说明 |
|---|---|
| 定义 | 确保每个节点运行一个 Pod 副本 |
| 自动调度 | 新节点加入 → 自动创建 Pod;节点删除 → 自动回收 Pod |
| 应用场景 | 日志收集(Fluentd)、监控代理(Node Exporter)、网络插件(Calico)、存储驱动(CSI) |
| 更新策略 | RollingUpdate(默认,逐步替换)和OnDelete(手动触发) |
| 节点故障容忍 | DaemonSet Pod 对节点问题污点具有无限容忍,不会被驱逐 |
污点与容忍度要点
| 知识点 | 说明 |
|---|---|
| 污点 | 节点排斥 Pod 的机制 |
| 容忍度 | Pod 允许调度到有污点节点的机制 |
| 系统自动污点 | 节点出现NotReady、MemoryPressure等问题时自动添加 |
| 普通 Pod 默认容忍 | not-ready和unreachable容忍 300 秒 |
| DaemonSet Pod 容忍 | 无限容忍,节点故障时不驱逐 |
QoS 要点
| 知识点 | 说明 |
|---|---|
| Guaranteed | requests=limits,最高保障,最后被驱逐 |
| Burstable | requests<limits或只设其一,中等保障 |
| BestEffort | 不设requests和limits,最低保障,最先被驱逐 |
| 驱逐顺序 | BestEffort → Burstable → Guaranteed |
| 判定原则 | 最严格的容器决定整个 Pod 的 QoS 等级 |