k8s DaemonSet 介绍与实例

语言: CN / TW / HK

我们之前说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-tolerations

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

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 如下

fluentd-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

node-exporter

以上是关于k8s中的DaemonSet相关内容。

希望小作文对你有些许帮助,如果内容有误请指正。

您可以随意转载、修改、发布本文,无需经过本人同意。通过博客阅读 :iqsing.github.io

References

[1]

fluentd-daemonset-elasticsearch.yaml:  https://github.com/fluent/fluentd-kubernetes-daemonset/blob/master/fluentd-daemonset-elasticsearch.yaml

[2]

daemonset:  https://kubernetes.io/zh/docs/concepts/workloads/controllers/daemonset/

[3]

node-affinity:  https://kubernetes.io/zh/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity

[4]

node-exporter-daemonset:  https://github.com/prometheus-operator/kube-prometheus/blob/main/manifests/node-exporter-daemonset.yaml

[5]  iqsing.github.io:  https://iqsing.github.io