大家好啊,咱们的Kubernetes
学习笔记时隔两月终于又迎来了更新,前面咱们介绍的Deployment、Service、Statefulset 相信看过文章的同学都已经明白他们各自的能力和使用场景了,如果已经没啥印象了或者是还没看过的同学,推荐看一下之前讲他们三个的文章。
K8s入门笔记--Deployment搞定服务部署
深入理解StatefulSet,用Kubernetes编排有状态应用
K8s入门笔记-- 用 Service 公开服务
K8s里的Deployment、Service、Statefulset这三个控制器离我们的应用层最近所以接触到的机会比较多,今天我来给大家介绍另外一个控制器 DaemonSet,它堪称是集群幕后的英雄。
我做个比喻大家就马上能明白DaemonSet的作用,假如K8s集群是一个大House,Deployment、Service、Statefulset 他们几个就是给屋子(Node)搞软装的,你可以用他们把屋子搞成餐厅、客厅、卧室等各种功能房,而DamonSet就是给屋子搞水电网、刷墙这些硬装的,而对于K8s集群来说它的水电网不就是--网络、存储、监控等等这些吗?
好了,明白了 DaemonSet 就是给 K8s 集群搞硬装的这个角色后,接下来咱们就展开来说一下它的特性和怎么使用它。
DaemonSet的作用是,确保可用节点上都能运行一个守护进程类的 Pod,这个 Pod 如下三个特点
这个 Pod 运行在 K8s 集群里的每一个节点(Node)上。
每个节点上有且只有一个被指定DamonSet创建的 Pod实例(当然我们可以创建不同作用的DamonSet,每个都会在节点上创建一个对应的Pod实例) 。
当有新的节点加入 Kubernetes 集群后,该 Pod 会自动地在新节点上被创建出来,而当旧节点被删除后,它上面的 Pod 也相应地会被回收掉。
DaemonSet 是 K8s 集群必不可少的组成部分,它便于集群管理员跨所有节点或部分节点轻松配置服务(pod)。
DaemonSets 可以通过在所有节点上部署 Pod 来分配维护集群和支持服务类的任务,从而提高 K8s 集群的性能。它非常适合用于长时间运行的服务,例如监控或日志收集。以下是 DaemonSet 的一些使用场景:
在每个节点上挂载集群存储例如 glusterd 和 ceph,操作容易的Volume目录。
在每个节点上运行一个守护进程来收集日志,例如 Fluentd 和 logstash。
在每个节点上运行一个守护进程来监控节点,例如 Prometheus Node Exporter、collectd 或 Datadog(AWS上的服务)的Agent。
默认情况下,Pod 运行在哪个节点上由 K8s 调度程序决定。但是,DaemonSet pod 是由 DaemonSet 控制器创建和调度的。使用 DaemonSet 控制器会导致 Pod 行为不一致和 Pod 优先级抢占的问题。
为了解决这个问题,K8s 允许用户通过给DaemonSet Pod 设置 NodeAffinity (节点亲密性)来使用 K8s 调度器把DaemonSet Pod调度到目标节点上。
下面是一个示例 NodeAffinity 配置:
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values:
- ssd
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
上面我们通过配置 NodeAffinity 让Pod只能调度到持有"disktype=ssd"标签的节点上去。
requiredDuringSchedulingIgnoredDuringExecution:它的意思是说,这个 nodeAffinity 必须在每次调度的时候予以考虑,你也可以设置在某些情况下不考虑这个 NodeAffinity。
nodeSelectorTerms 里指定的 disktype In (ssd) 表示:这个 Pod,将来只允许运行在"metadata.lables.disktype=ssd"的节点上。
节点亲密性更详细的解释可以去看一下我之前写的文章 玩转K8s Pod滚动更新里关注NodeAffinity章节的内容。
此外,DaemonSet 还会给 Pod 容忍度 (tolerations)自动加上容忍node.kubernetes.io/unschedulable:NoSchedule
这个污点的配置。
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
tolerations:
- key: node.kubernetes.io/unschedulable
operator: Exists
effect: NoSchedule
K8s 集群中新加入的节点在未完成准备工作之前都会被标记上这个污点(taints),不允许Pod调度到节点上来,而DaemonSet 自动给它Pod加上容忍这个污点的配置,就让它创建的Pod有机会提前入场,在节点上搭建好各种"硬装"后再供集群进行调度。
跟 K8s 里的其他组件一样,DaemonSets 也是使用 YAML 文件配置的。我们来看看 DaemonSet 配置文件的结构。
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: test-daemonset
namespace: test-daemonset-namespace
Labels:
app-type: test-app-type
spec:
template:
metadata:
labels:
name: test-daemonset-container
image: "image to use for container"
selector:
matchLabels:
name: test-daemonset-container
跟其他组件的配置一样,apiVersion、kind 和 metadata 是每个 K8s 组件配置中的必填字段。
template:也叫Pod模板,在Deployment、StatefulSet的配置里我们都已经见过了,这里是要部署到每个节点上的Pod的定义。DaemonSet 中的 pod 模板必须将其 RestartPolicy 设置为“Always”,如果没有指定 RestartPolicy,默认情况下它就是“Always”。
selector: DaemonSet 管理的 Pod 的标签选择器。该值必须是 Pod 模板中指定的标签。(在上面的例子中,我们使用了名称:test-daemonset-container 作为选择器。)这个值是固定的,在初始创建 DaemonSet 后不能更改。
其他可选的配置字段有:
template.spec.affinity – 配置Pod的节点亲密性,文章开头说过,可以通过 NodeAffinity 配置限定DaemonSet控制器创建的Pod只被调度器调度到满足Affinity配置的节点上。
现在让我们创建一个示例的DaemonSet。它将管理一个使用"fluentd-elasticsearch"镜像运行容器的Pod,它创建的Pod会在 K8s 集群的每个节点上运行,通过 fluentd 将节点上 Docker 容器里的日志转发到 ElasticSearch 中。
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd-elasticsearch-test
namespace: default # Name Space
labels:
k8s-app: fluentd-logging
spec:
selector: # Selector
matchLabels:
name: fluentd-elasticsearch-test-deamonset
template: # Pod Template
metadata:
labels:
name: fluentd-elasticsearch-test-deamonset
spec:
tolerations: # Tolerations
- key: node-role.kubernetes.io/master
effect: NoSchedule
containers: # Container Details
- name: fluentd-elasticsearch
image: quay.io/fluentd_elasticsearch/fluentd:v2.5.2
resources:
limits:
memory: 200Mi
requests:
cpu: 100m
memory: 200Mi
volumeMounts:
- name: varlog
mountPath: /var/log
- name: varlibdockercontainers
mountPath: /var/lib/docker/containers
readOnly: true
terminationGracePeriodSeconds: 30
volumes:
- name: varlog
hostPath:
path: /var/log
- name: varlibdockercontainers
hostPath:
path: /var/lib/docker/containers
有了 DaemonSet 的YAML配置文件后,接下来,让我们使用 kubectl create 命令创建 DaemonSet 并检索 DaemonSet 和它创建的 Pod 信息:
创建DaemonSet
➜ ✗ kubectl apply -f daemonset.yaml
daemonset.apps/fluentd-elasticsearch-test created
查看是否创建成功
➜ ✗ kubectl get pods
NAME READY STATUS RESTARTS AGE
fluentd-elasticsearch-test-pb5qw 0/1 ContainerCreating 0 18s
➜ ✗ kubectl describe pod fluentd-elasticsearch-test-pb5qw
......
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled Successfully assigned default/fluentd-elasticsearch-test-pb5qw to docker-desktop
Normal Pulling 32s kubelet, docker-desktop Pulling image "quay.io/fluentd_elasticsearch/fluentd:v2.5.2"
Normal Pulled 6s kubelet, docker-desktop Successfully pulled image "quay.io/fluentd_elasticsearch/fluentd:v2.5.2" in 25.3910795s
Normal Created 6s kubelet, docker-desktop Created container fluentd-elasticsearch
Normal Started 5s kubelet, docker-desktop Started container fluentd-elasticsearch
➜ ✗ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
fluentd-elasticsearch-test-pb5qw 1/1 Running 0 5m7s 10.1.0.38 docker-desktop
从上面的输出可以看出,我们的 DaemonSet 已经部署成功。可以看到我们在定义文件里并没有像Deployment那样通过 replicas 指定Pod的数量,那是因为 DaemonSet 会根据集群上可用的节点,将 Pod 自动扩展到配置里指定的可用节点上。这里因为我是在电脑上Docker桌面应用自带的K8s集群,只有一个节点,所以DaemonSet 只创建出了一个Pod。
更新和删除DaemonSet的方法跟其他组件没有什么两样,这里就不再多说了,直接上命令
## 更新完配置文件后直接apply
kubectl apply -f daemonset.yaml
## 删除
kubectl delete daemonset <>
好了,这篇介绍 DaemonSet 的文章就到这里,如果不是搞 K8s 相关工作的,DaemonSet 平常可能接触不到,这篇文章也算是一个科普,记住我那个比喻:Deployment 和 StatefulSet 这些控制器是给 K8s 集群搞软装的,而 DaemonSet 是给集群这个大 House 的屋子搞硬装的,所以 DaemonSet 会在节点这个"屋子"准备好之前先入场"装修"完,后面才能让 Deployment 它们搞"软装"。
- END -
扫码关注公众号「网管叨bi叨」
给网管个星标,第一时间吸我的知识
网管为大家整理了一本超实用的《Go 开发参考书》收集了70多条开发实践。去公众号回复【gocookbook】即刻领取!
觉得有用就点个在看