4.4. 使用节点关联性规则控制节点上的 pod 放置

关联性是 pod 的一个属性,用于控制它们希望调度到的节点。

在 OpenShift Container Platform 中,节点关联性是由调度程序用来确定 pod 的可放置位置的一组规则。规则是使用节点中的自定义标签和 pod 中指定的选择器进行定义的。

4.4.1. 了解节点关联性

节点关联性允许 pod 指定与可以放置该 pod 的一组节点的关联性。节点对放置没有控制权。

例如,您可以将 pod 配置为仅在具有特定 CPU 或位于特定可用区的节点上运行。

节点关联性规则有两种,即必要规则和偏好规则。

必须满足必要规则,pod 才能调度到节点上。偏好规则指定在满足规则时调度程序会尝试强制执行规则,但不保证一定能强制执行成功。

注意

如果节点标签在运行时改变,使得不再满足 pod 上的节点关联性规则,该 pod 将继续在这个节点上运行。

您可以通过 Pod 规格文件配置节点关联性。您可以指定必要规则或偏好规则,或同时指定这两种规则。如果您同时指定,节点必须首先满足必要规则,然后尝试满足偏好规则。

下例中的 Pod spec 包含一条规则,要求 pod 放置到具有键为 e2e-az-NorthSouth 且值为 e2e-az-Northe2e-az-South 的标签的节点上:

具有节点关联性必要规则的 pod 配置文件示例

apiVersion: v1
kind: Pod
metadata:
  name: with-node-affinity
spec:
  affinity:
    nodeAffinity: 1
      requiredDuringSchedulingIgnoredDuringExecution: 2
        nodeSelectorTerms:
        - matchExpressions:
          - key: e2e-az-NorthSouth 3
            operator: In 4
            values:
            - e2e-az-North 5
            - e2e-az-South 6
  containers:
  - name: with-node-affinity
    image: docker.io/ocpqe/hello-pod
#...

1
用于配置节点关联性的小节。
2
定义必要规则。
3 5 6
必须匹配键/值对(标签)才会应用该规则。
4
运算符表示节点上的标签和 Pod 规格中 matchExpression 参数的值集合之间的关系。这个值可以是 InNotInExistsDoesNotExistLtGt

下例中的节点规格包含一条偏好规则,其规定优先为 pod 选择具有键为 e2e-az-EastWest 且值为 e2e-az-Easte2e-az-West 的节点:

具有节点关联性偏好规则的 pod 配置文件示例

apiVersion: v1
kind: Pod
metadata:
  name: with-node-affinity
spec:
  affinity:
    nodeAffinity: 1
      preferredDuringSchedulingIgnoredDuringExecution: 2
      - weight: 1 3
        preference:
          matchExpressions:
          - key: e2e-az-EastWest 4
            operator: In 5
            values:
            - e2e-az-East 6
            - e2e-az-West 7
  containers:
  - name: with-node-affinity
    image: docker.io/ocpqe/hello-pod
#...

1
用于配置节点关联性的小节。
2
定义偏好规则。
3
为偏好规则指定权重。优先选择权重最高的节点。
4 6 7
必须匹配键/值对(标签)才会应用该规则。
5
运算符表示节点上的标签和 Pod 规格中 matchExpression 参数的值集合之间的关系。这个值可以是 InNotInExistsDoesNotExistLtGt

没有明确的节点反关联性概念,但使用 NotInDoesNotExist 运算符就能实现这种行为。

注意

如果您在同一 pod 配置中同时使用节点关联性和节点选择器,请注意以下几点:

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

4.4.2. 配置节点关联性必要规则

必须满足必要规则,pod 才能调度到节点上。

流程

