【k8s】DaemonSet 守护进程(九)


Deployment 有哪些不足

Deployment 能够创建任意多个的 Pod 实例,并且维护这些 Pod 的正常运行,保证应用始终处于可用状态。Deployment 并不关心 Pod 在哪些节点上运行,只要 Pod 的数量足够,应用程序应该会正常工作。

但是有些业务是和运行环境相关的,它们并非完全独立于系统运行,而是与主机存在绑定关系,必须依附于节点才能产生价值:

  • 网络应用如 kube-proxy,节点不运行这个 Pod 就无法加入 Kubernetes 网络
  • 监控应用如 Prometheus,节点需要运行这个 Pod 报告节点运行状态
  • 日志应用如 Fluentd,节点需要运行这个 Pod 来收集日志
  • 安全应用,每个节点都要有一个 Pod 来执行安全审计、入侵检查、漏洞扫描等工作

这些业务如果用 Deployment 来部署就不太合适了,因为 Deployment 所管理的 Pod 数量是固定的,而且可能会在集群里漂移,但,实际的需求却是要在集群里的每个节点上都运行 Pod,也就是说 Pod 的数量与节点数量保持同步

所以,Kubernetes 就定义了新的 API 对象 DaemonSet,它在形式上和 Deployment 类似,都是管理控制 Pod,但管理调度策略却不同。

DaemonSet 确保全部(或者某些)节点上运行一个 Pod 的副本。 当有节点加入集群时, 也会为他们新增一个 Pod 。 当有节点从集群移除时,这些 Pod 也会被回收。删除 DaemonSet 将会删除它创建的所有 Pod。

一、使用 YAML 描述 DaemonSet 对象

使用命令 kubectl api-resources 可以知道它的简称是 ds。Kubernetes 不提供自动创建 DaemonSet YAML 样板的功能,我们只能去 DaemonSet 的文档页面获取一个 DaemonSet 的 YAML 模板。我们把它拷贝下来,再去掉多余的部分,就可以做成自己的一份样板文件:

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: redis-ds
  labels:
    app: redis-ds

spec:
  selector:
    matchLabels:
      name: redis-ds

  template:
    metadata:
      labels:
        name: redis-ds
    spec:
      containers:
      - image: redis:5-alpine
        name: redis
        ports:
        - containerPort: 6379

这个 DaemonSet 对象的名字是 redis-ds,镜像是 redis:5-alpine
spec 部分,DaemonSet 也有 selector 字段,匹配 templatePodlabels 标签,这和 Deployment 对象几乎一模一样。

DaemonSetspec 里没有 replicas 字段,意味着它不会在集群里创建多个 Pod 副本,而是要在每个节点上只创建出一个 Pod 实例。也就是说,DaemonSet 仅仅是在 Pod 的部署调度策略上和 Deployment 不同,其他的都是相同的,某种程度上我们也可以把 DaemonSet 看做是 Deployment 的一个特例

所以我们只需要用 kubectl create 先创建出一个 Deployment 对象,然后把 kind 改成DaemonSet,再删除 spec.replicas 就行了。

二、在 Kubernetes 里使用 DaemonSet

现在,让我们执行命令 kubectl apply,把 YAML 发送给 Kubernetes,让它创建 DaemonSet 对象,再用 kubectl get 查看对象的状态:

$ kubectl apply -f redis-ds.yaml 
daemonset.apps/redis-ds created
l$ kubectl get ds
NAME       DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
redis-ds   1         1         0       1            0           <none>          12s
$ kubectl get ds
NAME       DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
redis-ds   1         1         1       1            1           <none>          15s
$ kubectl get pod -o wide 
NAME                       READY   STATUS    RESTARTS   AGE   IP           NODE      NOMINATED NODE   READINESS GATES
redis-ds-ktmrm             1/1     Running   0          22s   10.10.1.26   k8s-work01 <none>           <none>

虽然我们没有指定 DaemonSet 里 Pod 要运行的数量,但它自己就会去查找集群里的节点,在节点里创建 Pod。因为我们的实验环境里有一个 Master 一个 Worker,而 Master 默认是不跑应用的,所以 DaemonSet 就只生成了一个 Pod,运行在了worker节点上。

按照 DaemonSet 的本意,应该在每个节点上都运行一个 Pod 实例才对,但 Master 节点却被排除在外了,这就不符合我们当初的设想了。

为了应对 Pod 在某些节点的调度驱逐问题,它定义了两个新的概念:污点(taint)容忍度(toleration)

三、Taint 和 Toleration

污点是 Kubernetes 节点的一个属性,它的作用也是给节点贴标签,但为了不和已有的 labels 字段混淆,就改成了taint

