2.7. 使用节点选择器将 pod 放置到特定节点

节点选择器指定一个键值对映射。使用节点中的自定义标签和 pod 中指定的选择器来定义规则。您可以使用特定节点选择器将特定的 pod 放置到特定的节点上,项目节点选择器将新 pod 放置到该项目的特定节点上,或默认的集群范围节点选择器,以将新 pod 放置到集群中的任何特定节点上。

要使 pod 有资格在节点上运行,pod 必须具有与节点上标签相同的键值节点选择器。

重要

如果您在同一 pod 配置中使用节点选择器和节点关联性,则以下规则控制 pod 放置到节点上:

  • 如果同时配置了 nodeSelectornodeAffinity,则必须满足这两个条件时 pod 才能调度到候选节点。
  • 如果您指定了多个与 nodeAffinity 类型关联的 nodeSelectorTerms,那么其中一个 nodeSelectorTerms 满足时 pod 就能调度到节点上。
  • 如果您指定了多个与 nodeSelectorTerms 关联的 matchExpressions,那么只有所有 matchExpressions 都满足时 pod 才能调度到节点上。

2.7.1. 使用节点选择器控制 pod 放置

您可以使用 pod 上的节点选择器标签来控制 pod 的调度位置。

使用节点选择器时,OpenShift Container Platform 会将 pod 调度到包含匹配标签的节点。

要向现有的 pod 添加节点选择器,请将节点选择器添加到该节点的控制对象,如 ReplicaSet、Daemonset 或 StatefulSet。任何属于该控制对象的现有 pod 都会在具有匹配标签的节点上重新创建。如果要创建新 pod,可以将节点选择器直接添加到 pod 规格中。

您可以向节点或 MachineConfig 添加标签,但标签不会在节点或机器停机后保留。将标签添加到 MachineSet 可确保新的节点或机器具有该标签。

注意

您不能直接将节点选择器添加到现有调度的 pod 中。

前提条件

要将节点选择器添加到现有 pod 中,请确定该 pod 的控制对象。例如,router-default-66d5cf9464-m2g75 pod 由 router-default-66d5cf9464 ReplicaSet 控制:

$ oc describe pod router-default-66d5cf9464-7pwkc

Name:               router-default-66d5cf9464-7pwkc
Namespace:          openshift-ingress

....

Controlled By:      ReplicaSet/router-default-66d5cf9464

Web 控制台在 pod YAML 的 ownerReferences 下列出控制对象:

  ownerReferences:
    - apiVersion: apps/v1
      kind: ReplicaSet
      name: router-default-66d5cf9464
      uid: d81dd094-da26-11e9-a48a-128e7edf0312
      controller: true
      blockOwnerDeletion: true

流程

  1. 通过使用 MachineSet 或直接编辑节点,为节点添加标签:

    • 在创建节点时,使用 MachineSet 将标签添加到由 MachineSet 管理的节点上:

      1. 运行以下命令,将节点选择器添加到 MachineSet 中:

        $ oc patch MachineSet <name> --type='json' -p='[{"op":"add","path":"/spec/template/spec/metadata/labels", "value":{"<key>"="<value>","<key>"="<value>"}}]'  -n openshift-machine-api

        例如:

        $ oc patch MachineSet abc612-msrtw-worker-us-east-1c  --type='json' -p='[{"op":"add","path":"/spec/template/spec/metadata/labels", "value":{"type":"user-node","region":"east"}}]'  -n openshift-machine-api
      2. 使用 oc edit 命令验证标签是否已添加到 MachineSet:

        例如:

        $ oc edit MachineSet abc612-msrtw-worker-us-east-1c -n openshift-machine-api

        MachineSet 对象示例

        apiVersion: machine.openshift.io/v1beta1
        kind: MachineSet
        
        ....
        
        spec:
        ...
          template:
            metadata:
        ...
            spec:
              metadata:
                labels:
                  region: east
                  type: user-node
        ....
    • 直接向节点添加标签:

      1. 为节点编辑 Node 对象:

        $ oc label nodes <name> <key>=<value>

        例如,若要为以下节点添加标签:

        $ oc label nodes ip-10-0-142-25.ec2.internal type=user-node region=east
      2. 验证标签是否已添加到节点:

        $ oc get nodes -l type=user-node,region=east

        输出示例

        NAME                          STATUS   ROLES    AGE   VERSION
        ip-10-0-142-25.ec2.internal   Ready    worker   17m   v1.18.3+002a51f

  2. 将匹配的节点选择器添加到 pod:

    • 要将节点选择器添加到现有和未来的 pod,请向 pod 的控制对象添加节点选择器:

      ReplicaSet 对象示例

      kind: ReplicaSet
      
      ....
      
      spec:
      
      ....
      
        template:
          metadata:
            creationTimestamp: null
            labels:
              ingresscontroller.operator.openshift.io/deployment-ingresscontroller: default
              pod-template-hash: 66d5cf9464
          spec:
            nodeSelector:
              beta.kubernetes.io/os: linux
              node-role.kubernetes.io/worker: ''
              type: user-node 1

      1
      添加节点选择器。
    • 要将节点选择器添加到特定的 pod,直接将选择器添加到 Pod 对象中:

      Pod 对象示例

      apiVersion: v1
      kind: Pod
      
      ...
      
      spec:
        nodeSelector:
          <key>: <value>
      
      ...

      例如:

      使用节点选择器的 Pod 对象示例

      apiVersion: v1
      kind: Pod
      
      ....
      
      spec:
        nodeSelector:
          region: east
          type: user-node