以下步骤演示了一个简单的配置,此配置会创建一个节点,以及调度程序要放置到该节点上的 pod。

  1. 使用 oc label node 命令给节点添加标签:

    $ oc label node node1 e2e-az-name=e2e-az1
    提示

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

    kind: Node
    apiVersion: v1
    metadata:
      name: <node_name>
      labels:
        e2e-az-name: e2e-az1
    #...
  2. 创建 pod 规格中具有特定标签的 pod:

    1. 使用以下内容创建 YAML 文件:

      注意

      您不能直接将关联性添加到调度的 pod 中。

      输出示例

      apiVersion: v1
      kind: Pod
      metadata:
        name: s1
      spec:
        affinity: 1
          nodeAffinity:
            requiredDuringSchedulingIgnoredDuringExecution: 2
              nodeSelectorTerms:
              - matchExpressions:
                - key: e2e-az-name 3
                  values:
                  - e2e-az1
                  - e2e-az2
                  operator: In 4
      #...

      1
      添加 pod 关联性。
      2
      配置 requiredDuringSchedulingIgnoredDuringExecution 参数。
      3
      指定必须满足的 keyvalues。如果希望新 pod 调度到您编辑的节点上,请使用与节点中标签相同的 keyvalues 参数:
      4
      指定一个 operator。运算符可以是 InNotInExistsDoesNotExist。例如,使用运算符 In 来要求节点上存在该标签。
    2. 创建 pod:

      $ oc create -f <file-name>.yaml

4.4.3. 配置首选的节点关联性规则

偏好规则指定在满足规则时调度程序会尝试强制执行规则,但不保证一定能强制执行成功。

流程

以下步骤演示了一个简单的配置,此配置会创建一个节点,以及调度程序尝试放置到该节点上的 pod。

  1. 使用 oc label node 命令给节点添加标签:

    $ oc label node node1 e2e-az-name=e2e-az3
  2. 创建具有特定标签的 pod:

    1. 使用以下内容创建 YAML 文件:

      注意

      您不能直接将关联性添加到调度的 pod 中。

      apiVersion: v1
      kind: Pod
      metadata:
        name: s1
      spec:
        affinity: 1
          nodeAffinity:
            preferredDuringSchedulingIgnoredDuringExecution: 2
            - weight: 3
              preference:
                matchExpressions:
                - key: e2e-az-name 4
                  values:
                  - e2e-az3
                  operator: In 5
      #...
      1
      添加 pod 关联性。
      2
      配置 preferredDuringSchedulingIgnoredDuringExecution 参数。
      3
      为节点指定一个数字为 1-100 的权重。优先选择权重最高的节点。
      4
      指定必须满足的 keyvalues。如果希望新 pod 调度到您编辑的节点上,请使用与节点中标签相同的 keyvalues 参数:
      5
      指定一个 operator。运算符可以是 InNotInExistsDoesNotExist。例如,使用运算符 In 来要求节点上存在该标签。
    2. 创建 pod。

      $ oc create -f <file-name>.yaml

4.4.4. 节点关联性规则示例

以下示例演示了节点关联性。

4.4.4.1. 具有匹配标签的节点关联性

以下示例演示了具有匹配标签的节点与 pod 的节点关联性:

  • Node1 节点具有标签 zone:us

    $ oc label node node1 zone=us
    提示

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

    kind: Node
    apiVersion: v1
    metadata:
      name: <node_name>
      labels:
        zone: us
    #...
  • pod-s1 pod 在节点关联性必要规则下具有 zoneus 键/值对:

    $ cat pod-s1.yaml

    输出示例

    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-s1
    spec:
      containers:
        - image: "docker.io/ocpqe/hello-pod"
          name: hello-pod
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
              - matchExpressions:
                - key: "zone"
                  operator: In
                  values:
                  - us
    #...

  • pod-s1 pod 可以调度到 Node1 上:

    $ oc get pod -o wide

    输出示例

    NAME     READY     STATUS       RESTARTS   AGE      IP      NODE
    pod-s1   1/1       Running      0          4m       IP1     node1

4.4.4.2. 没有匹配标签的节点关联性

以下示例演示了无匹配标签的节点与 pod 的节点关联性:

  • Node1 节点具有标签 zone:emea:

    $ oc label node node1 zone=emea
    提示

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

    kind: Node
    apiVersion: v1
    metadata:
      name: <node_name>
      labels:
        zone: emea
    #...
  • pod-s1 pod 在节点关联性必要规则下具有 zoneus 键/值对:

    $ cat pod-s1.yaml

    输出示例

    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-s1
    spec:
      containers:
        - image: "docker.io/ocpqe/hello-pod"
          name: hello-pod
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
              - matchExpressions:
                - key: "zone"
                  operator: In
                  values:
                  - us
    #...

  • pod-s1 pod 无法调度到 Node1 上:

    $ oc describe pod pod-s1

    输出示例

    ...
    
    Events:
     FirstSeen LastSeen Count From              SubObjectPath  Type                Reason
     --------- -------- ----- ----              -------------  --------            ------
     1m        33s      8     default-scheduler Warning        FailedScheduling    No nodes are available that match all of the following predicates:: MatchNodeSelector (1).