污点相对的,就是 Pod 的容忍度,顾名思义,就是 Pod 能否容忍污点。

Kubernetes 在创建集群的时候会自动给节点 Node 加上一些污点,方便 Pod 的调度和部署。你可以用 kubectl describe node 来查看 Master 和 Worker 的状态:

$ kubectl describe node k8s-master01
Name:               k8s-master01
Roles:              control-plane
···
Taints:             node-role.kubernetes.io/control-plane:NoSchedule
···

$ kubectl describe node worker1
Name:               k8s-worker01
Roles:              <none>
···
Taints:             <none>
···

可以看到,Master 节点默认有一个 taint,名字是 node-role.kubernetes.io/master,它的效果是 NoSchedule,也就是说这个污点会拒绝 Pod 调度到本节点上运行,而 Worker 节点的 taint 字段则是空的。这正是 Master 和 Worker 在 Pod 调度策略上的区别所在,通常来说 Pod 都不能容忍任何污点,所以加上了 taint 属性的 Master 节点也就会无缘 Pod 了。

两种方法让 DaemonSet 在 Master 节点(或者任意其他节点)上运行:

  • 去掉 Master 节点上的 taint,DaemonSet 自然就不需要再区分 Master/Worker
$ kubectl taint node master node-role.kubernetes.io/master:NoSchedule-

这种方法修改的是 Node 的状态,影响面会比较大,可能会导致很多 Pod 都跑到这个节点上运行,所以我们可以保留 Node 的污点,为需要的 Pod 添加容忍度,只让某些 Pod 运行在个别节点上,实现精细化调度

  • 为 Pod 添加字段 tolerations,让它能够容忍某些污点,就可以在任意的节点上运行了

tolerations 是一个数组,里面可以列出多个被容忍污点,需要写清楚污点的名字、效果。比较特别是要用 operator 字段指定如何匹配污点,一般我们都使用 Exists,也就是说存在这个名字和效果的污点

如果我们想让 DaemonSet 里的 Pod 能够在 Master 节点上运行,就要写出这样的一个 tolerations,容忍节点的

tolerations:
- key: node-role.kubernetes.io/control-plane
  effect: NoSchedule
  operator: Exists

重新部署加上了容忍度的 DaemonSet:

$ kubectl apply -f ds.yml

$ kubectl get ds -o wide 
NAME       DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE   CONTAINERS   IMAGES           SELECTOR
redis-ds   2         2         2       2            2           <none>          53m   redis        redis:5-alpine   name=redis-ds

需要特别说明的是:容忍度并不是 DaemonSet 独有的概念,而是从属于 Pod,所以理解了污点容忍度之后,你可以在 Job/CronJob、Deployment 里为它们管理的 Pod 也加上 tolerations,从而能够更灵活地调度应用。

点和容忍度的文档在这里:点我,有哪些污点、污点有哪些效果可以在这里找到。

四、静态 Pod

DaemonSet 是在 Kubernetes 里运行节点专属 Pod 最常用的方式,但它不是唯一的方式,Kubernetes 还支持另外一种叫静态 Pod的应用部署手段

静态 Pod非常特殊,它不受 Kubernetes 系统的管控,不与 apiserver、scheduler 发生关系,所以是静态的。但既然它是 Pod,也必然会在容器运行时上,也会有 YAML 文件来描述它,而唯一能够管理它的 Kubernetes 组件也就只有在每个节点上运行的 kubelet 了。

静态 Pod的 YAML 文件默认都存放在节点的 /etc/kubernetes/manifests 目录下,它是 Kubernetes 的专用目录。

Kubernetes 的 4 个核心组件 apiserver、etcd、scheduler、controller-manager 原来都以静态 Pod 的形式存在的,这也是它们能够先于 Kubernetes 集群启动的原因。

DaemonSet YAML

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: redis-ds
  labels:
    app: redis-ds

spec:
  selector:
    matchLabels:
      name: redis-ds

  template:
    metadata:
      labels:
        name: redis-ds
    spec:
      tolerations:
      - key: node-role.kubernetes.io/control-plane
        effect: NoSchedule
        operator: Exists

      containers:
      - image: redis:5-alpine
        name: redis
        ports:
        - containerPort: 6379

总结

  1. DaemonSet 的目标是为集群里的每个节点部署唯一的 Pod,常用于监控、日志等业务。
  2. DaemonSet 的 YAML 描述与 Deployment 非常接近,只是没有 replicas 字段。
  3. 污点容忍度是与 DaemonSet 相关的两个重要概念,分别从属于 Node 和 Pod,共同决定了 Pod 的调度策略。
  4. 静态 Pod 也可以实现和 DaemonSet 同样的效果,但它不受 Kubernetes 控制,必须在节点上纯手动部署,应当慎用。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值