×

理解污点和容忍度

污点允许节点拒绝调度 Pod,除非该 Pod 具有匹配的容忍度

您可以通过Node规范 (NodeSpec) 将污点应用于节点,并通过Pod规范 (PodSpec) 将容忍度应用于 Pod。当您将污点应用于节点时,除非 Pod 可以容忍该污点,否则调度程序无法将 Pod 放置到该节点上。

节点规范中的污点示例
apiVersion: v1
kind: Node
metadata:
  name: my-node
#...
spec:
  taints:
  - effect: NoExecute
    key: key1
    value: value1
#...
Pod规范中的容忍度示例
apiVersion: v1
kind: Pod
metadata:
  name: my-pod
#...
spec:
  tolerations:
  - key: "key1"
    operator: "Equal"
    value: "value1"
    effect: "NoExecute"
    tolerationSeconds: 3600
#...

污点和容忍度由键、值和效果组成。

表 1. 污点和容忍度组件
参数 描述

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

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

效果

效果是以下之一

NoSchedule [1]

  • 不匹配污点的新的 Pod 不会调度到该节点上。

  • 节点上现有的 Pod 保持不变。

PreferNoSchedule

  • 不匹配污点的新的 Pod 可能会调度到该节点上,但调度程序会尽量避免。

  • 节点上现有的 Pod 保持不变。

NoExecute

  • 不匹配污点的新的 Pod 无法调度到该节点上。

  • 节点上不存在匹配容忍度的现有 Pod 将被移除。

运算符

等于

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

存在

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

  1. 如果您向控制平面节点添加NoSchedule污点,则该节点必须具有node-role.kubernetes.io/master=:NoSchedule污点,该污点默认添加。

    例如

    apiVersion: v1
    kind: Node
    metadata:
      annotations:
        machine.openshift.io/machine: openshift-machine-api/ci-ln-62s7gtb-f76d1-v8jxv-master-0
        machineconfiguration.openshift.io/currentConfig: rendered-master-cdc1ab7da414629332cc4c3926e6e59c
      name: my-node
    #...
    spec:
      taints:
      - effect: NoSchedule
        key: node-role.kubernetes.io/master
    #...

容忍度与污点匹配

  • 如果operator参数设置为Equal

    • key参数相同;

    • value参数相同;

    • effect参数相同。

  • 如果operator参数设置为Exists

    • key参数相同;

    • effect参数相同。

以下污点内置于 OpenShift Container Platform 中

  • node.kubernetes.io/not-ready:节点未就绪。这对应于节点状态Ready=False

  • node.kubernetes.io/unreachable:节点控制器无法访问该节点。这对应于节点状态Ready=Unknown

  • 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 将移除此污点。

  • node.kubernetes.io/pid-pressure:节点存在 PID 压力。这对应于节点状态PIDPressure=True

    OpenShift Container Platform 没有设置默认的 pid.available evictionHard

了解如何使用容忍度秒数来延迟 Pod 驱逐

您可以通过在Pod规范或MachineSet对象中指定tolerationSeconds参数来指定 Pod 在被驱逐之前可以在节点上保持绑定状态的时间长度。如果向节点添加了具有NoExecute效果的污点,则具有tolerationSeconds参数的、不耐受该污点的 Pod 只有在该时间段到期后才会被驱逐。

示例输出
apiVersion: v1
kind: Pod
metadata:
  name: my-pod
#...
spec:
  tolerations:
  - key: "key1"
    operator: "Equal"
    value: "value1"
    effect: "NoExecute"
    tolerationSeconds: 3600
#...

在此示例中,如果此 Pod 正在运行但没有匹配的容忍度,则 Pod 将保持与节点绑定 3600 秒,然后被驱逐。如果在此之前移除了污点,则 Pod 不会被驱逐。

了解如何使用多个污点

您可以在同一节点上设置多个污点,在同一 Pod 上设置多个容忍度。OpenShift Container Platform 按如下方式处理多个污点和容忍度:

  1. 处理 Pod 具有匹配容忍度的污点。

  2. 剩余的不匹配污点对 Pod 产生指示的效果。

    • 如果至少存在一个具有NoSchedule效果的不匹配污点,则 OpenShift Container Platform 无法将 Pod 调度到该节点。

    • 如果没有具有NoSchedule效果的不匹配污点,但至少存在一个具有PreferNoSchedule效果的不匹配污点,则 OpenShift Container Platform 会尝试不将 Pod 调度到该节点。

    • 如果至少存在一个具有NoExecute效果的不匹配污点,则 OpenShift Container Platform 会将 Pod 从节点驱逐(如果它已经在节点上运行),或者 Pod 不会被调度到节点上(如果它尚未在节点上运行)。

      • 不耐受污点的 Pod 会立即被驱逐。

      • 耐受污点且未在其Pod规范中指定tolerationSeconds的 Pod 将永远保持绑定状态。

      • 耐受污点并指定了tolerationSeconds的 Pod 将保持绑定指定的时间量。

