一文读懂DaemonSet以及实践攻略
目录
❤️ 摘要: 在 Kubernetes 集群中,DaemonSet 是用于在每个(或特定)节点上运行一个 Pod 副本的控制器。通常情况下,DaemonSet 用于部署集群中的基础服务,如日志收集、监控代理、网络插件等。这些服务需要在每个节点上运行,以确保对整个集群的全面覆盖和管理。这篇博客会带着读者将详细了解 DaemonSet 的核心概念、适用场景,并展示如何通过实际案例来创建和管理 DaemonSet。
❤️ 如果想对比Deployment、StatefulSet、DaemonSet三种工作负载,可以浏览相关文章。《一文读懂Deployment以及实践攻略》、《一文读懂StatefulSet以及实践攻略》
1 概念
1.1 什么是DaemonSet
DaemonSet 是 Kubernetes 中的一种常见控制器,会规定在每个(或特定)节点上都运行一个或几个 同样Pod 。想象一下,你是一名Kubernetes小镇的管理员,你的职责是确保每个Node街区居民都能收到邮件。为了完成这个任务,你需要一个DaemonSet邮件分派系统,这个系统会自动给小镇中的每一街区安排一个Pod邮递员,不管小镇以后扩建了多少新街区,都会有新的Pod邮递员分派到该街区完成派件任务。
1.2 DaemonSet 的工作机制
DaemonSet 的核心功能是确保指定 Pod 在集群中的每个节点上都运行一个副本,当有新节点加入时,DaemonSet 会自动在新节点上调度一个 Pod 副本,并确保其正常运行。当节点从集群中删除时,这些 Pod 就会被垃圾收集。
DaemonSet 具备以下特性:
- 自动部署到新节点:当集群中有新的节点加入时,DaemonSet 自动在该节点上运行指定的 Pod 副本。
- 支持特定节点:可以通过节点选择器(NodeSelector)或节点亲和性(NodeAffinity)指定 DaemonSet 仅在某些节点上运行。
- 独立管理和更新:可以独立管理和更新集群中的系统服务,而不影响应用层的服务。
1.3 适用场景
DaemonSet 主要用于需要在每个节点上运行相同任务的场景,例如:
- 日志收集器:如 Fluentd、Filebeat,用于在每个节点上收集日志。
- 监控代理:如 Prometheus Node Exporter,用于在每个节点上收集监控数据。
- 网络插件:如 Calico、Weave 等,负责网络的配置和管理。
- 存储系统:如 Ceph 或 GlusterFS 的代理进程,用于在每个节点上进行存储管理。
1.4 DaemonSet 与 Deployment 的区别
DaemonSet 与 Deployment 是类似的,都会创建非终止性 Pod,而DaemonSet 与 Deployment 的主要区别在于它确保在每个节点上运行一个副本,则Deployment 的副本数是固定的,并且可以分布在任意节点上。以下的特点对比:
特性 | DaemonSet | Deployment |
---|---|---|
副本数 | 每个节点一个副本(可以是所有节点或指定节点)。 | 副本数是固定的,并分布在任意节点。 |
Pod 分布 | 自动在每个(或特定)节点上创建 Pod。 | 根据调度器在节点上分布 Pod。 |
主要用途 | 集群范围内的系统服务(监控、日志收集等)。 | 无状态或有状态的应用服务。 |
此外,官方也给出其他替代DaemonSet的方法,作为了解:
- Init 脚本:
- 通过传统的系统服务管理工具(如
init
、systemd
)在每个节点上启动守护进程。这是 DaemonSet 的传统替代方式,但与 Kubernetes 的 Pod 管理工具(如kubectl
)集成度较低。使用 DaemonSet 能获得更好的监控和日志管理,还可以利用容器的资源隔离特性。
- 通过传统的系统服务管理工具(如
- 裸 Pod:
- 可以直接创建固定在某个节点上的 Pod,但这种方式缺少 DaemonSet 的自愈能力。比如当节点故障或进行维护时,裸 Pod 不会自动重新调度到其他节点,而 DaemonSet 会自动管理这些场景。
- 静态 Pod:
- 静态 Pod 是由 Kubelet 直接管理的 Pod,通常用于集群启动时的场景。它们不依赖 Kubernetes API,也不能通过
kubectl
管理。尽管静态 Pod 有一定的用例,但未来可能会被弃用。
- 静态 Pod 是由 Kubelet 直接管理的 Pod,通常用于集群启动时的场景。它们不依赖 Kubernetes API,也不能通过
1.5 DaemonSet的通信模式
目前官方给出几种与 DaemonSet 中的 Pod 进行通信的常见模式:
- Push(推送模式):
- DaemonSet 中的 Pod 被配置为将信息推送到另一个服务(如数据库)。这种模式下,DaemonSet 的 Pod 是主动发送信息的,类似于Fluentd 收集日志并推送到 Elasticsearch,不需要其他客户端直接与这些 Pod 交互。
- NodeIP 和已知端口:
- DaemonSet 中的 Pod 可以通过
hostPort
暴露端口,这样每个节点上的 Pod 就能通过节点的 IP 和指定的端口直接访问。例如Prometheus 的 Node Exporter 通过节点 IP 和端口进行访问并收集每个节点的资源利用率数据。
- DaemonSet 中的 Pod 可以通过
- DNS:
- 使用无头服务(headless service)来为 DaemonSet Pod 提供 DNS 发现。客户端可以通过 Kubernetes 的
endpoints
资源或 DNS 中的多个 A 记录来发现并与这些 Pod 进行通信。无头服务不创建 Cluster IP,而是直接通过 Pod 的 IP 进行通信。
- 使用无头服务(headless service)来为 DaemonSet Pod 提供 DNS 发现。客户端可以通过 Kubernetes 的
- Service(服务):
- 通过 Kubernetes 服务来访问 DaemonSet 中的 Pod。服务会随机选择一个 Pod 来处理请求,这意味着客户端不能选择具体的节点进行访问。这种模式适合不依赖于节点的具体性,更多地关注负载均衡的场景。
2 实践案例:部署和更新 Fluentd 日志收集器
以下是如何通过 DaemonSet 来部署一个 Fluentd 日志收集器的案例,它会在每个 Kubernetes 节点上运行,用于收集节点和应用的日志数据。
2.1 部署Fluentd DaemonSet
2.1.1 定义Fluentd DaemonSet
首先,定义一个Fluent的配置文件,后续将该配置挂载到pod上。
apiVersion: v1
kind: ConfigMap
metadata:
name: fluentd-config
data:
fluent.conf: |
<source>
@type tail
path /var/log/*.log
pos_file /var/log/td-agent/var_log.pos
tag var.log.*
<parse>
@type none
</parse>
</source>
<source>
@type tail
path /var/lib/docker/containers/*/*.log
pos_file /var/log/td-agent/docker_containers.pos
tag docker.containers.*
<parse>
@type json
</parse>
</source>
我们再定义一个 DaemonSet,确保 Fluentd 能在每个节点上部署并运行:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd
labels:
app: fluentd
spec:
selector:
matchLabels:
app: fluentd
template:
metadata:
labels:
app: fluentd
spec:
containers:
- name: fluentd
image: harbor.zx/hcie/fluentd:v3.4.0
volumeMounts:
- name: varlog
mountPath: /var/log
readOnly: true
- name: varlibdockercontainers
mountPath: /var/lib/docker/containers
readOnly: true
- name: config-volume
mountPath: /etc/fluent/config.d/fluent.conf
subPath: fluent.conf
volumes:
- name: varlog
hostPath:
path: /var/log
- name: varlibdockercontainers
hostPath:
path: /var/lib/docker/containers
- name: config-volume
configMap:
name: fluentd-config
❔ 参数说明: fluent的每个pod都挂载两个主机卷做volume
- varlog:是节点路径/var/log,存放当前节点的系统日志和应用日志。
- varlibdockercontainers: 是节点路径/var/lib/docker/containers,存在当前节点所有运行Containerd的日志和配置文件。
- config-volume: 是fluent的配置文件
- fluent对这两个目录权限是只读权限。
2.1.2 部署 DaemonSet
执行以下命令将定义的 DaemonSet 部署到 Kubernetes 集群中:
kubectl apply -f fluentd-configmap.yaml
kubectl apply -f fluentd-daemonset.yaml
2.1.3 验证 DaemonSet 部署
你可以通过以下命令查看 DaemonSet 的 Pod 状态:
kubectl get pods -l app=fluentd
输出将显示 Fluentd Pod 在每个节点上的分布情况:
NAME READY STATUS RESTARTS AGE
fluentd-lhjbn 1/1 Running 0 6m4s
fluentd-m58wd 1/1 Running 0 6m4s
fluentd-p979h 1/1 Running 0 6m4s
fluentd-qjq29 1/1 Running 0 6m4s
fluentd-rz7q8 1/1 Running 0 6m5s
也可以通过以下命令查看 DaemonSet 的 状态:
kubectl get ds -l app=fluentd
输出将显示 Fluentd DaemonSet总体情况:
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
fluentd 5 5 5 5 5 <none> 6m24s
2.1.4 验证日志收集
检查 Fluentd 是否在正确收集日志数据。你可以查看 Fluentd Pod 的日志来确认:
kubectl logs fluentd-abc12
日志输出将显示 Fluentd 成功从 /var/log
和 /var/lib/docker/containers
中收集日志数据。
2024-09-19 08:20:59 +0000 [info]: #0 starting fluentd worker pid=17 ppid=1 worker=0
2024-09-19 08:20:59 +0000 [error]: #0 unexpected error error_class=Errno::EROFS error="Read-only file system @ dir_s_mkdir - /var/log/td-agent"
2024-09-19 08:20:59 +0000 [error]: #0 /usr/local/lib/ruby/2.7.0/fileutils.rb:247:in `mkdir'
2024-09-19 08:20:59 +0000 [error]: #0 /usr/local/lib/ruby/2.7.0/fileutils.rb:247:in `fu_mkdir'
2024-09-19 08:20:59 +0000 [error]: #0 /usr/local/lib/ruby/2.7.0/fileutils.rb:228:in `block (2 levels) in mkdir_p'
2024-09-19 08:20:59 +0000 [error]: #0 /usr/local/lib/ruby/2.7.0/fileutils.rb:226:in `reverse_each'
2024-09-19 08:20:59 +0000 [error]: #0 /usr/local/lib/ruby/2.7.0/fileutils.rb:226:in `block in mkdir_p'
2.2 配置节点选择器(可选)
如果你希望 Fluentd 只运行在特定的节点上,可以为 DaemonSet 添加节点选择器。比如我们想让 Fluentd 只运行在标签为 logging=true
的节点上:
spec:
template:
spec:
nodeSelector:
logging: "true"
或者使用节点亲和性与容忍度(Taints & Tolerations),可以将DaemonSet只部署在控制平面的节点上:
tolerations:
# these tolerations are to have the daemonset runnable on control plane nodes
# remove them if your control plane nodes should not run pods
- key: node-role.kubernetes.io/control-plane
operator: Exists
effect: NoSchedule
- key: node-role.kubernetes.io/master
operator: Exists
effect: NoSchedule
❔ 说明: 关于节点亲和度和容忍度在后续文章详细说明。
2.3 资源限制(可选)
每个 运行的DaemonSet Pod 都会消耗节点的资源,确保为其分配足够的 CPU 和内存,避免影响应用的正常运行。
如果要对pod进行资源的配额和限制,可以添加以下参数:
containers:
- name: fluentd-elasticsearch
image: quay.io/fluentd_elasticsearch/fluentd:v2.5.2
resources:
limits:
memory: 200Mi
requests:
cpu: 100m
memory: 200Mi
❔ 说明: 关于pod的资源QOS在后续文章详细说明。
2.4 更新DaemonSet
2.4.1 更新策略
DaemonSet的更新策略与StatefulSet的一致,支持OnDelete
和RollingUpdate
两种类型。
- 设置更新策略为
OnDelete
, DaemonSet控制器不会自动更新 Pod。用户必须手动删除 Pod ,控制器会对 按DaemonSet 的.spec.template
更新的内容创建新 Pod。 - 设置更新策略为
RollingUpdate
,DaemonSet会控制Pod的生命周期,按照更新的模板和更新策略参数自动完成更新流程。以下是更新策略参数说明:
参数 | 说明 | 可能值 |
---|---|---|
.spec.updateStrategy.rollingUpdate.partition | 控制平面会在 Pod 准备就绪后继续等待该时间,然后再继续。如果应用启动还要加载第三方组件等, 建议设置该值,或者使用就绪探针。 | 默认是0s |
.spec.updateStrategy.rollingUpdate.maxSurge | 指定在更新期间可以拥有更新的 DaemonSet pod的数量,可以是数值或者百分数,与maxUnavailable 互斥 | 该字段适用于0到replicas - 1,默认是0 |
.spec.updateStrategy.rollingUpdate.maxUnavailable | 指定以下参数来控制更新期间不可用的最大 Pod 数量,可以是数值或者百分数,与maxSurge 互斥 | 该字段适用于0到replicas - 1范围内的所有 Pod,默认是1 |
2.4.2 查看更新策略
我们沿用上面部署的daemonSet例子,执行以下命令查看默认策略:
kubectl get ds/fluentd -o go-template='{{.spec.updateStrategy.type}}{{"\n"}}'
输出如下:
RollingUpdate
2.4.3 更新DaemonSet镜像
kubectl set image ds/fluentd fluentd=harbor.zx/hcie/fluentd:v4.6
2.4.4 查看滚动更新状态
kubectl rollout status ds/fluentd
更新完成后,输出类似于以下内容:
Waiting for daemon set "fluentd" rollout to finish: 1 out of 5 new pods have been updated...
Waiting for daemon set "fluentd" rollout to finish: 1 out of 5 new pods have been updated...
Waiting for daemon set "fluentd" rollout to finish: 2 out of 5 new pods have been updated...
Waiting for daemon set "fluentd" rollout to finish: 2 out of 5 new pods have been updated...
Waiting for daemon set "fluentd" rollout to finish: 2 out of 5 new pods have been updated...
Waiting for daemon set "fluentd" rollout to finish: 3 out of 5 new pods have been updated...
Waiting for daemon set "fluentd" rollout to finish: 3 out of 5 new pods have been updated...
Waiting for daemon set "fluentd" rollout to finish: 4 out of 5 new pods have been updated...
Waiting for daemon set "fluentd" rollout to finish: 4 out of 5 new pods have been updated...
Waiting for daemon set "fluentd" rollout to finish: 4 of 5 updated pods are available...
daemon set "fluentd" successfully rolled out
查看更新后的daemonSet信息
[root@k8s-master1 hcie]# kubectl describe ds
Name: fluentd
Selector: app=fluentd
Node-Selector: <none>
Labels: app=fluentd
Annotations: deprecated.daemonset.template.generation: 2
Desired Number of Nodes Scheduled: 5
Current Number of Nodes Scheduled: 5
Number of Nodes Scheduled with Up-to-date Pods: 5
Number of Nodes Scheduled with Available Pods: 5
Number of Nodes Misscheduled: 0
Pods Status: 5 Running / 0 Waiting / 0 Succeeded / 0 Failed
Pod Template:
Labels: app=fluentd
Containers:
fluentd:
Image: harbor.zx/hcie/fluentd:v4.6
2.5 回滚DaemonSet
DaemonSet回滚的流程大致跟StatefulSet一致,以下案例也是将DaemonSet更新错镜像版本,然后验证如何回滚的过程。
现在我们引入一个错误的 Fluentd 镜像,故意将版本号设置为一个不存在的版本,观察更新失败的情况。
2.5.1 引入错误的 Fluentd 镜像:
修改 fluentd-daemonset.yaml
,将 Fluentd 镜像改为不存在的版本 v9.99.0
:
kubectl set image ds/fluentd fluentd=harbor.zx/hcie/fluentd:v4.7.0
查看滚动更新的状态:
kubectl rollout status daemonset/fluentd
验证 Pod 的状态:
kubectl get pods m -o wide
❔说明: 因为 Kubernetes 无法拉取
fluent/fluentd:v4.7.0
镜像,Pod 状态会显示ImagePullBackOff
错误。
使用 describe
命令查看失败原因:
kubectl describe pod fluentd-mhqhb
输出如下:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 2m40s default-scheduler Successfully assigned default/fluentd-mhqhb to k8s-worker2
Warning Failed 82s (x6 over 2m36s) kubelet Error: ImagePullBackOff
Normal Pulling 70s (x4 over 2m37s) kubelet Pulling image "harbor.zx/hcie/fluentd:v4.7.0"
Warning Failed 70s (x4 over 2m37s) kubelet Failed to pull image "harbor.zx/hcie/fluentd:v4.7.0": rpc error: code = NotFound desc = failed to pull and unpack image "harbor.zx/hcie/fluentd:v4.7.0": failed to resolve reference "harbor.zx/hcie/fluentd:v4.7.0": harbor.zx/hcie/fluentd:v4.7.0: not found
Warning Failed 70s (x4 over 2m37s) kubelet Error: ErrImagePull
Normal BackOff 56s (x7 over 2m36s) kubelet Back-off pulling image "harbor.zx/hcie/fluentd:v4.7.0"
回滚DaemonSet 到之前的版本
当引入错误后,Pod 无法正常运行,我们可以回滚到之前的 v4.
6 版本。
查看**DaemonSet **历史稳定版本:
kubectl rollout history daemonset fluentd
输出如下:
daemonset.apps/fluentd
REVISION CHANGE-CAUSE
1 <none>
2 <none>
3 <none>
当前状态版本是最新的版本,如果不确定,可以执行以下命令
kubectl rollout history daemonset fluentd --revision=3
输出如下:
daemonset.apps/fluentd with revision #3
Pod Template:
Labels: app=fluentd
Containers:
fluentd:
Image: harbor.zx/hcie/fluentd:v4.7.0
Port: <none>
Host Port: <none>
Environment: <none>
执行回滚操作:
kubectl rollout undo daemonset fluentd
❔ 参数说明:
--to-revision
指定历史版本,如果未指定则是默认上一版本。
查看滚动更新的状态,确保所有 Pod 都已经恢复正常:
kubectl rollout status daemonset/fluentd
如果输入如下,证明回滚成功;
daemon set "fluentd" successfully rolled out
验证 Pod 是否恢复正常:
kubectl get pods -o wide
输入如下:
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
fluentd-26ksx 1/1 Running 0 78m 172.16.194.65 k8s-worker1 <none> <none>
fluentd-8wnhj 1/1 Running 0 76m 172.16.224.59 k8s-master2 <none> <none>
fluentd-ddxbp 1/1 Running 0 75m 172.16.159.155 k8s-master1 <none> <none>
fluentd-hmqds 1/1 Running 0 79m 172.16.135.242 k8s-master3 <none> <none>
fluentd-xhl7b 1/1 Running 0 55s 172.16.126.12 k8s-worker2 <none> <none>
3 总结
DaemonSet 是 Kubernetes 中用于集群范围部署的一种强大的控制器,特别适用于那些需要在每个节点上运行系统服务的场景。通过本文的介绍,你可以轻松地部署日志收集器、监控代理等服务,实现对集群的全面监控和日志管理。
4 参考资料
[1]DaemonSet
[2]Perform a Rolling Update on a DaemonSet
[3]Perform a Rollback on a DaemonSet
标签:fluentd,Fluentd,读懂,DaemonSet,攻略,Pod,kubectl,节点 From: https://blog.csdn.net/u013522701/article/details/142370278