2.7.2. 创建默认的集群范围节点选择器

您可以组合使用 pod 上的默认集群范围节点选择器和节点上的标签,将集群中创建的所有 pod 限制到特定节点。

使用集群范围节点选择器时,如果您在集群中创建 pod,OpenShift Container Platform 会将默认节点选择器添加到 pod,并将该 pod 调度到具有匹配标签的节点。

您可以通过创建调度程序 Operator 自定义资源(CR)来配置集群范围节点选择器。您可以通过编辑节点对象、MachineSet 或 MachineConfig 向节点添加标签。将标签添加到 MachineSet 可确保节点或机器停机时,新节点具有标签。如果节点或机器停机,添加到节点或 MachineConfig 的标签不会保留。

例如,调度程序配置集群范围的 region=east 节点选择器:

Scheduler Operator 自定义资源示例

apiVersion: config.openshift.io/v1
kind: Scheduler
metadata:
  name: cluster
...

spec:
  defaultNodeSelector: type=user-node,region=east 1
...

集群中的节点具有 type=user-node,region=east 标签:

节点对象示例

apiVersion: v1
kind: Node
metadata:
  name: ci-ln-qg1il3k-f76d1-hlmhl-worker-b-df2s4
...
  labels:
    region: east
    type: user-node
...

如果您在该集群中创建 pod,则该 pod 使用集群范围节点选择器创建,并调度到标记的节点:

Pod 对象示例

apiVersion: v1
kind: Pod
...

spec:
  nodeSelector:
    region: east
...

在标记的节点上带有 pod 的 pod 列表示例

NAME     READY   STATUS    RESTARTS   AGE   IP           NODE                                       NOMINATED NODE   READINESS GATES
pod-s1   1/1     Running   0          20s   10.131.2.6   ci-ln-qg1il3k-f76d1-hlmhl-worker-b-df2s4   <none>           <none>

注意

如果您在其中创建 pod 的项目具有项目节点选择器,则该选择器优先于集群范围节点选择器。如果 Pod spec 中的节点选择器不使用项目节点选择器,则 Pod 不会被创建或调度。

如果 Pod 对象包含不是集群范围节点选择器或项目节点选择器,则 pod 不会被创建或调度。例如,如果您将以下 Pod 部署到示例项目中,则不会创建它:

带有无效节点选择器的 Pod 输出示例

apiVersion: v1
kind: Pod
....

spec:
  nodeSelector:
    region: west

从该 spec 创建 pod 时,您收到类似以下消息的错误:

错误信息示例

Error from server (Forbidden): error when creating "pod.yaml": pods "pod-4" is forbidden: pod node label selector conflicts with its project node label selector

注意

您可以向 pod 添加额外的键/值对。但是,您无法为默认项目键添加其他值。

流程

