17、Kubernetes核心技术 - 污点(Taints)和污点容忍(Tolerations)

目录

一、概述

二、污点和污点容忍示例

2.1、NoSchedule

2.2、NoExecute

三、污点和污点容忍应用场景

四、k8s内置的一些污点


一、概述

上一篇文章介绍了节点亲和性,它主要实现的是将Pod强制或者尽可能调度到满足某些条件的node节点上**【通过在Pod上添加属性,来确定Pod是否要调度到指定的节点上**】,k8s中的污点,它的行为刚好与节点亲和性相反,污点可以将节点和 Pod 达到互斥的效果,让Pod不被调度到存在污点的那些节点上**【在Node节点上添加污点属性(Taints),来避免Pod被分配到不合适的节点上】**;k8s中的污点容忍,则可以让 Pod 调度到带有污点的节点上。

  • taints(污点)

污点是定义在节点上的键值型属性数据,用于让节点拒绝将Pod 调度运行于其上,除非 Pod 有接纳节点污点的容忍度;

  • tolerations (污点容忍)

污点容忍是定义在 Pod 上的键值型属性数据,用于配置可容忍的污点,且调度器将 Pod 调度至其能容忍该节点污点的节点上或没有污点的节点上;

在k8s中,我们可以给节点添加一些污点,以便在该节点上不能调度任何 Pod,除非Pod明确定义了Tolerations,Tolerations 应用于 Pod,并允许(但不要求)Pod 调度到具有匹配污点的节点上。

可以使用命令 kubectl taint 给节点增加一个污点。比如:

java 复制代码
kubectl taint node <node_name> key=value[effect]   

示例:
# 给节点 master 增加一个污点,它的键名是 key1,键值是 value1,效果是 NoSchedule。 这表示只有拥有和这个污点相匹配的容忍度的 Pod 才能够被分配到这个节点。
kubectl taint node master key1=value1:NoSchedule       # 设置value值

effect可选值有三个:

  • NoSchedule:表示 Pod 将不会被调度到具有该污点的节点上,注意,已经正在运行中的Pod不受影响
  • PreferNoSchedule:表示 Pod 将尽量避免调度到具有该污点的节点上,注意,已经正在运行中的Pod不受影响
  • NoExecute:表示 Pod 将不会被调度到具有该污点的节点上,同时将节点上已经存在的 Pod 进行驱逐,注意,已经正在运行中的Pod也会受影响,因节点污点变动或Pod容忍度变动而不再满足匹配规则时,Pod对象将被驱逐

可以对单个节点应用多个污点,对单个 Pod 应用多个容忍度。

二、污点和污点容忍示例

2.1、NoSchedule

NoSchedule表示 Pod 将不会被调度到具有该污点的节点上,注意,已经正在运行中的Pod不受影响。

假设当前k8s集群有两个node节点,node01和controlplane。我们先给node01节点添加一个NoSchedule类型的污点。

NoSchedule:表示 Pod 将不会被调度到具有该污点的节点上

java 复制代码
#给节点添加污点
$ kubectl taint nodes node01 a=b:NoSchedule
node/node01 tainted

#查看某个节点的污点
$ kubectl describe node node01 | grep Taints
Taints:             a=b:NoSchedule

$ kubectl describe node controlplane | grep Taints
Taints:             <none>

然后我们创建一个三个副本的nginx的Pod:

vim taint-demo.yaml

java 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx

创建三个副本的Pod:

java 复制代码
$ kubectl apply -f taint-demo.yaml 
deployment.apps/nginx created

$ kubectl get pods -o wide
NAME                     READY   STATUS    RESTARTS   AGE   IP            NODE           NOMINATED NODE   READINESS GATES
nginx-748c667d99-5t842   1/1     Running   0          13s   192.168.0.8   controlplane   <none>           <none>
nginx-748c667d99-dptjw   1/1     Running   0          13s   192.168.0.6   controlplane   <none>           <none>
nginx-748c667d99-gvt5s   1/1     Running   0          13s   192.168.0.7   controlplane   <none>           <none>

