2.6. 使用节点污点控制 pod 放置

通过污点和容限,节点可以控制哪些 Pod 应该(或不应该)调度到节点上。

2.6.1. 了解污点和容限

通过使用污点(taint),节点可以拒绝调度 pod,除非 pod 具有匹配的容限(toleration)

您可以通过节点规格 (NodeSpec) 将污点应用到节点,并通过 pod 规格 (PodSpec) 将容限应用到 pod。节点上的污点指示节点排斥所有不容许该污点的 pod。

污点与容限由 key、value 和 effect 组成。运算符允许您将其中一个参数留空。

表 2.1. 污点和容限组件

参数描述

key

key 是任意字符串,最多 253 个字符。key 必须以字母或数字开头,可以包含字母、数字、连字符、句点和下划线。

value

value 是任意字符串,最多 63 个字符。value 必须以字母或数字开头,可以包含字母、数字、连字符、句点和下划线。

effect

effect 的值包括:

NoSchedule

  • 与污点不匹配的新 pod 不会调度到该节点上。
  • 该节点上现有的 pod 会保留。

PreferNoSchedule

  • 与污点不匹配的新 pod 可以调度到该节点上,但调度程序会尽量不这样调度。
  • 该节点上现有的 pod 会保留。

NoExecute

  • 与污点不匹配的新 pod 无法调度到该节点上。
  • 节点上没有匹配容限的现有 pod 将被移除。

operator

Equal

key/value/effect 参数必须匹配。这是默认值。

Exists

key/effect 参数必须匹配。您必须保留一个空的 value 参数,这将匹配任何值。

容限与污点匹配:

  • 如果 operator 参数设为 Equal

    • key 参数相同;
    • value 参数相同;
    • effect 参数相同。
  • 如果 operator 参数设为 Exists

    • key 参数相同;
    • effect 参数相同。

Kubernetes 中内置了以下污点:

  • node.kubernetes.io/not-ready:节点未就绪。这与节点状况 Ready=False 对应。
  • node.kubernetes.io/unreachable:节点无法从节点控制器访问。这与节点状况 Ready=Unknown 对应。
  • node.kubernetes.io/out-of-disk:节点上的可用空间不足,无法添加新 pod。这与节点状况 OutOfDisk=True 对应。
  • node.kubernetes.io/memory-pressure:节点存在内存压力问题。这与节点状况 MemoryPressure=True 对应。
  • node.kubernetes.io/disk-pressure:节点存在磁盘压力问题。这与节点状况 DiskPressure=True 对应。
  • node.kubernetes.io/network-unavailable:节点网络不可用。
  • node.kubernetes.io/unschedulable:节点不可调度。
  • node.cloudprovider.kubernetes.io/uninitialized:当节点控制器通过外部云提供商启动时,在节点上设置这个污点来将其标记为不可用。在云控制器管理器中的某个控制器初始化这个节点后,kubelet 会移除此污点。

2.6.1.1. 了解如何使用容限秒数来延迟 pod 驱除

您可以通过在 pod 规格中指定 tolerationSeconds 参数,指定 pod 在被驱除前可以保持与节点绑定的时长。如果将具有 NoExecute effect 的污点添加到某个节点,则所有不容许该污点的 pod 都被立即驱除(容许该污点的 pod 不会被驱除)。但是,如果要被驱除的 pod 具有 tolerationSeconds 参数,则只有该时限到期后 pod 才会被驱除。

例如:

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

在这里,如果此 pod 正在运行但没有匹配的污点,pod 保持与节点绑定 3600 秒,然后被驱除。如果污点在这个时间之前移除,pod 就不会被驱除。

2.6.1.2. 了解如何使用多个污点

您可以在同一个节点中放入多个污点,并在同一 pod 中放入多个容限。OpenShift Container Platform 按照如下所述处理多个污点和容限:

  1. 处理 pod 具有匹配容限的污点。
  2. 其余的不匹配污点在 pod 上有指示的 effect:

    • 如果至少有一个不匹配污点具有 NoSchedule effect,则 OpenShift Container Platform 无法将 pod 调度到该节点上。
    • 如果没有不匹配污点具有 NoSchedule effect,但至少有一个不匹配污点具有 PreferNoSchedule effect,则 OpenShift Container Platform 尝试不将 pod 调度到该节点上。
    • 如果至少有一个未匹配污点具有 NoExecute effect,OpenShift Container Platform 会将 pod 从该节点驱除(如果它已在该节点上运行),或者不将 pod 调度到该节点上(如果还没有在该节点上运行)。

      • 不容许污点的 Pod 会立即被驱除。
      • 如果 Pod 容许污点,且没有在容限规格中指定 tolerationSeconds,则会永久保持绑定。
      • 如果 Pod 容许污点,且指定了 tolerationSeconds,则会在指定的时间里保持绑定。

