AnyRobot 作为一款强大日志存储与分析的平台,存在某些特定Pod需要在AnyRobot每个节点进行部署,如node-exporter采集器、logstash-input日志接收等,该些Pod需要在每个节点运行,那AnyRobot是如何保证该类Pod在每个主机节点运行呢,主要是采用k8s DaemonSet相关技术来实现,那么接下来,我们详细了解下k8s DaemonSet相关技术细节。
首先我们先来了解下,DaemonSet相关基础知识。
一、为什么需要DaemonSet
在 Kubernetes 集群中,通常需要在每个节点上运行守护进程来监视节点健康状态、收集日志等,这些守护进程通常称为系统级守护进程,如 Kubernetes Cluster Autoscaler 和 Kubernetes DNS。使用 Deployment 或 StatefulSet 可以创建 Pod,这些 Pod 可以被调度到任何节点上运行,但是在某些情况下,需要确保每个节点上都运行着一个 Pod 副本版本,即需要使用 DaemonSet。
AnyRobot中,node-exporter作为收集主机等相关信息,需要在AnyRobot每个节点上运行,同时logstash-input作为日志接收Pod,也需要在AnyRobot每个节点运行。
二、DaemonSet是如何实现的
所有的 DaemonSet 都是由控制器负责管理的,与其他的资源一样,用于管理 DaemonSet 的控制器是 DaemonSetsController,该控制器会监听 DaemonSet、ControllerRevision、Pod 和 Node 资源的变动。
大多数的触发事件最终都会将一个待处理的 DaemonSet 资源入栈,下游 DaemonSetsController 持有的多个工作协程就会从队列里面取出资源进行消费和同步。
三、DaemonSet是如何调度的
由 DaemonSet 控制器调度 (v1.12以后默认禁用)
通常,Kubernetes Scheduler(调度器)决定了 Pod 在哪个节点上运行。然而 DaemonSet Controller 创建的 Pod 已经指定了 .spec.nodeName 字段,因此:
- Node 节点的 unschedulable (opens new window)字段将被 DaemonSet Controller 忽略
- DaemonSet Controller 可以在 kubernetes scheduler 启动之前创建 Pod,这个特性在引导集群启动的时候非常有用(集群使用者无需关心)。
由默认调度器调度(v1.12以后默认启用)
DaemonSet 确保所以符合条件的节点运行了一个指定的 Pod。通常,Kubernetes Scheduler 决定 Pod 在哪个节点上运行。然而如果 DaemonSet 的 Pod 由 DaemonSet Controller 创建和调度,会引发如下问题:
- Pod 的行为不一致:普通的 Pod 在创建后处于 Pending 状态,并等待被调度,但是 DaemonSet Pod 创建后,初始状态不是 Pending。
- Pod 的优先权(preemption) (opens new window)由 kubernetes 调度器处理。如果 Pod 优先权被启用,DaemonSet Controller 在创建和调度 Pod 时,不会考虑 Pod 的优先权
Kubernetes v1.12 版本以后,默认通过 kubernetes 调度器来调度 DaemonSet 的 Pod。DaemonSet Controller 将会向 DaemonSet 的 Pod 添加 .spec.nodeAffinity 字段,而不是 .spec.nodeName 字段,并进一步由 kubernetes 调度器将 Pod 绑定到目标节点。如果 DaemonSet 的 Pod 已经存在了 nodeAffinity 字段,该字段的值将被替换。
此外, node.kubernetes.io/unschedulable:NoSchedule 容忍(toleration)将被自动添加到 DaemonSet 的 Pod 中。由此,默认调度器在调度 DaemonSet 的 Pod 时可以忽略节点的 unschedulable 属性。
污点和容忍
在调度 DaemonSet 的 Pod 时,污点和容忍(taints and tolerations)会被考量到,同时,以下容忍(toleration)将被自动添加到 DaemonSet 的 Pod 中:
四、AnyRobot之node-exporter
首先我们来查看node-exporter相关daemonset相关yaml文件
apiVersion: apps/v1
kind: DaemonSet
metadata:
annotations:
deprecated.daemonset.template.generation: "1"
labels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: node-exporter
app.kubernetes.io/part-of: kube-prometheus
app.kubernetes.io/version: 1.3.1
name: node-exporter
namespace: kubesphere-monitoring-system
resourceVersion: "5998"
uid: e925fd22-38f0-467d-8f33-d9dd6075759b
spec:
revisionHistoryLimit: 10
selector:
matchLabels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: node-exporter
app.kubernetes.io/part-of: kube-prometheus
template:
metadata:
creationTimestamp: null
labels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: node-exporter
app.kubernetes.io/part-of: kube-prometheus
app.kubernetes.io/version: 1.3.1
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: node-role.kubernetes.io/edge
operator: DoesNotExist
containers:
- args:
- --web.listen-address=127.0.0.1:29100
- --path.procfs=/host/proc
- --path.sysfs=/host/sys
- --path.rootfs=/host/root
- --no-collector.wifi
- --no-collector.hwmon
- --collector.filesystem.ignored-mount-points=^/(dev|proc|sys|var/lib/docker/.+)($|/)
- --collector.filesystem.ignored-fs-types=^(autofs|binfmt_misc|cgroup|configfs|debugfs|devpts|devtmpfs|fusectl|hugetlbfs|mqueue|overlay|proc|procfs|pstore|rpc_pipefs|securityfs|sysfs|tracefs)$
image: registry.aishu.cn:15000/prom/node-exporter:v1.3.1
imagePullPolicy: IfNotPresent
name: node-exporter
resources:
limits:
cpu: "1"
memory: 500Mi
requests:
cpu: 102m
memory: 180Mi
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /host/proc
name: proc
readOnly: true
- mountPath: /host/sys
name: sys
readOnly: true
- mountPath: /host/root
mountPropagation: HostToContainer
name: root
readOnly: true
- args:
- --logtostderr
.......................................
初步看,这份配置跟 Deployment 基本类似,唯一一个显著的差异是 DaemonSet 不需要指定副本数,因为它的副本数取决于工作节点数。该份配置将创建一个 DaemonSet 对象,然后 DaemonSet 控制器会根据该对象信息分别在每个节点上创建一个 Pod 副本。
可以查看创建DaemonSet以后,在每个节点创建一个Pod副本
[root@node104 ~]# kubectl get daemonset -A
NAMESPACE NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
anyrobot logstash-input 1 1 1 1 1 anyrobot-app=true 8d
kube-system node-exporter 1 1 1 1 1 8d