×

亲和性是 Pod 的一个属性,它控制 Pod 优先调度的节点。

在 OpenShift Container Platform 中,节点亲和性是一组由调度程序用来确定 Pod 可以放置位置的规则。这些规则是使用节点上的自定义标签和 Pod 中指定的标签选择器定义的。

理解节点亲和性

节点亲和性允许 Pod 指定对其可以放置在其上的节点组的亲和性。节点无法控制放置。

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

节点亲和性规则有两种类型:**必需**和**首选**。

在 Pod 可以调度到节点上之前,**必须**满足必需规则。首选规则指定,如果满足该规则,调度程序将尝试强制执行这些规则,但不保证强制执行。

如果节点上的标签在运行时发生更改,导致 Pod 上的节点亲和性规则不再满足,则 Pod 将继续在该节点上运行。

您可以通过 `Pod`规范文件配置节点亲和性。您可以指定必需规则、首选规则或两者兼有。如果您同时指定两者,则节点必须首先满足必需规则,然后尝试满足首选规则。

以下示例是一个 `Pod` 规范,其中包含一个规则,该规则要求将 Pod 放置在具有标签的节点上,该标签的键为 `e2e-az-NorthSouth`,其值为 `e2e-az-North` 或 `e2e-az-South`。

具有节点亲和性必需规则的示例 Pod 配置文件
apiVersion: v1
kind: Pod
metadata:
  name: with-node-affinity
spec:
  securityContext:
    runAsNonRoot: true
    seccompProfile:
      type: RuntimeDefault
  affinity:
    nodeAffinity: (1)
      requiredDuringSchedulingIgnoredDuringExecution: (2)
        nodeSelectorTerms:
        - matchExpressions:
          - key: e2e-az-NorthSouth (3)
            operator: In (4)
            values:
            - e2e-az-North (3)
            - e2e-az-South (3)
  containers:
  - name: with-node-affinity
    image: docker.io/ocpqe/hello-pod
    securityContext:
      allowPrivilegeEscalation: false
      capabilities:
        drop: [ALL]
# ...
1 配置节点亲和性的节。
2 定义必需规则。
3 必须匹配的键/值对(标签)才能应用规则。
4 操作符表示节点上的标签与Pod规范中matchExpression参数中的值集之间的关系。此值可以是InNotInExistsDoesNotExistLtGt

以下示例是一个节点规范,它具有一个首选规则:优先为 Pod 选择键为e2e-az-EastWest且值为e2e-az-Easte2e-az-West的节点。

包含节点亲和性首选规则的示例 Pod 配置文件
apiVersion: v1
kind: Pod
metadata:
  name: with-node-affinity
spec:
  securityContext:
    runAsNonRoot: true
    seccompProfile:
      type: RuntimeDefault
  affinity:
    nodeAffinity: (1)
      preferredDuringSchedulingIgnoredDuringExecution: (2)
      - weight: 1 (3)
        preference:
          matchExpressions:
          - key: e2e-az-EastWest (4)
            operator: In (5)
            values:
            - e2e-az-East (4)
            - e2e-az-West (4)
  containers:
  - name: with-node-affinity
    image: docker.io/ocpqe/hello-pod
    securityContext:
      allowPrivilegeEscalation: false
      capabilities:
        drop: [ALL]
# ...
1 配置节点亲和性的节。
2 定义首选规则。
3 指定首选规则的权重。权重最高的节点优先。
4 必须匹配的键/值对(标签)才能应用规则。
5 操作符表示节点上的标签与Pod规范中matchExpression参数中的值集之间的关系。此值可以是InNotInExistsDoesNotExistLtGt

没有明确的节点反亲和性概念,但使用NotInDoesNotExist操作符可以复制该行为。

如果您在同一个 Pod 配置中同时使用节点亲和性和节点选择器,请注意以下事项

  • 如果您同时配置nodeSelectornodeAffinity,则必须同时满足这两个条件,Pod 才能调度到候选节点上。

  • 如果您指定了与nodeAffinity类型关联的多个nodeSelectorTerms,那么如果满足其中一个nodeSelectorTerms,则 Pod 可以调度到节点上。

  • 如果您指定了与nodeSelectorTerms关联的多个matchExpressions,则只有在满足所有matchExpressions的情况下,Pod 才能调度到节点上。

配置必需的节点亲和性规则

在 Pod 可以调度到节点上之前,必须满足必需规则。

步骤

以下步骤演示了一个简单的配置,该配置创建了一个节点和一个 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

配置首选的节点亲和性规则

首选规则指定,如果满足规则,调度程序将尝试强制执行规则,但不保证强制执行。

步骤

以下步骤演示了一个简单的配置,该配置创建了一个节点和一个 Pod,调度程序将尝试将该 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

节点亲和性规则示例

以下示例演示了节点亲和性。

具有匹配标签的节点亲和性

以下示例演示了具有匹配标签的节点和 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:
      securityContext:
        runAsNonRoot: true
        seccompProfile:
          type: RuntimeDefault
      containers:
        - image: "docker.io/ocpqe/hello-pod"
          name: hello-pod
          securityContext:
            allowPrivilegeEscalation: false
            capabilities:
              drop: [ALL]
      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

没有匹配标签的节点亲和性

以下示例演示了节点和 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:
      securityContext:
        runAsNonRoot: true
        seccompProfile:
          type: RuntimeDefault
      containers:
        - image: "docker.io/ocpqe/hello-pod"
          name: hello-pod
          securityContext:
            allowPrivilegeEscalation: false
            capabilities:
              drop: [ALL]
      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).

使用节点亲和性控制 Operator 的安装位置

默认情况下,安装 Operator 时,OpenShift Container Platform 会将 Operator Pod 随机安装到您的某个工作节点上。但是,在某些情况下,您可能希望将该 Pod 调度到特定节点或节点集上。

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

  • 如果 Operator 需要特定平台,例如amd64arm64

  • 如果 Operator 需要特定操作系统,例如 Linux 或 Windows

  • 如果您希望一起工作的 Operator 调度到同一主机上或位于同一机架上的主机上

  • 如果您希望 Operator 分散在整个基础设施中,以避免因网络或硬件问题导致的停机

您可以通过向 Operator 的Subscription对象添加节点亲和性约束来控制 Operator Pod 的安装位置。

以下示例演示了如何使用节点亲和性将 Custom 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>