例如:

  • 节点具有以下污点:

    $ oc adm taint nodes node1 key1=value1:NoSchedule
    $ oc adm taint nodes node1 key1=value1:NoExecute
    $ oc adm 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 已在节点上运行,pod 会继续运行,因为第三个污点是三个污点中 pod 唯一不容许的污点。

2.6.1.3. 防止因为节点问题而发生 pod 驱除

OpenShift Container Platform 可以配置为用污点来代表节点不可访问节点未就绪状况。这样,就可以对每个 pod 设置在节点变得不可访问或未就绪时保持与节点绑定的时长,而不是使用默认的五分钟。

Taint-Based Evictions 功能默认为启用。污点由节点控制器自动添加,而且会禁用从就绪节点驱除 pod 的一般逻辑。

  • 如果节点进入未就绪状态,则添加 node.kubernetes.io/not-ready:NoExecute 污点,并且无法将 pod 调度到该节点上。现有 pod 在容限秒数期限内保留。
  • 如果节点进入不可访问状态,则添加 node.kubernetes.io/unreachable:NoExecute 污点,并且无法将 pod 调度到该节点上。现有 pod 在容限秒数期限内保留。

此功能与 tolerationSeconds 相结合,可以允许 pod 指定它应当在多久时间内保持与具有一个或多个这种问题的节点的绑定。

2.6.1.4. 了解 pod 调度和节点状况(根据条件设置污点节点)

OpenShift Container Platform 会自动将报告内存压力和磁盘压力等状况的节点变成污点。如果某个节点报告一个状况,则添加一个污点,直到状况被清除为止。这些污点具有 NoSchedule effect;即,pod 无法调度到该节点上,除非 pod 有匹配的容限。此功能称为 根据条件设置污点节点(Taint Nodes By Condition),默认为启用。

在调度 pod 前,调度程序会检查节点上是否有这些污点。如果污点存在,则将 pod 调度到另一个节点。由于调度程序检查的是污点而非实际的节点状况,因此您可以通过添加适当的 Pod 容限,将调度程序配置为忽略其中一些节点状况。

DaemonSet 控制器会自动将下列容限添加到所有守护进程,以保证向后兼容性:

  • node.kubernetes.io/memory-pressure
  • node.kubernetes.io/disk-pressure
  • node.kubernetes.io/out-of-disk(仅限关键 pod)
  • node.kubernetes.io/unschedulable(1.10 或更高版本)
  • node.kubernetes.io/network-unavailable(仅限主机网络)

您还可以在 DaemonSet 中添加任意容限。

2.6.1.5. 了解根据状况驱除 pod (基于污点的驱除)

基于污点的驱除(Taint-Based Evictions)功能默认为启用,可以从遇到特定状况(如未就绪无法访问)的节点驱除 pod。当节点遇到其中一个状况时,OpenShift Container Platform 会自动给节点添加污点,并开始驱除 pod 以及将 pod 重新调度到其他节点。

Taint Based Evictions 具有 NoExecute effect,不容许污点的 pod 都会被立即驱除,而容许污点的 pod 则永不会被驱除。

注意

OpenShift Container Platform 会以限速方式驱除 pod,从而防止在主控机从节点分离等情形中发生大量 pod 驱除。

此功能与 tolerationSeconds 相结合,允许您指定 pod 应当在多久时间内保持与具有某一节点状况的节点的绑定。如果在 tolerationSections 到期后状况仍然存在,则污点会保持在节点上,并且 pod 会以限速方式被驱除。如果状况在 tolerationSeconds 到期前清除,则 pod 不会被移除。

OpenShift Container Platform 会自动为 node.kubernetes.io/not-readynode.kubernetes.io/unreachable 添加容限并设置 tolerationSeconds=300,除非 pod 配置中已指定了其中任一种容限。

spec
  tolerations:
    - key: node.kubernetes.io/not-ready
      operator: Exists
      effect: NoExecute
      tolerationSeconds: 300
    - key: node.kubernetes.io/unreachable
      operator: Exists
      effect: NoExecute
      tolerationSeconds: 300

这些容限确保了在默认情况下,pod 在检测到这些节点条件问题中的任何一个时,会保持绑定 5 分钟。

