摘要:使用 DaemonSet 部署节点级日志、监控与网络组件,理解节点选择、污点容忍、滚动更新及与 Deployment 的职责差异。
本节学习 Kubernetes 中另一个非常重要的工作负载控制器——DaemonSet。
现在思考一个新的问题:
假设 Kubernetes 集群有 5 个 Node,每个 Node 都需要运行一个日志采集程序,用于收集本节点上所有容器的日志。
如果使用 Deployment,应该设置几个副本?
设置 5 个吗?
这样虽然可以运行 5 个 Pod,但 Deployment 并不能保证每个 Node 恰好有一个 Pod。
可能出现:
Node-1:2 个日志采集 PodNode-2:0 个日志采集 PodNode-3:1 个日志采集 PodNode-4:2 个日志采集 PodNode-5:0 个日志采集 Pod这显然不符合需求。
因此 Kubernetes 提供了 DaemonSet。
DaemonSet 的核心作用:确保所有符合条件的节点都运行一个指定的 Pod 副本。
一、DaemonSet 基本概念
1. 什么是 DaemonSet?
DaemonSet 是 Kubernetes 中用于管理节点级 Pod 的工作负载控制器。
它的核心特点:
- 每个符合条件的 Node 通常运行一个 Pod。
- 新增符合条件的 Node 时,自动创建 Pod。
- Node 不再符合条件时,相应 Pod 会被移除。
- 不需要手动设置固定副本数量。
例如:
集群有三个 Node:
DaemonSet 节点部署模型
flowchart TB
subgraph G0["Node-1"]
direction TB
N1["Agent Pod"]
end
subgraph G1["Node-2"]
direction TB
N2["Agent Pod"]
end
subgraph G2["Node-3"]
direction TB
N3["Agent Pod"]
end
N0["DaemonSet Controller<br/>负责协调节点与 Pod 的对应关系"]
N0 -.->|"协调"| N1
N0 -.->|"协调"| N2
N0 -.->|"协调"| N3
每个符合条件的节点一个 Pod
典型应用:
| 应用 | 作用 |
|---|---|
| Fluent Bit | 收集节点容器日志 |
| Node Exporter | 采集节点监控指标 |
| CNI Agent | 提供节点网络能力 |
| CSI Node Plugin | 提供节点存储能力 |
| 安全 Agent | 节点安全监控 |
2. DaemonSet 的工作原理
DaemonSet Controller 会监听:
- 集群中有哪些 Node。
- 哪些 Node 满足调度条件。
- 哪些 Node 已经存在对应 DaemonSet Pod。
- 是否有节点缺少对应 Pod。
工作流程:
flowchart TB
N0["DaemonSet Controller"]
N1["监听 Node"]
N2["判断节点是否符合条件"]
N3["创建 Pod"]
N4["不创建或移除"]
N5["节点运行 Agent"]
N0 --> N1
N1 --> N2
N2 -->|"符合"| N3
N2 -->|"不符合"| N4
N3 --> N5
例如:
原本有 3 个节点:
Node-1:Agent PodNode-2:Agent PodNode-3:Agent Pod新增 Node-4:
Node-4:自动创建 Agent Pod不需要修改 DaemonSet 的副本数量。
二、DaemonSet 与 Deployment 的区别
这是 CKA 必须掌握的知识点。
| 对比 | Deployment | DaemonSet |
|---|---|---|
| 主要用途 | 管理业务应用 | 管理节点级应用 |
| 副本数量 | 手动或自动设置 | 根据符合条件的节点决定 |
| Pod 分布 | 由调度器按约束调度 | 每个符合条件的节点一个 |
| 新增节点 | 不一定创建新 Pod | 自动创建对应 Pod |
| 节点级部署 | 不保证 | 核心功能 |
| 常见应用 | Web、API 服务 | 日志、监控、网络 Agent |
记忆:
- Deployment:我要运行几个副本。
- DaemonSet:我要在每个符合条件的节点运行一个副本。
1. 三种控制器的区别
| 控制器 | 管理目标 |
|---|---|
| Deployment | 维持指定数量的 Pod |
| StatefulSet | 维持有稳定身份的 Pod |
| DaemonSet | 维持每个符合条件节点上的 Pod |
三、DaemonSet YAML 结构
1. 创建一个 DaemonSet
新建文件:
vim daemonset.yaml编写:
apiVersion: apps/v1kind: DaemonSet
metadata: name: nginx-daemon
spec: selector: matchLabels: app: nginx-daemon
template: metadata: labels: app: nginx-daemon
spec: containers: - name: nginx image: nginx:1.27
ports: - containerPort: 80创建:
kubectl apply -f daemonset.yaml查看:
kubectl get daemonsets输出示例:
NAME DESIRED CURRENT READY UP-TO-DATEnginx-daemon 3 3 3 3注意这里没有:
replicas: 3因为 DaemonSet 不通过 replicas 控制副本数量。
2. DaemonSet 常见字段
| 字段 | 作用 |
|---|---|
| selector | 选择管理的 Pod |
| template | Pod 模板 |
| updateStrategy | 更新策略 |
| minReadySeconds | Pod Ready 后需要稳定的时间 |
| revisionHistoryLimit | 保留历史版本数量 |
和 Deployment 一样,DaemonSet 也使用:
- Selector 选择 Pod。
- Template 创建 Pod。
- Controller 协调实际状态。
四、DaemonSet 的节点选择机制
并不是所有 DaemonSet 都需要部署到集群中的所有节点。
例如:
日志采集 Agent 可能需要部署到所有 Worker Node,但不需要部署到 Control Plane Node。
这时就需要节点选择机制。
1. NodeSelector
NodeSelector 是 Kubernetes 最简单的节点选择方式。
首先给节点添加标签:
kubectl label nodes worker-1 node-type=workerkubectl label nodes worker-2 node-type=workerkubectl label nodes control-1 node-type=master查看:
kubectl get nodes --show-labels然后在 DaemonSet 中添加:
spec: template: spec: nodeSelector: node-type: worker
containers: - name: nginx image: nginx:1.27这样:
worker-1:创建 Podworker-2:创建 Podcontrol-1:不创建 Pod2. Node Affinity
如果需要更复杂的节点筛选条件,可以使用 Node Affinity。
例如:
spec: template: spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: node-type operator: In values: - worker - storage表示:
只在 node-type 为 worker 或 storage 的节点运行 Pod。
Node Affinity 常见操作符:
| Operator | 含义 |
|---|---|
| In | 标签值属于指定集合 |
| NotIn | 标签值不属于指定集合 |
| Exists | 存在指定标签 |
| DoesNotExist | 不存在指定标签 |
| Gt | 大于 |
| Lt | 小于 |
3. NodeSelector 与 Node Affinity 对比
| 对比 | NodeSelector | Node Affinity |
|---|---|---|
| 配置方式 | 简单键值匹配 | 表达式 |
| 复杂条件 | 不支持 | 支持 |
| 多条件组合 | 简单 | 灵活 |
| 软性调度偏好 | 不支持 | 支持 preferred |
| 使用场景 | 简单节点筛选 | 复杂调度策略 |
五、Taints 和 Tolerations
这是 DaemonSet 中非常重要的知识点。
NodeSelector 和 Node Affinity,它们解决的是:
Pod 希望运行在哪些节点上。
而 Taints 和 Tolerations 解决的是:
哪些节点允许 Pod 调度进去。
1. 什么是 Taint?
Taint(污点)是添加在 Node 上的一种标记,用于阻止不符合条件的 Pod 被调度到该节点。
例如:
kubectl taint nodes worker-1 dedicated=database:NoSchedule表示:
给 worker-1 添加一个污点:
dedicated=database:NoSchedule普通 Pod 如果没有对应容忍度,就不能调度到这个节点。
2. 什么是 Toleration?
Toleration(容忍度)是 Pod 上的配置。
如果 Pod 配置了与节点污点匹配的 Toleration,就可以容忍这个污点。
例如:
spec: tolerations: - key: dedicated operator: Equal value: database effect: NoSchedule这样 Pod 就可以调度到带有该污点的节点。
注意:
Toleration 只是允许 Pod 进入节点,不代表 Pod 一定会被调度到该节点。
如果还需要限定目标节点,可以配合 NodeSelector 或 Node Affinity。
3. 三种污点效果
| Effect | 含义 |
|---|---|
| NoSchedule | 不允许新的不匹配 Pod 调度到节点 |
| PreferNoSchedule | 尽量避免调度到节点 |
| NoExecute | 不仅影响新调度,还可能驱逐已经运行的不匹配 Pod |
例如:
kubectl taint nodes worker-1 dedicated=database:NoExecute如果已有 Pod 无法容忍该污点,可能被驱逐。
4. DaemonSet 为什么经常能运行在特殊节点?
DaemonSet 有一个特殊设计:
Kubernetes 创建的 DaemonSet Pod 通常会自动添加若干系统级 Toleration,以便节点级 Agent 可以运行在有特定污点的节点上。
例如 Control Plane 节点通常存在:
node-role.kubernetes.io/control-plane:NoSchedule普通 Pod 通常无法调度到该节点。
但很多 DaemonSet,例如 CNI 网络插件、节点监控组件,需要运行在 Control Plane 节点上。
因此 Kubernetes 为 DaemonSet Pod 自动添加了若干内置容忍度。
注意:这不意味着所有 DaemonSet 都能无条件运行在所有节点上。自定义污点、节点选择器、资源限制等仍可能影响部署。
六、DaemonSet 更新策略
DaemonSet 也支持应用更新。
主要有两种策略:
- RollingUpdate
- OnDelete
1. RollingUpdate
默认更新策略。
spec: updateStrategy: type: RollingUpdate当修改 DaemonSet 的 Pod 模板时,DaemonSet Controller 会逐步替换旧 Pod。
例如:
Node-1:nginx:v1Node-2:nginx:v1Node-3:nginx:v1更新为 v2:
Node-1:nginx:v2Node-2:nginx:v1Node-3:nginx:v1然后继续:
Node-1:nginx:v2Node-2:nginx:v2Node-3:nginx:v1最终:
Node-1:nginx:v2Node-2:nginx:v2Node-3:nginx:v22. maxUnavailable
DaemonSet 的滚动更新也支持 maxUnavailable。
例如:
spec: updateStrategy: type: RollingUpdate
rollingUpdate: maxUnavailable: 1表示更新期间,最多允许 1 个节点上的 DaemonSet Pod 不可用。
可以使用整数或百分比。
注意:DaemonSet 的 RollingUpdate 不支持 Deployment 的 maxSurge 配置。它主要通过控制旧 Pod 删除和新 Pod 创建来完成节点级更新。
3. OnDelete
spec: updateStrategy: type: OnDelete修改 DaemonSet 的 Pod 模板后,已有 Pod 不会自动更新。
需要手动删除旧 Pod:
kubectl delete pod <pod-name>DaemonSet Controller 会在相应节点创建新的 Pod。
4. 两种策略对比
| 对比 | RollingUpdate | OnDelete |
|---|---|---|
| 自动更新 | 是 | 否 |
| 手动删除 Pod | 不需要 | 需要 |
| 更新控制 | maxUnavailable | 人工控制 |
| 默认策略 | 是 | 否 |
七、DaemonSet 常见故障排查
1. 某些节点没有 DaemonSet Pod
执行:
kubectl get daemonset -A查看:
kubectl get pods -o wide可能原因:
- NodeSelector 不匹配。
- Node Affinity 不匹配。
- 节点存在不兼容污点。
- 节点资源不足。
- 节点不可调度。
- 镜像拉取失败。
查看节点标签:
kubectl get nodes --show-labels查看节点污点:
kubectl describe node worker-1查看 DaemonSet:
kubectl describe daemonset node-exporter -n monitoring2. DaemonSet Pod 一直 Pending
检查:
kubectl describe pod <pod-name> -n monitoring重点查看:
Events: FailedScheduling3. DaemonSet 更新失败
查看:
kubectl rollout status daemonset/node-exporter -n monitoring查看历史:
kubectl rollout history daemonset/node-exporter -n monitoring查看事件:
kubectl get events -n monitoring --sort-by=.metadata.creationTimestamp八、DaemonSet 必须掌握的命令
| 操作 | 命令 |
|---|---|
| 查看 DaemonSet | kubectl get ds -A |
| 查看详细信息 | kubectl describe ds nginx-daemon |
| 创建 DaemonSet | kubectl apply -f ds.yaml |
| 查看 Pod 分布 | kubectl get pods -o wide |
| 更新镜像 | kubectl set image ds/nginx-daemon nginx=nginx:1.28 |
| 查看更新状态 | kubectl rollout status ds/nginx-daemon |
| 查看更新历史 | kubectl rollout history ds/nginx-daemon |
| 回滚 | kubectl rollout undo ds/nginx-daemon |
| 修改配置 | kubectl edit ds nginx-daemon |
| 删除 DaemonSet | kubectl delete ds nginx-daemon |
九、本节知识总结
DaemonSet 核心知识结构
flowchart TB
subgraph G0["Node-1"]
direction TB
N1["Agent Pod"]
end
subgraph G1["Node-2"]
direction TB
N2["Agent Pod"]
end
subgraph G2["Node-3"]
direction TB
N3["Agent Pod"]
end
N0["DaemonSet Controller<br/>监控符合条件的 Node"]
N0 -.->|"协调"| N1
N0 -.->|"协调"| N2
N0 -.->|"协调"| N3
必须掌握的内容
- DaemonSet 的作用与工作原理。
- DaemonSet 和 Deployment 的区别。
- NodeSelector 与 Node Affinity。
- Taints 与 Tolerations。
- RollingUpdate 与 OnDelete。
- maxUnavailable。
- hostNetwork 与 hostPath。