k8s 的污点与容忍度

污点和容忍度是相互匹配的关系,在node上定义一个污点,pod上定义容忍度,如果pod能容忍这个污点,就会被调度到拥有这个污点的节点上,不能容忍这个污点就不会调度到拥有这个污点的节点上,如果node节点上没有定义污点,那么任何pod都会调度到这个节点上

给节点添加污点

[root@master-1 ~]# kubectl taint node node-1 key=cx:NoSchedule
node/node-1 tainted

  删除污点

[root@master-1 ~]# kubectl taint node node-1 key:NoSchedule-
node/node-1 untainted

  

可以在 PodSpec 中为容器设定容忍标签。以下两个容忍标签都与上面的 kubectl taint 创建的污点匹配, 因此具有任一容忍标签的Pod都可以将其调度到 node-1 上:

 

tolerations:
- key: "key"
  operator: "Equal"
  value: "value"
  effect: "NoSchedule"

tolerations:
- key: "key"
  operator: "Exists"
  effect: "NoSchedule"

 

  

Equal 相当于等于号key 与 effect 还有 value精确匹配检查
Exists 相当于等于号key 与 effect 可以没有value 不检查value

如果一个 toleration  effect 为空,则 key 值与之相同的相匹配 taint  effect 可以是任意值。
tolerations:
- key: "key"
  operator: "Exists"

  

使用到的 effect 的一个值 NoSchedule也可以使用另外一个值 PreferNoSchedule。这是优化版本的 NoSchedule ——系统会 尽量 避免将 pod 调度到存在其不能容忍 taint 的节点上,但这不是强制的。effect 的值还可以设置为 NoExecute,下文会详细描述这个值


  • 如果未被过滤的 taint 中存在一个以上 effect 值为 NoSchedule taint,则 Kubernetes 不会将 pod 分配到该节点。
  • 如果未被过滤的 taint 中不存在 effect 值为 NoSchedule taint,但是存在 effect 值为 PreferNoSchedule taint,则 Kubernetes  尝试 pod 分配到该节点。
  • 如果未被过滤的 taint 中存在一个以上 effect 值为 NoExecute taint,则 Kubernetes 不会将 pod 分配到该节点(如果 pod 还未在节点上运行),或者将 pod 从该节点驱逐(如果 pod 已经在节点上运行)

 

kubectl taint nodes node-1 key1=value1:NoSchedule
kubectl taint nodes node-1 key1=value1:NoExecute
kubectl taint nodes node-1 key2=value2:NoSchedule
然后存在一个 pod,它有两个 toleration:
tolerations:
- key: "key1"
  operator: "Equal"
  value: "value1"
  effect: "NoSchedule" # 未运行是不分配
- key: "key1"
  operator: "Equal"
  value: "value1"
  effect: "NoExecute" #不会将 pod 分配到该节点(如果 pod 还未在节点上运行),或者将 pod 从该节点驱逐(如果 pod 已经在节点上运行)。

 

  

上述 pod 不会被分配到上述节点,因为其没有 toleration 和第三个 taint 相匹配。但是如果在给节点添加上述 taint 之前,该 pod 已经在上述节点运行,那么它还可以继续运行在该节点上,因为第三个 taint 是三个 taint 中唯一不能被这个 pod 容忍的。通常情况下,如果给一个节点添加了一个 effect 值为 NoExecute taint,则任何不能忍受这个 taint pod 都会马上被驱逐,任何可以忍受这个 taint pod 都不会被驱逐。但是,如果 pod 存在一个 effect 值为 NoExecute toleration 指定了可选属性 tolerationSeconds 的值,则表示在给节点添加了上述 taint 之后,pod 还能继续在节点上运行的时间。

 

