k8s DaemonSet 介绍与实例
我们之前说k8s中使用deployment、statefulset工作负载资源来分别维护无状态和有状态应用。这篇小作文我们会学习如何使用DaemonSet
来维护一个守护进程(应用)。
一、DaemonSet是什么?
DaemonSet 是一个确保全部或者某些节点上必须运行一个 Pod的工作负载资源(守护进程),当有节点加入集群时, 也会为他们新增一个 Pod。
下面是常用的使用案例:
- 集群守护进程,如
Kured
、node-problem-detector
- 日志收集守护进程,如
fluentd
、logstash
- 监控守护进程,如promethues
node-exporter
通过创建DaemonSet 可以确保 守护进程pod 被调度到每个可用节点上运行。
二、DaemonSet 如何工作?
DaemonSet 是由控制器(controller manager)管理的 Kubernetes 工作资源对象。我们通过声明一个想要的daemonset状态,表明每个节点上都需要有一个特定的 Pod。协调控制回路会比较期望状态和当前观察到的状态。如果观察到的节点没有匹配的 Pod,DaemonSet controller将自动创建一个。可以参考之前《k8s工作流程详解》
在这个过程包括现有节点和所有新创建的节点。不过DaemonSet 控制器创建的 Pod 会被Kubernetes 调度器忽略,即DaemonSet Pods 由 DaemonSet 控制器创建和调度。这样带来的两个微妙的问题:
- Pod 行为的不一致性:正常 Pod 在被创建后等待调度时处于
Pending
状态, DaemonSet Pods 创建后不会处于Pending
状态下。 - Pod 抢占行为由默认调度器处理。启用抢占后,DaemonSet 控制器将在不考虑 Pod 优先级和抢占 的情况下制定调度决策。
所以在k8s v1.12以后DaemonSet Controller 将会向 DaemonSet 的 Pod 添加 .spec.nodeAffinity
字段,而不是 .spec.nodeName
字段,并进一步由 kubernetes 调度器将 Pod 绑定到目标节点。如果 DaemonSet 的 Pod 已经存在了 nodeAffinity
字段,该字段的值将被替换。
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchFields:
- key: metadata.name
operator: In
values:
- target-host-name
daemonset pod的默认容忍规则如下:
DaemonSet 默认在每个节点上创建一个 Pod。当然也可以使用节点选择器来限制可接受节点的数量。DaemonSet 控制器将仅在与 YAML 文件中预定义的nodeSelector字段匹配的节点上创建Pod。我们在下面会使用到。
三、DaemonSet实例
创建DaemonSet
我们只需要将前面deployment中的kind
调整为DaemonSet 就可以创建出一个DaemonSet守护进程
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: my-daemonset
spec:
selector:
matchLabels:
app: my-daemon
template:
metadata:
labels:
app: my-daemon
spec:
containers:
- name: daemonset-container
image: httpd
ports:
- containerPort : 80
通过apply应用后查看资源状态
$ kubectl get daemonset
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
my-daemonset 1 1 1 1 1 <none> 10m
由于我们minikube只有一个node 所以只建立了一个副本,在节点通过get查看到已创建出这个daemonset pod
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
my-daemonset-97z2g 1/1 Running 0 10m
在daemonset资源状态中可以看到NODE SELECTOR
的值为none
,显然我们可以通过在pod模板中添加nodeSelector
使DaemonSet 控制器仅在与Node 选择算符匹配的节点上创建出pod,接下来我们添加一个nodeSelector
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: my-daemonset
spec:
selector:
matchLabels:
app: my-daemon
template:
metadata:
labels:
app: my-daemon
spec:
containers:
- name: daemonset-container
image: httpd
ports:
- containerPort : 80
nodeSelector:
kubernetes.io/hostname: minikube
这样我们的pod只会在hostname为minikube的Node上创建DaemonSet守护进程的pod
$ kubectl get daemonset
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
my-daemonset 1 1 1 1 1 kubernetes.io/hostname=minikube 30m
除了通过nodeSelector
来控制节点调度外,还可以通过上面提到的容忍策略即tolerations
使daemonset pod 调度到“非正常“Node。
我们可以来看一个fluentd
的官方elasticsearch daemonset
源文件地址:fluentd-daemonset-elasticsearch.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd
namespace: kube-system
labels:
k8s-app: fluentd-logging
version: v1
spec:
selector:
matchLabels:
k8s-app: fluentd-logging
version: v1
template:
metadata:
labels:
k8s-app: fluentd-logging
version: v1
spec:
tolerations:
- key: node-role.kubernetes.io/master
effect: NoSchedule
containers:
- name: fluentd
image: fluent/fluentd-kubernetes-daemonset:v1-debian-elasticsearch
env:
- name: FLUENT_ELASTICSEARCH_HOST
value: "elasticsearch-logging"
- name: FLUENT_ELASTICSEARCH_PORT
value: "9200"
- name: FLUENT_ELASTICSEARCH_SCHEME
value: "http"
# Option to configure elasticsearch plugin with self signed certs
# ================================================================
- name: FLUENT_ELASTICSEARCH_SSL_VERIFY
value: "true"
# Option to configure elasticsearch plugin with tls
# ================================================================
- name: FLUENT_ELASTICSEARCH_SSL_VERSION
value: "TLSv1_2"
# X-Pack Authentication
# =====================
- name: FLUENT_ELASTICSEARCH_USER
value: "elastic"
- name: FLUENT_ELASTICSEARCH_PASSWORD
value: "changeme"
# Logz.io Authentication
# ======================
- name: LOGZIO_TOKEN
value: "ThisIsASuperLongToken"
- name: LOGZIO_LOGTYPE
value: "kubernetes"
resources:
limits:
memory: 200Mi
requests:
cpu: 100m
memory: 200Mi
volumeMounts:
- name: varlog
mountPath: /var/log
# When actual pod logs in /var/lib/docker/containers, the following lines should be used.
# - name: dockercontainerlogdirectory
# mountPath: /var/lib/docker/containers
# readOnly: true
# When actual pod logs in /var/log/pods, the following lines should be used.
- name: dockercontainerlogdirectory
mountPath: /var/log/pods
readOnly: true
terminationGracePeriodSeconds: 30
volumes:
- name: varlog
hostPath:
path: /var/log
# When actual pod logs in /var/lib/docker/containers, the following lines should be used.
# - name: dockercontainerlogdirectory
# hostPath:
# path: /var/lib/docker/containers
# When actual pod logs in /var/log/pods, the following lines should be used.
- name: dockercontainerlogdirectory
hostPath:
path: /var/log/pods
特别之处在于,为了收集master节点上的pod日志,将会容忍fluentd
调度到master节点。其中tolerations
如下
Daemon Pods 通信
与 DaemonSet 中的 Pod 进行通信的几种模式如下:
- 推送(Push):配置 DaemonSet 中的 Pod,将更新发送到另一个服务,例如统计数据库。
- NodeIP 和已知端口:DaemonSet 中的 Pod 可以使用
hostPort
,从而可以通过节点 IP 访问到 Pod。客户端能通过某种方法获取节点 IP 列表,并且基于此也可以获取到相应的端口。比如prometheus的node-exporter。 - DNS:创建具有相同 Pod 选择算符的 无头服务 通过使用
endpoints
资源或从 DNS 中检索到多个 A 记录来发现 DaemonSet。
DaemonSet 更新
如果节点的标签被修改,DaemonSet 将立刻向新匹配上的节点添加 Pod, 同时删除不匹配的节点上的 Pod。
可以删除一个 DaemonSet。如果使用 kubectl
指定 --cascade=orphan
选项, 则 Pod 将被保留在节点上。接下来如果创建使用相同选择算符的新 DaemonSet, 新的 DaemonSet 会收养已有的 Pod。 如果有 Pod 需要被替换,DaemonSet 会根据其 updateStrategy
来替换。
比如prometheus中的node-exporter
以上是关于k8s中的DaemonSet相关内容。
参考:
希望小作文对你有些许帮助,如果内容有误请指正。
您可以随意转载、修改、发布本文,无需经过本人同意。blog:iqsing.github.io
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
· Manus的开源复刻OpenManus初探