K8S 之 DaemonSet

摘要

DaemonSet 介绍

  • DaemonSet 定义了提供节点本地设施的 Pod。这些设施可能对于集群的运行至关重要,例如网络辅助工具,或者作为 add-on 的一部分。

  • DaemonSet 确保全部(或者某些)节点上运行一个 Pod 的副本。 当有节点加入集群时, 也会为他们新增一个 Pod 。 当有节点从集群移除时,这些 Pod 也会被回收。删除 DaemonSet 将会删除它创建的所有 Pod。

  • DaemonSet 的一些典型用法:

    • 在每个节点上运行集群守护进程
    • 在每个节点上运行日志收集守护进程
    • 在每个节点上运行监控守护进程
  • DaemonSet 与 Deployment 的主要区别是:

    • 无法自定义副本数量
    • 每个node上都会运行且只允许运行一个 Pod
    • 当有新Node加入集群时,会自动在其上部署并运行Pod副本,当Node从集群移除时,这些Pod也会被回收

DaemonSet 管理

DaemonSet 创建

  • DaemonSet 只能 通过 yaml 创建,不支持 create 创建

1
2
# 通过 yaml 文件创建
kubectl apply -f daemonset.yaml
  • 一个简单的 daemonset.yaml 文件说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
apiVersion: apps/v1                  # 指定使用的 API 版本,这里是 apps/v1,适用于 DaemonSet 资源
kind: DaemonSet # Kubernetes 资源类型,这里是部署(DaemonSet)
metadata:
labels:
app: nginx # 标签,用于标识资源,可与 selector 匹配
name: nginx # 资源名称,必须唯一(在同一命名空间下)
spec: # 配置项
selector: # 选择器,指定要管理的 Pod
matchLabels: # 标签选择器
app: nginx # 选择器,指定 DaemonSet 管理哪些 Pod(标签必须与 template 中匹配)
updateStrategy: # 更新策略
type: RollingUpdate # RollingUpdate:这是默认的更新策略。使用 RollingUpdate 更新策略时,在更新 DaemonSet 模板后, 老的 DaemonSet Pod 将被终止,并且将以受控方式自动创建新的 DaemonSet Pod。 更新期间,最多只能有 DaemonSet 的一个 Pod 运行于每个节点上。
# OnDelete:使用 OnDelete 更新策略时,在更新 DaemonSet 模板后,只有当你手动删除老的 DaemonSet Pod 之后,新的 DaemonSet Pod 才会被自动创建。
rollingUpdate: # 滚动升级的配置
maxUnavailable: 1 # 最大不可用 Pod 的数量,这里是 1,默认值为 1
template: # 模板,定义 Pod 的内容,具体可以参考 Pod 的配置
metadata:
labels:
app: nginx # Pod 的标签,必须与 selector 中的 matchLabels 一致
spec:
containers:
- image: nginx # 容器使用的镜像,这里是官方的 nginx 镜像
name: nginx # 容器的名称

查看 DaemonSet

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 查看 DaemonSet ,默认显示 default 命名空间下的 DaemonSet
kubectl get daemonsets
kubectl get ds # 简称
# 查看 kube-system 命名空间下的 DaemonSet
kubectl get ds -n kube-system
# 查看所有命名空间下的 DaemonSet
kubectl get ds -A
# -o wide: 显示 deploy 的详细信息
kubectl get ds -o wide
# 显示 DaemonSet 的标签
kubectl get ds --show-labels
# 按 DaemonSet 的标签进程查询
kubectl get ds -l <label_name>=<label_value>
# 持续查看 DaemonSet 的状态,当 DaemonSet 状态发生改变时,会实时显示
kubectl get ds -w

# 查看 pod、ds 的详细信息
$ k get pod,ds -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/nginx-6g8j8 1/1 Running 0 9m3s 10.244.126.18 k8s-worker2 <none> <none>
pod/nginx-tnvhn 1/1 Running 0 9m3s 10.244.194.89 k8s-worker1 <none> <none>

NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE CONTAINERS IMAGES SELECTOR
daemonset.apps/nginx 2 2 2 2 2 <none> 9m3s nginx nginx app=nginx

允许 master 节点运行 pod

  • 上面看到pod只在worker1和worker2上运行,而没有在master节点上运行

  • 默认情况下,Kubernetes 不允许在 master 节点上运行 Pod,这是因为master节点有污点

1
2
$ kubectl describe node k8s-master | grep Taints
Taints: node-role.kubernetes.io/control-plane:NoSchedule
  • 为了能让pod运行在具有污点的节点上,我们需要为pod指定容忍度(tolerations),实际上 DaemonSet 控制器会自动将一组容忍度添加到 DaemonSet Pod