tolerations:
- key: "key1"
  operator: "Equal"
  value: "value1"
  effect: "NoExecute"
  tolerationSeconds: 3600

 

  这表示如果这个 pod 正在运行,然后一个匹配的 taint 被添加到其所在的节点,那么 pod 还将继续在节点上运行 3600 秒,然后被驱逐。如果在此之前上述 taint 被删除了,则 pod 不会被驱逐。

  • 专用节点:如果想将某些节点专门分配给特定的一组用户使用,可以给这些节点添加一个 taint(即, kubectl taint nodes nodename dedicated=groupName:NoSchedule),然后给这组用户的 pod 添加一个相对应的 toleration(通过编写一个自定义的 admission controller,很容易就能做到)。拥有上述 toleration pod 就能够被分配到上述专用节点,同时也能够被分配到集群中的其它节点。如果希望这些 pod 只能被分配到上述专用节点,那么还需要给这些专用节点另外添加一个和上述 taint 类似的 label (例如:dedicated=groupName),同时 还要在上述 admission controller 中给 pod 增加节点亲和性要求上述 pod 只能被分配到添加了 dedicated=groupName 标签的节点上。
  • 配备了特殊硬件的节点:在部分节点配备了特殊硬件(比如 GPU)的集群中,我们希望不需要这类硬件的 pod 不要被分配到这些特殊节点,以便为后继需要这类硬件的 pod 保留资源。要达到这个目的,可以先给配备了特殊硬件的节点添加 taint(例如 kubectl taint nodes nodename special=true:NoSchedule or kubectl taint nodes nodename special=true:PreferNoSchedule),然后给使用了这类特殊硬件的 pod 添加一个相匹配的 toleration。和专用节点的例子类似,添加这个 toleration 的最简单的方法是使用自定义 admission controller。比如,我们推荐使用 Extended Resources 来表示特殊硬件,给配置了特殊硬件的节点添加 taint 时包含 extended resource 名称,然后运行一个 ExtendedResourceToleration admission controller。此时,因为节点已经被 打上taint 了,没有对应 toleration Pod 会被调度到这些节点。但当你创建一个使用了 extended resource Pod 时。ExtendedResourceToleration admission controller 会自动给 Pod 加上正确的 toleration ,这样 Pod 就会被自动调度到这些配置了特殊硬件件的节点上。这样就能够确保这些配置了特殊硬件的节点专门用于运行 需要使用这些硬件的 Pod,并且无需手动给这些 Pod 添加 toleration
  • 基于 taint 的驱逐: 这是在每个 pod 中配置的在节点出现问题时的驱逐行为
    • 如果 pod 不能忍受 effect 值为 NoExecute taint,那么 pod 将马上被驱逐
    • 如果 pod 能够忍受 effect 值为 NoExecute taint,但是在 toleration 定义中没有指定 tolerationSeconds,则 pod 还会一直在这个节点上运行。
    • 如果 pod 不能够忍受 effect 值为 NoExecute taint,而且指定了 tolerationSeconds,则 pod 还能在这个节点上继续运行这个指定的时间长度。

     

    此外,Kubernetes 1.6+ 已经支持(alpha阶段)节点问题的表示。换句话说,当某种条件为真时,node controller会自动给节点添加一个 taint。当前内置的 taint 包括:

    • node.kubernetes.io/not-ready:节点未准备好。这相当于节点状态 Ready 的值为 False
    • node.kubernetes.io/unreachablenode controller 访问不到节点. 这相当于节点状态 Ready 的值为 Unknown
    • node.kubernetes.io/out-of-disk:节点磁盘耗尽。
    • node.kubernetes.io/memory-pressure:节点存在内存压力。
    • node.kubernetes.io/disk-pressure:节点存在磁盘压力。
    • node.kubernetes.io/network-unavailable:节点网络不可用。
    • node.kubernetes.io/unschedulable: 节点不可调度。
    • node.cloudprovider.kubernetes.io/uninitialized:如果 kubelet 启动时指定了一个 外部” cloud provider,它将给当前节点添加一个 taint 将其标志为不可用。在 cloud-controller-manager 的一个 controller 初始化这个节点后,kubelet 将删除这个 taint

    在节点被驱逐时,节点控制器或者 kubelet 会添加带有 NoExecute 效应的相关污点。如果异常状态恢复正常,kubelet 或节点控制器能够移除相关的污点。

    注意:

    为了保证由于节点问题引起的 pod 驱逐rate limiting行为正常,系统实际上会以 rate-limited 的方式添加 taint。在像 master node 通讯中断等场景下,这避免了 pod 被大量驱逐。

    使用这个功能特性,结合 tolerationSecondspod 就可以指定当节点出现一个或全部上述问题时还将在这个节点上运行多长的时间。

    比如,一个使用了很多本地状态的应用程序在网络断开时,仍然希望停留在当前节点上运行一段较长的时间,愿意等待网络恢复以避免被驱逐。在这种情况下,pod toleration 可能是下面这样的

 

tolerations:
- key: "node.kubernetes.io/unreachable"
  operator: "Exists"
  effect: "NoExecute"
  tolerationSeconds: 6000

 

  

注意,Kubernetes 会自动给 pod 添加一个 key  node.kubernetes.io/not-ready toleration 并配置 tolerationSeconds=300,除非用户提供的 pod 配置中已经已存在了 key  node.kubernetes.io/not-ready toleration。同样,Kubernetes 会给 pod 添加一个 key  node.kubernetes.io/unreachable toleration 并配置 tolerationSeconds=300,除非用户提供的 pod 配置中已经已存在了 key  node.kubernetes.io/unreachable toleration

这种自动添加 toleration 机制保证了在其中一种问题被检测到时 pod 默认能够继续停留在当前节点运行 5 分钟。这两个默认 toleration 是由 DefaultTolerationSeconds admission controller添加的。

DaemonSet 中的 pod 被创建时,针对以下 taint 自动添加的 NoExecute toleration 将不会指定 tolerationSeconds

 

 

  • node.kubernetes.io/unreachable
  • node.kubernetes.io/not-ready

 

这保证了出现上述问题时 DaemonSet 中的 pod 永远不会被驱逐。

 

