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

节点选择器指定一个键/值对映射,该映射使用 pod 中指定的自定义标签和选择器定义。

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

4.7.1. 关于节点选择器

您可以使用节点上的 pod 和标签上的节点选择器来控制 pod 的调度位置。使用节点选择器时,OpenShift Container Platform 会将 pod 调度到包含匹配标签的节点。

您可以使用节点选择器将特定的 pod 放置到特定的节点上,集群范围节点选择器将新 pod 放置到集群中的任何特定节点上,以及项目节点选择器,将新 pod 放置到特定的节点上。

例如,作为集群管理员,您可以创建一个基础架构,应用程序开发人员可以通过在创建的每个 pod 中包括节点选择器,将 pod 部署到最接近其地理位置的节点。在本例中,集群由五个数据中心组成,分布在两个区域。在美国,将节点标记为 us-eastus-centralus-west。在亚太地区(APAC),将节点标记为 apac-eastapac-west。开发人员可在其创建的 pod 中添加节点选择器,以确保 pod 调度到这些节点上。

如果 Pod 对象包含节点选择器,但没有节点具有匹配的标签,则不会调度 pod。

重要

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

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

您可以使用节点选择器和标签控制特定 pod 调度到哪些节点上。

要使用节点选择器和标签,首先标记节点以避免 pod 被取消调度,然后将节点选择器添加到 pod。

注意

您不能直接将节点选择器添加到现有调度的 pod 中。您必须标记控制 pod 的对象,如部署配置。

例如,以下 Node 对象具有 region: east 标签:

带有标识的 Node 对象示例

kind: Node
apiVersion: v1
metadata:
  name: ip-10-0-131-14.ec2.internal
  selfLink: /api/v1/nodes/ip-10-0-131-14.ec2.internal
  uid: 7bc2580a-8b8e-11e9-8e01-021ab4174c74
  resourceVersion: '478704'
  creationTimestamp: '2019-06-10T14:46:08Z'
  labels:
    kubernetes.io/os: linux
    failure-domain.beta.kubernetes.io/zone: us-east-1a
    node.openshift.io/os_version: '4.5'
    node-role.kubernetes.io/worker: ''
    failure-domain.beta.kubernetes.io/region: us-east-1
    node.openshift.io/os_id: rhcos
    beta.kubernetes.io/instance-type: m4.large
    kubernetes.io/hostname: ip-10-0-131-14
    beta.kubernetes.io/arch: amd64
    region: east 1
    type: user-node
#...

1
与 pod 节点选择器匹配的标签。

pod 具有 type: user-node,region: east 节点选择器:

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

apiVersion: v1
kind: Pod
metadata:
  name: s1
#...
spec:
  nodeSelector: 1
    region: east
    type: user-node
#...

1
与节点标签匹配的节点选择器。节点必须具有每个节点选择器的标签。

使用示例 pod 规格创建 pod 时,它可以调度到示例节点上。

默认集群范围节点选择器

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

例如,以下 Scheduler 对象具有默认的集群范围的 region=easttype=user-node 节点选择器:

Scheduler Operator 自定义资源示例

apiVersion: config.openshift.io/v1
kind: Scheduler
metadata:
  name: cluster
#...
spec:
  defaultNodeSelector: type=user-node,region=east
#...

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

Node 对象示例

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

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

apiVersion: v1
kind: Pod
metadata:
  name: s1
#...
spec:
  nodeSelector:
    region: east
#...

当您使用示例集群中的 pod spec 创建 pod 时,该 pod 会使用集群范围节点选择器创建,并调度到标记的节点:

在标记的节点上带有 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,OpenShift Container Platform 会将节点选择器添加到 pod,并将 pod 调度到具有匹配标签的节点。如果存在集群范围默认节点选择器,则以项目节点选择器为准。

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

Namespace 对象示例

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

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

Node 对象示例

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

当您使用本例项目中的示例 pod 规格创建 pod 时,pod 会使用项目节点选择器创建,并调度到标记的节点:

Pod 对象示例

apiVersion: v1
kind: Pod
metadata:
  namespace: east-region
#...
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
metadata:
  name: west-region
#...
spec:
  nodeSelector:
    region: west
#...

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

您可以使用节点上的 pod 和标签上的节点选择器来控制 pod 的调度位置。使用节点选择器时,OpenShift Container Platform 会将 pod 调度到包含匹配标签的节点。

您可向节点、计算机器集或机器配置添加标签。将标签添加到计算机器集可确保节点或机器停机时,新节点具有该标签。如果节点或机器停机,添加到节点或机器配置的标签不会保留。

要将节点选择器添加到现有 pod 中,将节点选择器添加到该 pod 的控制对象中,如 ReplicaSet 对象、DaemonSet 对象、StatefulSet 对象、Deployment 对象或 DeploymentConfig 对象。任何属于该控制对象的现有 pod 都会在具有匹配标签的节点上重新创建。如果要创建新 pod,可以将节点选择器直接添加到 pod 规格中。如果 pod 没有控制对象,您必须删除 pod,编辑 pod 规格并重新创建 pod。

注意

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

先决条件

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

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

输出示例

kind: Pod
apiVersion: v1
metadata:
#...
Name:               router-default-66d5cf9464-7pwkc
Namespace:          openshift-ingress
# ...
Controlled By:      ReplicaSet/router-default-66d5cf9464
# ...

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

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