您可以根据需要配置这些容限。例如,如果您有一个具有许多本地状态的应用程序,您可能希望在发生网络分区时让 pod 与节点保持绑定更久一些,以等待分区恢复并避免 pod 驱除行为的发生。

DaemonSet pod 创建时具有以下污点的 NoExecute 容限,但没有设置 tolerationSeconds:

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

这可以确保 DaemonSet pod 不会因为这些节点状况而被驱除,即使 DefaultTolerationSeconds 准入控制器已被禁用。

2.6.2. 添加污点和容限

您可以给节点添加污点并给 pod 添加容限,让节点能够控制哪些 pod 应该(或不应该)调度到节点上。

流程

  1. 在以下命令中使用污点和容限组件表中描述的参数:

    $ oc adm taint nodes <node-name> <key>=<value>:<effect>

    例如:

    $ oc adm taint nodes node1 key1=value1:NoExecute

    本例在 node1 上放置一个键为 key1 且值为 value1 的污点,污点效果是 NoExecute

  2. 通过编辑 pod 规格以使其包含一个 tolerations 部分,给 pod 添加容限:

    使用 Equal 运算符的 pod 配置文件示例

    tolerations:
    - key: "key1" 1
      operator: "Equal" 2
      value: "value1" 3
      effect: "NoExecute" 4
      tolerationSeconds: 3600 5

    1 2 3 4
    容限参数,如污点和容限组件表中所述。
    5
    tolerationSeconds 参数指定 pod 在被驱除前可以保持与节点绑定的时长。

    例如:

    使用 Exists 运算符的 pod 配置文件示例

    tolerations:
    - key: "key1"
      operator: "Exists"
      effect: "NoExecute"
      tolerationSeconds: 3600

    这两个容限都与上述 oc adm taint 命令创建的污点匹配。具有任一容限的 pod 可以调度到 node1

2.6.2.1. 使用污点和容限为用户指定专用节点

您可以指定一组节点供一组特定用户独占使用。

流程

指定专用节点:

  1. 给这些节点添加污点:

    例如:

    $ oc adm taint nodes node1 dedicated=groupName:NoSchedule
  2. 通过编写自定义准入控制器,给 pod 添加对应的容限。

    只有具有这些容限的 pod 才可以使用专用节点。

2.6.2.2. 使用污点和容限将用户绑定到节点

您可以配置节点,使特定用户只能使用专用节点。

流程

配置节点以使用户只能使用该节点:

  1. 给这些节点添加污点:

    例如:

    $ oc adm taint nodes node1 dedicated=groupName:NoSchedule
  2. 通过编写自定义准入控制器,给 pod 添加对应的容限。

    准入控制器应该添加一个节点关联性,使得 pod 只能调度到具有 key:value 标签 (dedicated=groupName) 的节点。

  3. 给专用节点添加与污点类似的标签(如 key:value 标签)。

2.6.2.3. 使用污点和容限控制具有特殊硬件的节点

如果集群中有少量节点具有特殊的硬件(如 GPU),您可以使用污点和容限让不需要特殊硬件的 pod 与这些节点保持距离,从而将这些节点保留给那些确实需要特殊硬件的 pod。您还可以要求需要特殊硬件的 pod 使用特定的节点。

流程

确保 pod 被禁止使用特殊硬件:

  1. 使用以下命令之一,给拥有特殊硬件的节点添加污点:

    $ oc adm taint nodes <node-name> disktype=ssd:NoSchedule
    $ oc adm taint nodes <node-name> disktype=ssd:PreferNoSchedule
  2. 给利用准入控制器来使用特殊硬件的 pod 添加对应的容限。

例如,准入控制器可以使用 pod 的一些特征来决定是否应该允许 pod 通过添加容限来使用特殊节点。

要确保 pod 只能使用特殊硬件,您需要一些额外的机制。例如,您可以给具有特殊硬件的节点打上标签,并在需要该硬件的 pod 上使用节点关联性。

2.6.3. 删除污点和容限

您可以根据需要,从节点移除污点并从 pod 移除容限。

流程

移除污点和容限:

  1. 从节点移除污点:

    $ oc adm taint nodes <node-name> <key>-

    例如:

    $ oc adm taint nodes ip-10-0-132-248.ec2.internal key1-
    
    node/ip-10-0-132-248.ec2.internal untainted
  2. 要从 pod 移除某一容限,请编辑 pod 规格来移除该容限:

    tolerations:
    - key: "key2"
      operator: "Exists"
      effect: "NoExecute"
      tolerationSeconds: 3600