DeamonSets类似于Replica Sets,因为它们可以帮助我们部署多个pod实例,但是它在Kubernetes集群的每个节点上只运行一个pod副本。
DaemonSets确保所有(或部分)节点运行Pod的副本。随着节点被添加到集群中,pod也被添加到集群中,当节点从集群中移除时,这些pod将会被删除。
DaemonSets的使用场景
下面是一些典型的daemonset用例:
- 当我们希望在集群中的每个节点上部署监控代理,以便更好地监视集群时。然后,当集群中发生了变化,我们不必担心在这些节点上添加或删除监视代理,因为守护进程将为我们处理这些更改。如Prometheus Node export, Datadog agent等。
- 在集群中的每个节点上运行的日志收集器。例如logstash, fluentd。
- 在集群中的每个节点上运行的集群存储守护进程。例如glusterd - ceph。
- 对于网络解决方案,例如Weavenet需要在集群中的每个节点上运行一个Weavenet代理。
- kube-proxy是DaemonSets的另一个很好的用例。原因是集群中的每个节点都需要kube-proxy来运行IP Tables,这样每个节点都可以访问这个pod,而不管它运行在哪个节点上。因此,当我们将kube-proxy设置为守护进程,并且稍后将另一个节点添加到集群中时,kube-proxy将自动在该节点上生成。
在一个简单的情况下,可以为每种不同类型的守护进程使用一个Daemonset(覆盖所有节点)。我们也可以为单一类型的守护进程配置多个daemonset,使用不同的标志、内存、CPU等。
Kube-dns的职责是使用其名称发现服务IP,并且只需Kube-dns的一个副本就足以将服务名称解析为其IP。因此,我们将kube-dns作为一个部署,因为我们不需要在每个节点上都部署kube-dns。
如何调度DaemonSets
守护进程控制器管理像部署、复制集和状态集这样的pod。
创建一个DaemonSet
在本例中,我们将在集群的每个节点上部署prometheus节点导出代理pod。
下面是一个DaemonSet manifest文件的示例:
root@kube-master:~/DaemonSet# cat daemonset_demo.yml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: daemonset-demo-prometheus
spec:
selector:
matchLabels:
tier: monitoring
name: prometheus-exporter # Label selector that determines which Pods belong to the DaemonSet
template:
metadata:
labels:
tier: monitoring # Pod template's label selector
name: prometheus-exporter # Pod template's label selector
spec:
containers:
- name: prometheus
image: prom/node-exporter
ports:
- containerPort: 80
关于daemonset_demo.yml的说明
- 创建一个名为DaemonSet -demo-prometheus的守护进程,由metadata: name字段表示。
- 守护进程的Pod被标记为prometheus-expoter,并被标记为monitoring
- Pod的容器提取最新的节点导出器映像。容器映像由container Registry托管。
使用kubectl命令创建DaemonSet
root@kube-master:~/DaemonSet# kubectl apply -f daemonset_demo.yml --record
daemonset.apps/daemonset-demo-prometheus created
--record 表示将跟踪通过每次编辑所做的更改
验证创建的DaemonSet
root@kube-master:~/DaemonSet# kubectl get daemonsets daemonset-demo-prometheus -o wide
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE CONTAINERS IMAGES SELECTOR
daemonset-demo-prometheus 3 3 3 3 3 <none> 2m13s prometheus prom/node-exporter name=prometheus-exporter,tier=monitoring
获取更多有关DaemonSet的详细信息:
root@kube-master:~/DaemonSet# kubectl describe daemonsets daemonset-demo-prometheus
Name: daemonset-demo-prometheus
Selector: name=prometheus-exporter,tier=monitoring
Node-Selector: <none>
Labels: <none>
Annotations: deprecated.daemonset.template.generation: 1
kubernetes.io/change-cause: kubectl apply --filename=daemonset_demo.yml --record=true
Desired Number of Nodes Scheduled: 3
Current Number of Nodes Scheduled: 3
Number of Nodes Scheduled with Up-to-date Pods: 3
Number of Nodes Scheduled with Available Pods: 3
Number of Nodes Misscheduled: 0
Pods Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed
Pod Template:
Labels: name=prometheus-exporter
tier=monitoring
Containers:
prometheus:
Image: prom/node-exporter
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulCreate 2m52s daemonset-controller Created pod: daemonset-demo-prometheus-2l57n
Normal SuccessfulCreate 2m52s daemonset-controller Created pod: daemonset-demo-prometheus-8sgfk
Normal SuccessfulCreate 2m52s daemonset-controller Created pod: daemonset-demo-prometheus-ffbp6
在Pod中获取更多DaemonSet的信息
root@kube-master:~/DaemonSet# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
daemonset-demo-prometheus-2l57n 1/1 Running 0 5m1s 192.168.221.241 kube-master <none> <none>
daemonset-demo-prometheus-8sgfk 1/1 Running 0 5m1s 192.168.194.4 kube-worker1 <none> <none>
daemonset-demo-prometheus-ffbp6 1/1 Running 0 5m1s 192.168.161.240 kube-worker2 <none> <none>
从上面的输出可以看到,部署了3个pod。主节点和工作节点各一个。在这里,守护进程确保每个节点有一个pod,而不使用任何关联规则。
删除一个DaemonSet
像所有其他Kubernetes对象一样,DaemonSet也可以通过使用创建它的相同的manifest file或使用kubectl命令来删除。
root@kube-master:~/DaemonSet# kubectl delete -f daemonset_demo.yml
daemonset.apps "daemonset-demo-prometheus" deleted
root@kube-master:~/DaemonSet# kubectl delete daemonsets daemonset-demo-prometheus
daemonset.apps "daemonset-demo-prometheus" deleted
更新一个DaemonSet
可以通过更改以下规格来更新DaemonSet:
- Pod specification
- resource requests
- limits
- labels
- Annotations
我们可以使用以下两种更新策略来更新守护进程:
rolllingupdate —这是默认策略,将在配置更改时应用。它会自动删除并重新创建DaemonSet pod。
OnDelete -当使用此策略时,Kubernetes不会自动删除DaemonSet pods,并在配置更改时重新创建它们。我们必须手动删除pod,然后控制器将创建一个带有新更改的新pod。
Daemon Pod 是如何调度的?
DaemonSet确保所有符合条件的节点都运行Pod的副本。通常,Kubernetes调度器决定Pod运行的节点。但是,DaemonSet pod是由DaemonSet控制器创建和调度的。
但这会导致以下问题:
- Pod行为不一致:创建等待调度的普通Pod并保持Pending状态,但DaemonSet Pod没有创建Pending状态。这会让用户感到困惑。
- Pod抢占由默认调度器处理。当启用抢占时,守护进程控制器将在不考虑pod优先级和抢占的情况下做出调度决策。
那么如何解决这种问题?
ScheduleDaemonSetPods允许我们使用默认调度器而不是DaemonSet控制器来调度DaemonSet,通过将NodeAffinity 添加到DaemonSet pods中,而不是.spec.nodename。然后使用默认调度器将pod绑定到目标主机。
下面的清单文件使用节点关联规则创建一个pod。
apiVersion: v1
kind: Pod
metadata:
name: web-servers
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: workload
operator: In
values:
- staging
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
如果你观察上面的main file,我们有一个使用requiredduringscheduleingignoredduringexecution类型节点亲和力和表达式key-value作为workload: staging调度的Pod。这意味着pod将只被安排在具有workload=staging标签的节点上。
污点和容忍度
Daemon Pods 允许污点和容忍度。node.kubernetes.io/ unscheable:将NoSchedule容忍自动添加到DaemonSet Pods中。默认调度程序在调度DaemonSet pod时忽略不可调度的节点。
与Daemon pod通信
我们可以通过不同的方式与DaemonSets创建的pod进行通信。
- Push:使用这种方式,可以配置pods来发送诸如统计、数据库或监控服务之类的信息给其他服务。他们没有客户。
- NodeIP & Known Port : pod可以使用hostPort通过它们各自的节点ip到达。用户可以使用已知的端口和节点IP与pod通信。
- DNS:我们可以使用相同的pod选择器创建无头服务,然后使用端点资源发现daemonset或从DNS检索多个a记录。
- Service:我们可以使用相同的Pod选择器创建服务,并使用该服务访问随机节点上的守护进程。(无法到达特定节点。)
总结
当我们想要部署需要在所有或某些节点上运行的应用程序时,daemonset非常有用。此类任务的示例包括日志收集守护进程(如logstash)、存储守护进程(如ceph)和节点监控守护进程(如prometheus node-export)等。