掘金 后端 ( ) • 2024-07-02 12:02

theme: channing-cyan

污点 Taint

污点的作用就像一个过滤器,能够使节点排斥一些Pod,它是一个作用于Node的键值对;熟悉K8S的同学可能立马能想到有一个相反作用的属性叫做节点亲和性Affinity,作用于Pod,使得Pod能够被吸引到一类特定的节点。

污点类型

根据effect值的不同,我们可以把污点分为三类,程度从高到低依次为

NoExecute

会影响已经在节点上运行的Pod

  • 如果Pod没有对应的容忍度,会被驱逐
  • 如果Pod有对应的容忍度,容忍度没有设置tolerationSeconds,则会一直在该节点上运行
  • 如果Pod有对应的容忍度,容忍度设置了tolerationSeconds,则会在到期后被驱逐

NoScedule

影响的是即将调度的Pod,如果Pod没有对应的容忍度则不会被调度到该节点上,不会影响正在节点上运行的Pod

PreferNoSchedule

是一个削弱版的NoScedule,影响的是即将调度的Pod,会尝试将Pod不调度到该节点上,但不能保证完全避免

删除和添加污点

添加污点

kubectl taint nodes node1 key1=value1:NoSchedule

给node1节点添加一个键名为key1,值为value1的键值对,effect的值是NoSchedule,作用和直译过来一样,就是不调度,只有具有和这个污点相匹配的容忍度的Pod才会被调度到这个节点上。

key+value+effect这三个字段构成了一个污点,只要其中有一个值不同,那么就是两个不同的污点,例如

kubectl taint nodes node1 key1=value1:NoSchedule
kubectl taint nodes node1 key1=value1:NoExecute

这就是两个不同的污点,第一个污点作用是不让Pod调度到Node上,第二个污点作用是让已经在Node上运行的Pod被驱逐。

删除污点

kubectl taint nodes node1 key1=value1:NoSchedule-

K8S调度器在选择一个节点来运行Pod时会考虑到污点和容忍度,然而如果你手动为Pod指定了.spec.nodeName,那么选节点的操作会绕过调度器,无论节点有没有NoSchedule污点,都会将这个Pod调度到指定的节点上。如果节点有NoExecute的污点,那么kubelet会将Pod再驱逐出去。

内置污点

前内置的污点包括:

  • node.kubernetes.io/not-ready:节点未准备好。这相当于节点状况 Ready 的值为 "False"。
  • node.kubernetes.io/unreachable:节点控制器访问不到节点. 这相当于节点状况 Ready 的值为 "Unknown"。
  • node.kubernetes.io/memory-pressure:节点存在内存压力,控制平面监测到节点状态缺乏内存资源,则会为Node添加这个污点。
  • node.kubernetes.io/disk-pressure:节点存在磁盘压力,同上。
  • node.kubernetes.io/pid-pressure:节点的 PID 压力,同上。
  • node.kubernetes.io/network-unavailable:节点网络不可用,同上。
  • node.kubernetes.io/unschedulable:节点不可调度,同上。
  • node.cloudprovider.kubernetes.io/uninitialized:如果 kubelet 启动时指定了一个“外部”云平台驱动, 它将给当前节点添加一个污点将其标志为不可用。在 cloud-controller-manager 的一个控制器初始化这个节点后,kubelet 将删除这个污点。

容忍度 Toleration

容忍度Toleration是应用于Pod的属性,它也是一个key:value键值对,还能附带额外的属性effect、operator、tolerationSecondoperator默认为equaltolerationSecond默认不设置,容忍度能够允许调度器将Pod调度到具有相应污点的节点上,但并不保证调度,因为调度器也会评估其他参数。

一个容忍度和一个污点相匹配,指的是

  • 当容忍度的operatorequal时,容忍度和污点的key+value+effect都匹配
  • 当容忍度的operatorexists时,容忍度和污点的key+effect匹配,此时容忍度无法设置value字段

污点和容忍度相互配合,可以实现一个双向的过滤器,用来避免Pod被分配到不合适的节点上。在调度某个Pod时会从一个节点的所有污点开始遍历,过滤掉存在容忍度相匹配的容忍度的污点,剩下的没有被过滤的污点的effect值决定了该Pod是否会被分配到该节点上

  • 如果至少存在一个NoSchedule的污点,那么就不会将Pod调度到该节点
  • 如果不存在NoSchedule的污点,但存在PreferNoSchedule的污点,则会尝试不将Pod调度到该节点
  • 如果至少存在一个NoExecute的污点,则在调度时不会将Pod调度到该节点,已在该节点上运行的Pod会被驱逐

内置容忍度

K8S会为每个Pod添加node.kubernetes.io/not-readynode.kubernetes.io/unreachable的容忍度,且配置tolerationSecond=300,除非用户自身或者控制器显式的设置容忍度。

实战

首先能看到minikube初始时只有一个节点,我们通过minikube node add命令往集群中添加几个节点,最后结果如下。

看一下添加污点之前的节点以及现在的pod运行情况,能看到现在的两个pod都是运行在minikube这个节点上的

为该节点添加两个污点,effect分别为NoScheduleNoExecute,因为NoExecute污点的存在,所以已经运行在该节点上的Pod会被驱逐,符合预期。

对应容忍度的Pod

apiVersion: v1
kind: Pod
metadata:
  name: test-taint-pod
spec:
  nodeName: minikube
  containers:
  - name: container-a
    image: alpine:latest
    command: ["sh", "-c", "while true; do echo hello; sleep 10; done"]
  tolerations:
    - key: "test"
      operator: "Equal"
      value: "true"
      effect: "NoSchedule"
    - key: "test2"
      operator: "Exists"
      effect: "NoExecute"