例如

  • 向节点添加以下污点

    $ 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 具有以下容忍度

    apiVersion: v1
    kind: Pod
    metadata:
      name: my-pod
    #...
    spec:
      tolerations:
      - key: "key1"
        operator: "Equal"
        value: "value1"
        effect: "NoSchedule"
      - key: "key1"
        operator: "Equal"
        value: "value1"
        effect: "NoExecute"
    #...

在这种情况下,由于没有容忍度与第三个污点匹配,因此无法将 Pod 调度到节点。如果在添加污点时 Pod 已经在节点上运行,则 Pod 会继续运行,因为第三个污点是三个污点中唯一一个不被 Pod 容忍的污点。

了解 Pod 调度和节点状态(按状态污点节点)

按状态污点节点功能(默认启用)会自动对报告内存压力和磁盘压力等状态的节点添加污点。如果节点报告某个状态,则会添加污点,直到该状态清除。这些污点具有NoSchedule效果,这意味着除非 Pod 具有匹配的容忍度,否则任何 Pod 都无法调度到该节点。

调度程序在调度 Pod 之前会检查节点上的这些污点。如果存在污点,则 Pod 将调度到其他节点。由于调度程序检查的是污点而不是实际的节点状态,因此您可以通过添加相应的 Pod 容忍度来配置调度程序忽略其中一些节点状态。

为了确保向后兼容性,守护程序集控制器会自动向所有守护程序添加以下容忍度:

  • node.kubernetes.io/memory-pressure

  • node.kubernetes.io/disk-pressure

  • node.kubernetes.io/unschedulable(1.10 或更高版本)

  • node.kubernetes.io/network-unavailable(仅限主机网络)

您还可以向守护程序集添加任意容忍度。

控制平面还会在具有 QoS 类别的 Pod 上添加node.kubernetes.io/memory-pressure容忍度。这是因为 Kubernetes 管理GuaranteedBurstableQoS 类别的 Pod。新的BestEffort Pod 不会被调度到受影响的节点。

了解按状态驱逐 Pod(基于污点的驱逐)

基于污点的驱逐功能(默认启用)会将 Pod 从遇到特定状态(例如not-readyunreachable)的节点驱逐。当节点遇到这些状态之一时,OpenShift Container Platform 会自动向节点添加污点,并开始将 Pod 驱逐并重新调度到其他节点。

基于污点的驱逐具有NoExecute效果,任何不耐受污点的 Pod 都会立即被驱逐,任何耐受污点的 Pod 永远不会被驱逐,除非 Pod 使用tolerationSeconds参数。

tolerationSeconds参数允许您指定 Pod 保持绑定到具有节点状态的节点的时间长度。如果在tolerationSeconds时间段后状态仍然存在,则污点将保留在节点上,并且具有匹配容忍度的 Pod 将被驱逐。如果在tolerationSeconds时间段之前状态清除,则具有匹配容忍度的 Pod 不会被移除。

如果您使用tolerationSeconds参数且没有值,则由于节点未就绪和不可访问的状态,Pod 永远不会被驱逐。

OpenShift Container Platform 以限速的方式驱逐 Pod,以防止在诸如主节点与节点分区等场景中发生大规模 Pod 驱逐。

默认情况下,如果给定区域中超过 55% 的节点不健康,节点生命周期控制器会将该区域的状态更改为PartialDisruption,并且 Pod 驱逐速率会降低。对于处于此状态的小型集群(默认情况下,50 个节点或更少),该区域中的节点不会被污染,并且驱逐操作将停止。

更多信息,请参见 Kubernetes 文档中的驱逐限速

OpenShift Container Platform 自动添加对node.kubernetes.io/not-readynode.kubernetes.io/unreachable 的容忍,tolerationSeconds=300,除非Pod配置指定了任一容忍。

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
#...
spec:
  tolerations:
  - key: node.kubernetes.io/not-ready
    operator: Exists
    effect: NoExecute
    tolerationSeconds: 300 (1)
  - key: node.kubernetes.io/unreachable
    operator: Exists
    effect: NoExecute
    tolerationSeconds: 300
#...
1 这些容忍确保默认的 Pod 行为是在检测到这些节点条件问题后保持绑定五分钟。

您可以根据需要配置这些容忍。例如,如果您有一个具有大量本地状态的应用程序,您可能希望在网络分区的情况下将 Pod 绑定到节点更长时间,从而允许分区恢复并避免 Pod 驱逐。

由 DaemonSet 生成的 Pod 会为以下污点创建NoExecute容忍,且没有tolerationSeconds

  • node.kubernetes.io/unreachable

  • node.kubernetes.io/not-ready

因此,DaemonSet Pod 永远不会因为这些节点条件而被驱逐。

容忍所有污点

您可以通过添加一个operator: "Exists" 的容忍,且没有keyvalues参数来配置 Pod 以容忍所有污点。具有此容忍的 Pod 不会从具有污点的节点中移除。

容忍所有污点的 Pod 规范
apiVersion: v1
kind: Pod
metadata:
  name: my-pod
#...
spec:
  tolerations:
  - operator: "Exists"
#...

添加污点和容忍

您可以向 Pod 添加容忍,向节点添加污点,以允许节点控制哪些 Pod 应该或不应该在其上调度。对于现有 Pod 和节点,您应该首先将容忍添加到 Pod,然后将污点添加到节点,以避免在您可以添加容忍之前 Pod 从节点中移除。

步骤
  1. 通过编辑Pod规范以包含tolerations部分来向 Pod 添加容忍。

    使用 Equal 运算符的 Pod 配置文件示例
    apiVersion: v1
    kind: Pod
    metadata:
      name: my-pod
    #...
    spec:
      tolerations:
      - key: "key1" (1)
        value: "value1"
        operator: "Equal"
        effect: "NoExecute"
        tolerationSeconds: 3600 (2)
    #...
    1 容忍参数,如污点和容忍组件表中所述。
    2 tolerationSeconds参数指定 Pod 在被驱逐之前可以绑定到节点的时间长度。

    例如

    使用 Exists 运算符的 Pod 配置文件示例
    apiVersion: v1
    kind: Pod
    metadata:
      name: my-pod
    #...
    spec:
       tolerations:
        - key: "key1"
          operator: "Exists" (1)
          effect: "NoExecute"
          tolerationSeconds: 3600
    #...
    1 Exists运算符不接受value

    此示例在node1上放置一个污点,该污点具有键key1、值value1和污点效果NoExecute

  2. 使用以下命令并使用污点和容忍组件表中描述的参数向节点添加污点

    $ oc adm taint nodes <node_name> <key>=<value>:<effect>

    例如

    $ oc adm taint nodes node1 key1=value1:NoExecute

    此命令在node1上放置一个污点,该污点具有键key1、值value1和效果NoExecute

    如果您向控制平面节点添加NoSchedule污点,则该节点必须具有node-role.kubernetes.io/master=:NoSchedule污点,该污点默认添加。

    例如

    apiVersion: v1
    kind: Node
    metadata:
      annotations:
        machine.openshift.io/machine: openshift-machine-api/ci-ln-62s7gtb-f76d1-v8jxv-master-0
        machineconfiguration.openshift.io/currentConfig: rendered-master-cdc1ab7da414629332cc4c3926e6e59c
      name: my-node
    #...
    spec:
      taints:
      - effect: NoSchedule
        key: node-role.kubernetes.io/master
    #...

    Pod 上的容忍与节点上的污点匹配。具有任一容忍的 Pod 都可以调度到node1上。

使用计算机组添加污点和容忍

您可以使用计算主机组向节点添加污点。与MachineSet对象关联的所有节点都将使用污点更新。容忍以与直接添加到节点的污点相同的方式响应由计算主机组添加的污点。

步骤
  1. 通过编辑Pod规范以包含tolerations部分来向 Pod 添加容忍。

    使用Equal运算符的 Pod 配置文件示例
    apiVersion: v1
    kind: Pod
    metadata:
      name: my-pod
    #...
    spec:
      tolerations:
      - key: "key1" (1)
        value: "value1"
        operator: "Equal"
        effect: "NoExecute"
        tolerationSeconds: 3600 (2)
    #...
    1 容忍参数,如污点和容忍组件表中所述。
    2 tolerationSeconds参数指定 Pod 在被驱逐之前绑定到节点的时间长度。

    例如

    使用Exists运算符的 Pod 配置文件示例
    apiVersion: v1
    kind: Pod
    metadata:
      name: my-pod
    #...
    spec:
      tolerations:
      - key: "key1"
        operator: "Exists"
        effect: "NoExecute"
        tolerationSeconds: 3600
    #...
  2. 将污点添加到MachineSet对象

    1. 编辑您要污点的节点的MachineSet YAML,或者您可以创建一个新的MachineSet对象。

      $ oc edit machineset <machineset>
    2. 将污点添加到spec.template.spec部分。

      计算主机组规范中的污点示例
      apiVersion: machine.openshift.io/v1beta1
      kind: MachineSet
      metadata:
        name: my-machineset
      #...
      spec:
      #...
        template:
      #...
          spec:
            taints:
            - effect: NoExecute
              key: key1
              value: value1
      #...

      此示例放置一个污点,该污点在节点上具有键key1、值value1和污点效果NoExecute

    3. 将计算主机组缩减到 0。

      $ oc scale --replicas=0 machineset <machineset> -n openshift-machine-api

      或者,您可以应用以下 YAML 来缩放计算主机组。

      apiVersion: machine.openshift.io/v1beta1
      kind: MachineSet
      metadata:
        name: <machineset>
        namespace: openshift-machine-api
      spec:
        replicas: 0

      等待机器被移除。

    4. 根据需要扩展计算主机组。

      $ oc scale --replicas=2 machineset <machineset> -n openshift-machine-api

      或者

      $ oc edit machineset <machineset> -n openshift-machine-api

      等待机器启动。污点将添加到与MachineSet对象关联的节点。

使用污点和容忍将用户绑定到节点

如果您想将一组节点专供特定用户组使用,请向其 Pod 添加容忍。然后,向这些节点添加相应的污点。具有容忍的 Pod 允许使用被污点的节点或集群中的任何其他节点。

如果您想确保 Pod 只调度到那些被污点的节点,还可以向同一组节点添加标签,并向 Pod 添加节点亲和性,以便 Pod 只能调度到具有该标签的节点上。

步骤

要配置节点以便用户只能使用该节点

  1. 向这些节点添加相应的污点

    例如

    $ oc adm taint nodes node1 dedicated=groupName:NoSchedule

    或者,您可以应用以下 YAML 来添加污点

    kind: Node
    apiVersion: v1
    metadata:
      name: my-node
    #...
    spec:
      taints:
        - key: dedicated
          value: groupName
          effect: NoSchedule
    #...
  2. 通过编写自定义准入控制器向 Pod 添加容忍。

创建具有节点选择器和容忍的项目

您可以创建一个使用节点选择器和容忍(设置为注释)的项目,以控制 Pod 到特定节点的放置。然后,在项目中创建的任何后续资源都将调度到具有与容忍匹配的污点的节点上。

先决条件
  • 已使用计算主机组或直接编辑节点向一个或多个节点添加了节点选择标签。

  • 已使用计算主机组或直接编辑节点向一个或多个节点添加了污点。

步骤
  1. 创建Project资源定义,在metadata.annotations部分指定节点选择器和容忍。

    project.yaml文件示例
    kind: Project
    apiVersion: project.openshift.io/v1
    metadata:
      name: <project_name> (1)
      annotations:
        openshift.io/node-selector: '<label>' (2)
        scheduler.alpha.kubernetes.io/defaultTolerations: >-
          [{"operator": "Exists", "effect": "NoSchedule", "key":
          "<key_name>"} (3)
          ]
    1 项目名称。
    2 默认节点选择器标签。
    3 容忍参数,如污点和容忍组件表中所述。此示例使用NoSchedule效果,允许节点上现有的 Pod 保持不变,并使用Exists运算符,该运算符不接受值。
  2. 使用oc apply命令创建项目。

    $ oc apply -f project.yaml

现在,在<project_name>命名空间中创建的任何后续资源都应该调度到指定的节点上。

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

在一个集群中,如果只有一小部分节点拥有专用硬件,您可以使用污点和容忍来阻止不需要专用硬件的 Pod 使用这些节点,从而将这些节点留给需要专用硬件的 Pod。您还可以要求需要专用硬件的 Pod 使用特定的节点。

您可以通过向需要特殊硬件的 Pod 添加容忍,并对拥有专用硬件的节点添加污点来实现此目的。

步骤

确保拥有专用硬件的节点保留给特定的 Pod

  1. 向需要特殊硬件的 Pod 添加容忍。

    例如

    apiVersion: v1
    kind: Pod
    metadata:
      name: my-pod
    #...
    spec:
      tolerations:
        - key: "disktype"
          value: "ssd"
          operator: "Equal"
          effect: "NoSchedule"
          tolerationSeconds: 3600
    #...
  2. 使用以下命令之一对拥有专用硬件的节点添加污点

    $ oc adm taint nodes <node-name> disktype=ssd:NoSchedule

    或者

    $ oc adm taint nodes <node-name> disktype=ssd:PreferNoSchedule

    或者,您可以应用以下 YAML 来添加污点

    kind: Node
    apiVersion: v1
    metadata:
      name: my_node
    #...
    spec:
      taints:
        - key: disktype
          value: ssd
          effect: PreferNoSchedule
    #...

移除污点和容忍

您可以根据需要从节点中移除污点,从 Pod 中移除容忍。您应该先向 Pod 添加容忍,然后再向节点添加污点,以避免在您添加容忍之前 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规范以移除容忍

    apiVersion: v1
    kind: Pod
    metadata:
      name: my-pod
    #...
    spec:
      tolerations:
      - key: "key2"
        operator: "Exists"
        effect: "NoExecute"
        tolerationSeconds: 3600
    #...