我们看到,当前三个Pod都被调度到了controlplane这个节点,因为我们给node01节点设置了一个【a=b:NoSchedule】的污点,并且我们的Pod也没有配置污点容忍,所以Pod不能被调度到node01节点。

如果说我们希望Pod能调度到node01上,我们可以给Pod添加污点容忍,需要修改一下Pod的资源清单,添加tolerations污点容忍的配置:

java 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx
      tolerations:  # 污点容忍
        - key: "a"
          operator: "Equal"		# operator的默认值为Equal。(如果键相同且值相同,则容忍匹配污点)
          value: "b"
          effect: "NoSchedule"

如上配置表示Pod能够容忍节点中存在【a=b:NoSchedule】这个污点,说明Pod有资格被调度到存在这个污点的node上,但是,这并不能保证这个 Pod 一定被调度到该节点,因为我们没有指定任何node affinity或者nodeSelector。修改完成后重新应用Pod 清单文件:

java 复制代码
$ vim taint-demo.yaml 
$ kubectl apply -f taint-demo.yaml 
deployment.apps/nginx configured

$ kubectl get pod -o wide
NAME                     READY   STATUS    RESTARTS   AGE   IP            NODE           NOMINATED NODE   READINESS GATES
nginx-6bfd64d99c-4g9v9   1/1     Running   0          6s    192.168.0.9   controlplane   <none>           <none>
nginx-6bfd64d99c-lf8qv   1/1     Running   0          12s   192.168.1.3   node01         <none>           <none>
nginx-6bfd64d99c-ttscz   1/1     Running   0          4s    192.168.1.4   node01         <none>           <none>

我们看到,当给node01添加了污点容忍后,Pod也能够正常被调度到node01上了。

若要移除上述命令所添加的污点,可以执行:

java 复制代码
#删除污点  kubectl taint node <node名称> key:[effect]-
$ kubectl taint nodes node01 a=b:NoSchedule- 
node/node01 untainted

$ kubectl describe node node01 | grep Taints
Taints:             <none>

2.2、NoExecute

NoExecute表示 Pod 将不会被调度到具有该污点的节点上,同时将节点上已经存在的 Pod 进行驱逐。

vim noexecute-taint-demo.yaml

java 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx
java 复制代码
$ kubectl apply -f noexecute-taint-demo.yaml 
deployment.apps/nginx created

$ kubectl get pod -o wide
NAME                     READY   STATUS    RESTARTS   AGE   IP            NODE           NOMINATED NODE   READINESS GATES
nginx-748c667d99-2s88m   1/1     Running   0          9s    192.168.1.4   node01         <none>           <none>
nginx-748c667d99-lgndm   1/1     Running   0          9s    192.168.1.3   node01         <none>           <none>
nginx-748c667d99-tj4tc   1/1     Running   0          9s    192.168.0.6   controlplane   <none>           <none>

$ kubectl describe node node01 | grep Taints
Taints:             <none>
$ kubectl describe node controlplane | grep Taints
Taints:             <none>

可以看到,Pod被分别调度到两个节点上。接下来,我们给node01节点添加一个NoExecute类型的污点:

java 复制代码
$ kubectl taint nodes node01 c=d:NoExecute
node/node01 tainted

$ kubectl describe node node01 | grep Taints
Taints:             c=d:NoExecute

然后我们再查看Pod详情:

java 复制代码
$ kubectl get pod -o wide
NAME                     READY   STATUS    RESTARTS   AGE     IP            NODE           NOMINATED NODE   READINESS GATES
nginx-748c667d99-tj4tc   1/1     Running   0          2m58s   192.168.0.6   controlplane   <none>           <none>
nginx-748c667d99-tt5db   1/1     Running   0          34s     192.168.0.7   controlplane   <none>           <none>
nginx-748c667d99-v687w   1/1     Running   0          34s     192.168.0.8   controlplane   <none>           <none>