4.4.5. 使用节点关联性来控制安装 Operator 的位置

默认情况下,当安装 Operator 时,OpenShift Container Platform 会随机将 Operator pod 安装到其中一个 worker 节点。然而,在某些情况下,您可能希望该 pod 调度到特定节点或一组节点上。

以下示例描述了您可能希望将 Operator pod 调度到特定节点或一组节点的情况:

  • 如果 Operator 需要特定的平台,如 amd64arm64
  • 如果 Operator 需要特定的操作系统,如 Linux 或 Windows
  • 如果您希望 Operator 在同一个主机上或位于同一机架的主机上工作
  • 如果您希望 Operator 在整个基础架构中分散,以避免因为网络或硬件问题而停机

您可以通过在 Operator 的 Subscription 对象中添加节点关联性约束来控制 Operator pod 的安装位置。

以下示例演示了如何使用节点关联性将自定义 Metrics Autoscaler Operator 实例安装到集群中的特定节点:

将 Operator pod 放置到特定节点的节点关联性示例

apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
metadata:
  name: openshift-custom-metrics-autoscaler-operator
  namespace: openshift-keda
spec:
  name: my-package
  source: my-operators
  sourceNamespace: operator-registries
  config:
    affinity:
      nodeAffinity: 1
        requiredDuringSchedulingIgnoredDuringExecution:
          nodeSelectorTerms:
          - matchExpressions:
            - key: kubernetes.io/hostname
              operator: In
              values:
              - ip-10-0-163-94.us-west-2.compute.internal
#...

1
要求 Operator 的 pod 调度到名为 ip-10-0-163-94.us-west-2.compute.internal 的节点关联性。

将 Operator pod 放置到带有特定平台的节点关联性示例

apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
metadata:
  name: openshift-custom-metrics-autoscaler-operator
  namespace: openshift-keda
spec:
  name: my-package
  source: my-operators
  sourceNamespace: operator-registries
  config:
    affinity:
      nodeAffinity: 1
        requiredDuringSchedulingIgnoredDuringExecution:
          nodeSelectorTerms:
          - matchExpressions:
            - key: kubernetes.io/arch
              operator: In
              values:
              - arm64
            - key: kubernetes.io/os
              operator: In
              values:
              - linux
#...

1
要求 Operator 的 pod 调度到具有 kubernetes.io/arch=arm64kubernetes.io/os=linux 标签的节点上。

流程

要控制 Operator pod 的放置,请完成以下步骤:

  1. 照常安装 Operator。
  2. 如果需要,请确保您的节点已标记为正确响应关联性。
  3. 编辑 Operator Subscription 对象以添加关联性:

    apiVersion: operators.coreos.com/v1alpha1
    kind: Subscription
    metadata:
      name: openshift-custom-metrics-autoscaler-operator
      namespace: openshift-keda
    spec:
      name: my-package
      source: my-operators
      sourceNamespace: operator-registries
      config:
        affinity: 1
          nodeAffinity:
            requiredDuringSchedulingIgnoredDuringExecution:
              nodeSelectorTerms:
              - matchExpressions:
                - key: kubernetes.io/hostname
                  operator: In
                  values:
                  - ip-10-0-185-229.ec2.internal
    #...
    1
    添加 nodeAffinity

验证

  • 要确保 pod 部署到特定的节点上,请运行以下命令:

    $ oc get pods -o wide

    输出示例

    NAME                                                  READY   STATUS    RESTARTS   AGE   IP            NODE                           NOMINATED NODE   READINESS GATES
    custom-metrics-autoscaler-operator-5dcc45d656-bhshg   1/1     Running   0          50s   10.131.0.20   ip-10-0-185-229.ec2.internal   <none>           <none>

4.4.6. 其他资源