Node 生命周期控制器会自动创建与 Node 条件相对应的带有 NoSchedule 效应的污点。 同样,调度器不检查节点条件,而是检查节点污点。这确保了节点条件不会影响调度到节点上的内容。用户可以通过添加适当的 Pod 容忍度来选择忽略某些 Node 的问题(表示为 Node 的调度条件)

 

Kubernetes 1.8 起, DaemonSet 控制器自动为所有守护进程添加如下 NoSchedule toleration 以防 DaemonSet 崩溃:

 

  • node.kubernetes.io/memory-pressure
  • node.kubernetes.io/disk-pressure
  • node.kubernetes.io/out-of-disk (只适合 critical pod)
  • node.kubernetes.io/unschedulable (1.10 或更高版本)
  • node.kubernetes.io/network-unavailable (只适合 host network)
  • 添加上述 toleration 确保了向后兼容,也可以选择自由的向 DaemonSet 添加 toleration

测试

 

[root@master-1 pod]# kubectl taint node node-1 cx=cx-node:NoSchedule
node/node-1 tainted
[root@master-1 pod]# kubectl taint node node-2 cx=cx-node:NoSchedule
node/node-2 tainted
[root@master-1 pod]# cat pod-1.yaml   # 
apiVersion: v1
kind: Pod
metadata:
  name: nginx-test
spec:
  containers:
  - name: nginx
    image: nginx
[root@master-1 pod]# kubectl apply -f pod-1.yaml 
pod/nginx-test created
[root@master-1 pod]# kubectl get pod
NAME         READY   STATUS    RESTARTS   AGE
nginx-test   0/1     Pending   0          9s
[root@master-1 pod]# kubectl describe pods nginx-test
Name:         nginx-test
Namespace:    default
Priority:     0
Node:         <none>
Labels:       <none>
Annotations:  <none>
Status:       Pending
IP:           
IPs:          <none>
Containers:
  nginx:
    Image:        nginx
    Port:         <none>
    Host Port:    <none>
    Environment:  <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-w7bhz (ro)
Conditions:
  Type           Status
  PodScheduled   False 
Volumes:
  default-token-w7bhz:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-w7bhz
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                 node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
  Type     Reason            Age   From               Message
  ----     ------            ----  ----               -------
  Warning  FailedScheduling  2m8s  default-scheduler  0/3 nodes are available: 1 node(s) had taint {node-role.kubernetes.io/master: }, that the pod didn't tolerate, 2 node(s) had taint {cx: cx-node}, that the 
pod didn't tolerate.  Warning  FailedScheduling  2m8s  default-scheduler  0/3 nodes are available: 1 node(s) had taint {node-role.kubernetes.io/master: }, that the pod didn't tolerate, 2 node(s) had taint {cx: cx-node}, that the 
pod didn't tolerate.  #pod不容忍污点
[root@master-1 pod]# kubectl delete pods nginx-test 
pod "nginx-test" deleted
[root@master-1 pod]# cat pod-1.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: nginx-test
spec:
  containers:
  - name: nginx
    image: nginx
  tolerations: #定义pod容忍
  - key: cx
    value: cx-node
    effect: NoSchedule
[root@master-1 pod]# kubectl apply -f pod-1.yaml 
pod/nginx-test created
[root@master-1 pod]# kubectl get pod
NAME         READY   STATUS    RESTARTS   AGE
nginx-test   1/1     Running   0          7s
[root@master-1 pod]# kubectl describe pods nginx-test 
Name:         nginx-test
Namespace:    default
Priority:     0
Node:         node-1/192.168.10.30
Start Time:   Sun, 29 Jan 2023 09:31:00 +0800
Labels:       <none>
Annotations:  cni.projectcalico.org/podIP: 10.244.84.136/32
              cni.projectcalico.org/podIPs: 10.244.84.136/32
Status:       Running
IP:           10.244.84.136
IPs:
  IP:  10.244.84.136
Containers:
  nginx:
    Container ID:   docker://6007930c71983df9ba71b0ef27d59ffc663c659aab1bec18277136175c42ac0e
    Image:          nginx
    Image ID:       docker-pullable://nginx@sha256:b8f2383a95879e1ae064940d9a200f67a6c79e710ed82ac42263397367e7cc4e
    Port:           <none>
    Host Port:      <none>
    State:          Running
      Started:      Sun, 29 Jan 2023 09:31:06 +0800
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-w7bhz (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:
  default-token-w7bhz:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-w7bhz
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     cx=cx-node:NoSchedule
                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                 node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  80s   default-scheduler  Successfully assigned default/nginx-test to node-1
  Normal  Pulling    79s   kubelet            Pulling image "nginx"
  Normal  Pulled     74s   kubelet            Successfully pulled image "nginx" in 5.427330105s
  Normal  Created    74s   kubelet            Created container nginx
  Normal  Started    74s   kubelet            Started container nginx
[root@master-1 pod]# kubectl taint node node-1 cx:NoSchedule-  #删除污点
node/node-1 untainted

 

  

 

 

  

 

posted @ 2023-01-29 09:46  烟雨楼台,行云流水  阅读(193)  评论(0编辑  收藏  举报