流程

  1. 使用计算机器集或直接编辑节点,为节点添加标签:

    • 在创建节点时,使用 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
        提示

        您还可以应用以下 YAML 来向计算机器集中添加标签:

        apiVersion: machine.openshift.io/v1beta1
        kind: MachineSet
        metadata:
          name: xf2bd-infra-us-east-2a
          namespace: openshift-machine-api
        spec:
          template:
            spec:
              metadata:
                labels:
                  region: "east"
                  type: "user-node"
        #...
      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
        提示

        您还可以应用以下 YAML 来向节点添加标签:

        kind: Node
        apiVersion: v1
        metadata:
          name: hello-node-6fbccf8d9
          labels:
            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.25.0

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

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

      带有标签的 ReplicaSet 对象示例

      kind: ReplicaSet
      apiVersion: apps/v1
      metadata:
        name: hello-node-6fbccf8d9
      # ...
      spec:
      # ...
        template:
          metadata:
            creationTimestamp: null
            labels:
              ingresscontroller.operator.openshift.io/deployment-ingresscontroller: default
              pod-template-hash: 66d5cf9464
          spec:
            nodeSelector:
              kubernetes.io/os: linux
              node-role.kubernetes.io/worker: ''
              type: user-node 1
      #...

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

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

      apiVersion: v1
      kind: Pod
      metadata:
        name: hello-node-6fbccf8d9
      #...
      spec:
        nodeSelector:
          region: east
          type: user-node
      #...

      注意

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

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

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

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

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

注意

您可以向 pod 添加额外的键/值对。但是,您无法为一个默认的键添加不同的值。

流程

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

  1. 编辑调度程序 Operator CR 以添加默认的集群范围节点选择器:

    $ oc edit scheduler cluster

    使用节点选择器的调度程序 Operator CR 示例

    apiVersion: config.openshift.io/v1
    kind: Scheduler
    metadata:
      name: cluster
    ...
    spec:
      defaultNodeSelector: type=user-node,region=east 1
      mastersSchedulable: false

    1
    使用适当的 <key>:<value> 对添加节点选择器。

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

  2. 使用计算机器集或直接编辑节点,为节点添加标签:

    • 在创建节点时,使用计算机器集向由计算机器设置管理的节点添加标签:

      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
        提示

        您还可以应用以下 YAML 来向计算机器集中添加标签:

        apiVersion: machine.openshift.io/v1beta1
        kind: MachineSet
        metadata:
          name: <machineset>
          namespace: openshift-machine-api
        spec:
          template:
            spec:
              metadata:
                labels:
                  region: "east"
                  type: "user-node"
      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
          ...

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

        例如:

        $ 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.25.0

    • 直接向节点添加标签:

      1. 为节点编辑 Node 对象:

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

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

        $ oc label nodes ci-ln-l8nry52-f76d1-hl7m7-worker-b-tgq49 type=user-node region=east
        提示

        您还可以应用以下 YAML 来向节点添加标签:

        kind: Node
        apiVersion: v1
        metadata:
          name: <node_name>
          labels:
            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.25.0

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

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

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

您可以通过编辑 Namespace 对象来向项目添加节点选择器,以添加 openshift.io/node-selector 参数。您可向节点、计算机器集或机器配置添加标签。将标签添加到计算机器集可确保节点或机器停机时,新节点具有该标签。如果节点或机器停机,添加到节点或机器配置的标签不会保留。

如果 Pod 对象包含节点选择器,则不会调度 pod,但没有项目具有匹配的节点选择器。从该 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. 创建命名空间或编辑现有命名空间,以添加 openshift.io/node-selector 参数:

    $ oc edit namespace <name>

    输出示例

    apiVersion: v1
    kind: Namespace
    metadata:
      annotations:
        openshift.io/node-selector: "type=user-node,region=east" 1
        openshift.io/description: ""
        openshift.io/display-name: ""
        openshift.io/requester: kube:admin
        openshift.io/sa.scc.mcs: s0:c30,c5
        openshift.io/sa.scc.supplemental-groups: 1000880000/10000
        openshift.io/sa.scc.uid-range: 1000880000/10000
      creationTimestamp: "2021-05-10T12:35:04Z"
      labels:
        kubernetes.io/metadata.name: demo
      name: demo
      resourceVersion: "145537"
      uid: 3f8786e3-1fcb-42e3-a0e3-e2ac54d15001
    spec:
      finalizers:
      - kubernetes

    1
    使用适当的 <key>:<value> 对添加 openshift.io/node-selector
  2. 使用计算机器集或直接编辑节点,为节点添加标签:

    • 在创建节点时,使用 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
        提示

        您还可以应用以下 YAML 来向计算机器集中添加标签:

        apiVersion: machine.openshift.io/v1beta1
        kind: MachineSet
        metadata:
          name: <machineset>
          namespace: openshift-machine-api
        spec:
          template:
            spec:
              metadata:
                labels:
                  region: "east"
                  type: "user-node"
      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. 重新部署与该计算机器集关联的节点:

        例如:

        $ 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,region=east

        输出示例

        NAME                                       STATUS   ROLES    AGE   VERSION
        ci-ln-l8nry52-f76d1-hl7m7-worker-c-vmqzp   Ready    worker   61s   v1.25.0

    • 直接向节点添加标签:

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

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

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

        $ oc label nodes ci-ln-l8nry52-f76d1-hl7m7-worker-c-tgq49 type=user-node region=east
        提示

        您还可以应用以下 YAML 来向节点添加标签:

        kind: Node
        apiVersion: v1
        metadata:
          name: <node_name>
          labels:
            type: "user-node"
            region: "east"
      2. 使用 oc get 命令验证标签是否已添加到 Node 对象中:

        $ 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.25.0