容忍度键名 效果 操作 描述
node.kubernetes.io/not-ready NoExecute Exists DaemonSet Pod 可以被调度到不健康或未就绪的节点上,且不会被驱逐。
node.kubernetes.io/unreachable NoExecute Exists DaemonSet Pod 可以被调度到不可达的节点上,且不会被驱逐。
node.kubernetes.io/disk-pressure NoSchedule Exists DaemonSet Pod 可以被调度到存在磁盘压力的节点上。
node.kubernetes.io/memory-pressure NoSchedule Exists DaemonSet Pod 可以被调度到存在内存压力的节点上。
node.kubernetes.io/pid-pressure NoSchedule Exists DaemonSet Pod 可以被调度到存在进程数压力的节点上。
node.kubernetes.io/unschedulable NoSchedule Exists DaemonSet Pod 可以被调度到标记为不可调度的节点上。
node.kubernetes.io/network-unavailable NoSchedule Exists 针对 spec.hostNetwork: true 的 Pod,可以被调度到网络不可用的节点上。
  • 增加可以运行在 master 节点的容忍度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
apiVersion: apps/v1
kind: DaemonSet
metadata:
labels:
app: nginx
name: nginx
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
tolerations: # 增加容忍度
- key: "node-role.kubernetes.io/control-plane" # 容忍控制平面节点
operator: "Exists" # 操作符
effect: "NoSchedule" # 污点标签
containers:
- image: nginx
name: nginx
  • 增加容忍度后重新运行

1
2
3
4
5
6
7
8
9
10
11
kubectl apply -f daemonset.yaml

# 查看
$ k get pod,ds -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/nginx-4gxwh 1/1 Running 0 79m 10.244.235.205 k8s-master <none> <none>
pod/nginx-gx7tf 1/1 Running 0 78m 10.244.126.21 k8s-worker2 <none> <none>
pod/nginx-sl8cc 1/1 Running 0 78m 10.244.194.92 k8s-worker1 <none> <none>

NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE CONTAINERS IMAGES SELECTOR
daemonset.apps/nginx 3 3 3 3 3 <none> 3h42m nginx nginx app=nginx

访问pod中的nginx服务

  • 此时我们还没有创建 Service(后面章节会介绍),所以只能通过 Pod 的 IP 访问

1
2
# 任意pod的IP,端口80
curl http://10.244.194.92

查看 DaemonSet 详情

  • 当 DaemonSet 运行错误时,可以通过该命令查看 DaemonSet 的详情,找到错误原因

1
2
kubectl describe ds <ds-name>
kubectl describe ds <ds-name> -n <namespace-name>

删除 DaemonSet

1
2
3
4
5
kubectl delete ds <ds-name>
kubectl delete ds <ds-name> -n <namespace-name>

# 通过 yaml 文件删除
kubectl delete -f <yaml-file>

查看 DaemonSet 日志

1
2
kubectl logs ds/<ds-name>
kubectl logs ds/<ds-name> -n <namespace-name>

滚动升级与回滚 DaemonSet

  • RollingUpdate 类型的 DaemonSet.spec.template 的任何更新都将触发滚动更新。

  • 我们修改过 DaemonSet.spec.template,并保存后,重新运行 kubectl apply -f <yaml-file>即可触发滚动升级。

  • 如果只是更新容器的镜像,也可以通过如下命令触发滚动升级

1
2
# kubectl set image ds/<ds-name> <container-name>=<image>:<tag> --record=true
kubectl set image ds nginx nginx=nginx:1.9.1 --record=true
  • 查看滚动升级状态

1
2
# kubectl rollout status ds/<ds-name>
kubectl rollout status ds nginx
  • 查看历史版本

1
2
3
4
# 前面的序号表示版本号
kubectl rollout history ds nginx
# 查看指定版本的详情
kubectl rollout history ds nginx --revision=1
  • 回滚

1
2
3
4
# 回退到前一个版本
kubectl rollout undo ds nginx
# 回到指定版本,这里 --to-revision=1 表示回到版本1
kubectl rollout undo ds nginx --to-revision=1

Deployment 和 DaemonSet 的对比总结

特性 Deployment DaemonSet
用途 管理一组可水平扩展的 Pod,按需副本数运行 在每个(或特定)节点上运行 一个副本 的 Pod
常见场景 无状态服务、Web 服务、API、后端服务 日志采集(如 fluentd)、监控(如 node-exporter)、系统守护进程
副本控制 可通过 spec.replicas 灵活控制副本数 每个匹配的节点自动运行一个 Pod,无需设置 replicas
节点分布 Pod 分布随机,调度器选择可用节点 Pod 分布固定,每个匹配节点必跑一个 Pod
更新策略 RollingUpdate(默认)、Recreate,支持回滚 RollingUpdate(默认从 Kubernetes 1.6 起支持)
伸缩方式 kubectl scale deployment 可以水平扩缩容 不支持手动伸缩,跟随节点变化自动伸缩
Pod 更新行为 按策略滚动更新全部副本 每个节点上的 Pod 逐个滚动更新
调度策略 通过调度器分配节点,可搭配 affinity 使用 默认调度所有节点,可用 nodeSelectoraffinitytaints 控制