可以看到,之前调度到node01的两个Pod,已经被驱逐了,然后重新被调度到controlplane节点上。

实际上任何不容忍NoExecute污点的Pod都将被立即驱逐,而能够容忍污点的Pod 将永远不会被驱逐。但是可以指定一个可选tolerationSeconds字段,该字段指示在添加污点后Pod 将保持绑定到节点的时间。例如:

java 复制代码
tolerations:
- key: "c"
  operator: "Equal"
  value: "d"
  effect: "NoExecute"
  tolerationSeconds: 3600  # 表示当 Pod 被驱逐时,还可以在节点上继续运行的时间(仅可以和NoExecute配合使用)

如果这个Pod 正在运行并且有一个匹配的污点被添加到该节点,那么该Pod将保持绑定到该节点 3600 秒,然后被驱逐。如果在该时间之前移除了污点,则Pod不会被驱逐。

三、污点和污点容忍应用场景

  • 1、专用节点:当想将一组节点专用于专有工作负载或特定用户时,您可以向这些节点添加一个污点,然后向它们的Pod 添加相应的容忍度。
  • 2、具有特殊硬件的节点:对于具有专用硬件的节点,我们只希望具有这些要求的Pod 在这些节点上运行。污染将帮助我们并为使用特殊硬件的Pod 添加相应的容忍度。
  • 3、基于污点的驱逐:当节点存在问题时,每个Pod可配置的驱逐行为。

四、k8s内置的一些污点

Kubernetes自1.6版本起支持使用污点自动标识问题节点,它通过节点控制器在特定条件下自动为节点添加污点信息实现。目前,内建使用的此类污点包含如下几个。

Kubernetes的核心组件通常都要容忍此类的污点,以确保其相应的DaemonSet控制器能够无视此类污点,便于节点上部署相应的关键性Pod对象,例如kube-proxy或kube- flannel等。

我们可以通过kubectl describe pod xx查看污点容忍信息,例如下面是kube-proxy的一些污点容忍配置:

java 复制代码
Tolerations:                 op=Exists
                             node.kubernetes.io/disk-pressure:NoSchedule op=Exists
                             node.kubernetes.io/memory-pressure:NoSchedule op=Exists
                             node.kubernetes.io/network-unavailable:NoSchedule op=Exists
                             node.kubernetes.io/not-ready:NoExecute op=Exists
                             node.kubernetes.io/pid-pressure:NoSchedule op=Exists
                             node.kubernetes.io/unreachable:NoExecute op=Exists
                             node.kubernetes.io/unschedulable:NoSchedule op=Exists

参考:污点和容忍度 | Kubernetes

相关推荐
南猿北者2 小时前
docker容器
docker·容器
YCyjs3 小时前
K8S群集调度二
云原生·容器·kubernetes
Hoxy.R3 小时前
K8s小白入门
云原生·容器·kubernetes
€☞扫地僧☜€6 小时前
docker 拉取MySQL8.0镜像以及安装
运维·数据库·docker·容器
全能全知者7 小时前
docker快速安装与配置mongoDB
mongodb·docker·容器
为什么这亚子9 小时前
九、Go语言快速入门之map
运维·开发语言·后端·算法·云原生·golang·云计算
ZHOU西口11 小时前
微服务实战系列之玩转Docker(十八)
分布式·docker·云原生·架构·数据安全·etcd·rbac
牛角上的男孩11 小时前
Istio Gateway发布服务
云原生·gateway·istio
JuiceFS13 小时前
好未来:多云环境下基于 JuiceFS 建设低运维模型仓库
运维·云原生
景天科技苑13 小时前
【云原生开发】K8S多集群资源管理平台架构设计
云原生·容器·kubernetes·k8s·云原生开发·k8s管理系统