添加默认的集群范围节点选择器:

  1. 编辑调度程序 Operator 自定义资源以添加集群节点选择器:

    $ oc edit scheduler cluster
    apiVersion: config.openshift.io/v1
    kind: Scheduler
    metadata:
      name: cluster
    ...
    
    spec:
      defaultNodeSelector: type=user-node,region=east 1
      mastersSchedulable: false
      policy:
        name: ""
    1 1
    使用适当的 <key>:<value> 对添加节点选择器。

    完成此更改后,请等待重新部署 openshift-kube-apiserver 项目中的 pod。这可能需要几分钟。只有 pod 重新部署后,默认集群节点选择器才会生效。

  2. 通过使用 MachineSet 或直接编辑节点,为节点添加标签:

    • 在创建节点时,使用 MachineSet 将标签添加到由 MachineSet 管理的节点上:

      1. 运行以下命令,将节点选择器添加到 MachineSet 中:

        $ oc patch MachineSet <name> --type='json' -p='[{"op":"add","path":"/spec/template/spec/metadata/labels", "value":{"<key>"="<value>","<key>"="<value>"}}]'  -n openshift-machine-api 1
        1
        为每个节点选择器添加 <key> /<value> 对。

        例如:

        $ oc patch MachineSet ci-ln-l8nry52-f76d1-hl7m7-worker-c --type='json' -p='[{"op":"add","path":"/spec/template/spec/metadata/labels", "value":{"type":"user-node","region":"east"}}]'  -n openshift-machine-api
      2. 使用 oc edit 命令验证标签是否已添加到 MachineSet:

        例如:

        $ oc edit MachineSet ci-ln-l8nry52-f76d1-hl7m7-worker-c -n openshift-machine-api

        输出示例

        apiVersion: machine.openshift.io/v1beta1
        kind: MachineSet
        metadata:
        ...
        spec:
        ...
          template:
            metadata:
        ...
            spec:
              metadata:
                labels:
                  region: east
                  type: user-node

      3. 通过缩减至 0 并扩展节点来重新部署与该 MachineSet 关联的节点:

        例如:

        $ oc scale --replicas=0 MachineSet ci-ln-l8nry52-f76d1-hl7m7-worker-c -n openshift-machine-api
        $ oc scale --replicas=1 MachineSet ci-ln-l8nry52-f76d1-hl7m7-worker-c -n openshift-machine-api
      4. 当节点就绪并可用时,使用 oc get 命令验证该标签是否已添加到节点:

        $ oc get nodes -l <key>=<value>

        例如:

        $ oc get nodes -l type=user-node

        输出示例

        NAME                                       STATUS   ROLES    AGE   VERSION
        ci-ln-l8nry52-f76d1-hl7m7-worker-c-vmqzp   Ready    worker   61s   v1.18.3+002a51f

    • 直接向节点添加标签:

      1. 为节点编辑 Node 对象:

        $ oc label nodes <name> <key>=<value>

        例如,若要为以下节点添加标签:

        $ oc label nodes ci-ln-l8nry52-f76d1-hl7m7-worker-b-tgq49 type=user-node region=east
      2. 使用 oc get 命令验证标签是否已添加到节点:

        $ oc get nodes -l <key>=<value>,<key>=<value>

        例如:

        $ oc get nodes -l type=user-node,region=east

        输出示例

        NAME                                       STATUS   ROLES    AGE   VERSION
        ci-ln-l8nry52-f76d1-hl7m7-worker-b-tgq49   Ready    worker   17m   v1.18.3+002a51f

2.7.3. 创建项目范围节点选择器

您可以组合使用项目中的节点选择器和节点上的标签,将该项目中创建的所有 pod 限制到标记的节点。

当您在这个项目中创建 pod 时,OpenShift Container Platform 会将节点选择器添加到项目中 pod,并将 pod 调度到项目中具有匹配标签的节点。如果存在集群范围默认节点选择器,则以项目节点选择器为准。

您可以通过编辑 Namespace 对象来向项目添加标签,以添加 openshift.io/node-selector 参数,其中包含标签定义。您可以通过编辑节点对象、MachineSet 或 MachineConfig 向节点添加标签。将标签添加到 MachineSet 可确保节点或机器停机时,新节点具有标签。如果节点或机器停机,添加到节点或 MachineConfig 的标签不会保留。

注意

您可以向 pod 添加额外的键/值对。但是,您无法为默认项目键添加其他值。

例如,以下项目具有 region=east 节点选择器:

Namespace 对象示例

apiVersion: v1
kind: Namespace
metadata:
  annotations:
    openshift.io/node-selector: "region=east"
...

以下节点具有 type=user-node,region=east 标签:

节点对象示例

apiVersion: v1
kind: Node
metadata:
  name: ci-ln-qg1il3k-f76d1-hlmhl-worker-b-df2s4
...
  labels:
    region: east
    type: user-node
...

如果您在这个示例项目中创建 pod,则 pod 会被创建并带有项目节点选择器,并被调度到标记的节点:

Pod 对象示例

apiVersion: v1
kind: Pod
metadata:
...
spec:
  nodeSelector:
    region: east
    type: user-node
...

在标记的节点上带有 pod 的 pod 列表示例

