Kubernetes 的污点 (Taint) 和容忍度 (Toleration) 是强大的机制,用于控制 Pod 在节点上的调度。它们允许对节点进行标记,并指定哪些 Pod 可以忽略这些标记并仍然被调度到这些节点上。 这对于实现节点隔离、资源专用以及处理节点维护非常有用,Kubernetes 污点和容忍度还可以与其他调度功能(如节点亲和性)结合使用。
污点 (Taint):
污点应用于节点,表示节点的一些特性或限制。 它本质上是一个标记,告诉 Kubernetes 调度程序避免将某些 Pod 调度到该节点。 一个污点包含三个部分:
key
: 污点的键,一个字符串,用于标识污点的类型。value
: 污点的值,一个字符串,提供关于污点类型的更多信息。可以为空字符串。effect
: 污点的效果,决定污点如何影响 Pod 的调度。 有三种效果:NoSchedule
:阻止 Pod 调度到该节点,除非 Pod 有匹配的容忍度。PreferNoSchedule
:调度程序会尽量避免将 Pod 调度到该节点,但如果必要,仍然可以调度。NoExecute
:驱逐节点上已经存在的、没有匹配容忍度的 Pod。 这通常用于维护。
容忍度 (Toleration):
容忍度应用于 Pod,表示 Pod 可以容忍某些节点上的污点。 它允许 Pod 被调度到具有匹配污点的节点上。 一个容忍度包含四个部分:
key
: 容忍度的键,必须与节点污点的键匹配。operator
: 运算符,指定如何匹配污点的值。 可以是:Equal
:污点的值必须与容忍度的值完全匹配。Exists
:只要污点的键存在即可,忽略污点的值。value
: 容忍度的值,如果operator
为Equal
,则必须与污点的值匹配。effect
: 容忍度的效果,必须与节点污点的效果匹配。
使用场景:
专用节点: 将节点标记为仅用于特定类型的应用程序。 例如,将节点标记为
gpu=true:NoSchedule
,只有具有gpu=true:NoSchedule
容忍度的 Pod 才能调度到该节点。节点维护: 在节点进行维护之前,使用
NoExecute
效果的污点驱逐节点上的 Pod,然后进行维护。隔离敏感数据: 将节点标记为仅用于处理敏感数据的应用程序。
资源隔离: 将节点标记为仅用于高内存或高 CPU 应用程序。
示例:
1. 添加污点:
kubectl taint nodes <node-name> key1=value1:NoSchedule
这将为名为 <node-name>
的节点添加一个污点,键为 key1
,值为 value1
,效果为 NoSchedule
。
2. 定义容忍度 (在 Pod 的 YAML 文件中):
apiVersion: v1 kind: Pod metadata: name: my-pod spec: containers: - name: my-container image: nginx:latest tolerations: - key: "key1" operator: "Equal" value: "value1" effect: "NoSchedule"
这将允许名为 my-pod
的 Pod 调度到具有 key1=value1:NoSchedule
污点的节点上。
3. 使用 Exists
运算符:
如果只想检查键的存在性,而忽略值:
apiVersion: v1 kind: Pod metadata: name: my-pod spec: containers: - name: my-container image: nginx:latest tolerations: - key: "key1" operator: "Exists" effect: "NoSchedule"
这将允许 my-pod
调度到任何具有 key1
键的污点的节点上,无论其值是什么。
注意事项:
匹配: 污点和容忍度必须完全匹配才能生效(除非使用
Exists
运算符,否则key
、value
和effect
必须完全匹配)。顺序: 先添加污点,再创建具有匹配容忍度的 Pod,容忍度的顺序无关紧要。
移除污点: 使用
kubectl taint nodes <node-name> <key>-
命令移除污点。谨慎操作: 不正确的污点和容忍度配置可能会导致 Pod 无法调度或被意外驱逐。
如果一个节点同时存在多个污点,Pod 的容忍度必须能够满足所有这些污点才能成功调度到该节点。 这意味着需要为每个污点在 Pod 的 tolerations
列表中添加一个对应的容忍度。
Kubernetes 处理多个污点和容忍度的方式就像一个过滤器:从节点的所有污点开始,然后忽略 pod 具有匹配容忍度的污点;其余未被忽略的污点对 pod 具有的效果如下:
如果至少有一个未被忽略的污点具有 NoSchedule 效果, 那么 Kubernetes 将不会将 pod 调度到该节点上。
如果没有未忽略的污点 NoSchedule ,但至少有一个未忽略的污点 PreferNoSchedule,则 Kubernetes 将尝试不将 pod 调度到节点上。
如果至少有一个未被忽略的污点 NoExecute,那么该 pod 将被从节点中逐出(如果它已经在节点上运行),并且不会被调度到节点上(如果它尚未在节点上运行)。
1.例如,假设我们的一个节点上有以下三个污点:
kubectl taint nodes node1 key1=value1:NoSchedule
kubectl taint nodes node1 key1=value1:NoExecute
kubectl taint nodes node1 key2=value2:NoSchedule
我们创建一个pod,但是只配置两种容忍度匹配两个污点:
tolerations: - key: "key1" operator: "Equal" value: "value1" effect: "NoSchedule" - key: "key1" operator: "Equal" value: "value1" effect: "NoExecute"
在这种情况下,pod 将无法调度到节点上,因为没有与第三个污点匹配的容忍度。但是,如果在添加污点时它已经在节点上运行,它将能够继续运行,因为第三个污点是三个污点中唯一一个不被 pod 容忍的污点。
通常情况下,如果将具有效果的污点 NoExecute 添加到节点,则任何不容忍该污点的 Pod 都会被立即驱逐,而容忍该污点的 Pod 则永远不会被驱逐。但是,具有 NoExecute 效果的容忍可以指定一个可选 tolerationSeconds 字段,该字段表示在添加污点后 Pod 将与节点保持绑定多长时间。例如:
tolerations: - key: "key1" operator: "Equal" value: "value1" effect: "NoExecute" tolerationSeconds: 3600这个配置表示如果此 pod 正在运行,并且节点上添加了匹配的污点,则 pod 将保持与节点的绑定状态 3600 秒,然后被驱逐。如果在此时间之前删除污点,则 pod 将不会被驱逐。
2.假设一个节点存在以下三个污点:
key=env,value=prod,effect=NoSchedule
key=disktype,value=ssd,effect=NoSchedule
key=zone,value=us-east-1,effect=NoSchedule
那么,Pod 的 tolerations
部分应该如下配置:
apiVersion: v1 kind: Pod metadata: name: my-pod spec: containers: - name: my-container image: nginx:latest tolerations: - key: "env" operator: "Equal" value: "prod" effect: "NoSchedule" - key: "disktype" operator: "Equal" value: "ssd" effect: "NoSchedule" - key: "zone" operator: "Equal" value: "us-east-1" effect: "NoSchedule"
这个配置确保了 my-pod
可以容忍这三个污点,从而能够被调度到该节点。
参考: