×

亲和性是 Pod 的一个属性,它控制 Pod 优选在其上调度的节点。

在 OpenShift Dedicated 中,节点亲和性是一组规则,调度器使用这些规则来确定 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` 参数中的值集之间的关系。此值可以是 `In`、`NotIn`、`Exists` 或 `DoesNotExist`、`Lt` 或 `Gt`。

以下示例是一个节点规范,其中包含一个首选规则,该规则表示具有键为 `e2e-az-EastWest` 且值为 `e2e-az-East` 或 `e2e-az-West` 的标签的节点对于 Pod 是首选的

带有节点亲和性首选规则的示例 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` 参数中的值集之间的关系。此值可以是 `In`、`NotIn`、`Exists` 或 `DoesNotExist`、`Lt` 或 `Gt`。

没有明确的 *节点反亲和性* 概念,但使用 `NotIn` 或 `DoesNotExist` 运算符可以复制该行为。

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

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

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

  • 如果指定与nodeSelectorTerms关联的多个matchExpressions,则只有在满足所有matchExpressions时,才能将pod调度到节点上。

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

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

步骤

以下步骤演示了一个简单的配置,该配置创建一个节点和一个pod,调度程序必须将其放置在该节点上。

  1. 在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,调度程序将尝试将其放置在该节点上。

  1. 创建一个具有特定标签的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).