NAME     READY   STATUS    RESTARTS   AGE   IP           NODE                                       NOMINATED NODE   READINESS GATES
pod-s1   1/1     Running   0          20s   10.131.2.6   ci-ln-qg1il3k-f76d1-hlmhl-worker-b-df2s4   <none>           <none>

如果 pod 包含不同的节点选择器,则项目中的 pod 不会被创建或调度。例如,如果您将以下 Pod 部署到示例项目中,则不会创建它:

带有无效节点选择器的 Pod 对象示例

apiVersion: v1
kind: Pod
...

spec:
  nodeSelector:
    region: west

....

在创建 pod 时,您会收到类似以下消息的错误:

错误信息示例

Error from server (Forbidden): error when creating "pod.yaml": pods "pod-4" is forbidden: pod node label selector conflicts with its project node label selector

流程

添加默认项目节点选择器:

  1. 创建项目或编辑现有项目以添加 openshift.io/node-selector 参数:

    $ oc edit project <name>
    apiVersion: v1
    kind: Project
    metadata:
      annotations:
        openshift.io/node-selector: "type=user-node,region=east" 1
        openshift.io/sa.scc.mcs: s0:c17,c14
        openshift.io/sa.scc.supplemental-groups: 1000300000/10000
        openshift.io/sa.scc.uid-range: 1000300000/10000
      creationTimestamp: 2019-06-10T14:39:45Z
      labels:
        openshift.io/run-level: "0"
      name: demo
      resourceVersion: "401885"
      selfLink: /api/v1/namespaces/openshift-kube-apiserver
      uid: 96ecc54b-8b8d-11e9-9f54-0a9ae641edd0
    spec:
      finalizers:
      - kubernetes
    status:
      phase: Active
    1
    使用适当的 <key>:<value> 对添加 openshift.io/node-selector
  2. 通过使用 MachineSet 或直接编辑节点,为节点添加标签:

    • 在创建节点时,使用 MachineSet 将标签添加到由 MachineSet 管理的节点上:

      1. 运行以下命令,将节点选择器添加到 MachineSet 中:

        $ oc patch MachineSet <name> --type='json' -p='[{"op":"add","path":"/spec/template/spec/metadata/labels", "value":{"<key>"="<value>","<key>"="<value>"}}]'  -n openshift-machine-api

        例如:

        $ oc patch MachineSet ci-ln-l8nry52-f76d1-hl7m7-worker-c --type='json' -p='[{"op":"add","path":"/spec/template/spec/metadata/labels", "value":{"type":"user-node","region":"east"}}]'  -n openshift-machine-api
      2. 使用 oc edit 命令验证标签是否已添加到 MachineSet:

        例如:

        $ oc edit MachineSet ci-ln-l8nry52-f76d1-hl7m7-worker-c -n openshift-machine-api

        输出示例

        apiVersion: machine.openshift.io/v1beta1
        kind: MachineSet
        metadata:
        ...
        spec:
        ...
          template:
            metadata:
        ...
            spec:
              metadata:
                labels:
                  region: east
                  type: user-node

      3. 重新部署与该 MachineSet 关联的节点:

        例如:

        $ oc scale --replicas=0 MachineSet ci-ln-l8nry52-f76d1-hl7m7-worker-c -n openshift-machine-api
        $ oc scale --replicas=1 MachineSet ci-ln-l8nry52-f76d1-hl7m7-worker-c -n openshift-machine-api
      4. 在节点就绪并可用时,使用 oc get 命令验证该标签是否已添加到节点:

        $ oc label MachineSet abc612-msrtw-worker-us-east-1c type=user-node region=east

        例如:

        $ oc get nodes -l type=user-node

        输出示例

        NAME                                       STATUS   ROLES    AGE   VERSION
        ci-ln-l8nry52-f76d1-hl7m7-worker-c-vmqzp   Ready    worker   61s   v1.18.3+002a51f

    • 直接向节点添加标签:

      1. 编辑 Node 对象以添加标签:

        $ oc label <resource> <name> <key>=<value>

        例如,若要为以下节点添加标签:

        $ oc label nodes ci-ln-l8nry52-f76d1-hl7m7-worker-c-tgq49 type=user-node region=east
      2. 使用 oc get 命令验证标签是否已添加到节点:

        $ oc get nodes -l <key>=<value>

        例如:

        $ oc get nodes -l type=user-node,region=east

        输出示例

        NAME                                       STATUS   ROLES    AGE   VERSION
        ci-ln-l8nry52-f76d1-hl7m7-worker-b-tgq49   Ready    worker   17m   v1.18.3+002a51f