×

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

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

了解节点亲和性

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

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

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

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

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

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

以下示例是一个Pod规范,其中包含一条规则,该规则要求将 Pod 放置在具有标签的节点上,该标签的键为e2e-az-NorthSouth,其值为e2e-az-Northe2e-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

以下示例是一个节点规范,其中包含一条首选规则,即首选具有标签的节点(该标签的键为e2e-az-EastWest,其值为e2e-az-Easte2e-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参数中的值集之间的关系。此值可以是InNotInExistsDoesNotExistLtGt

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

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

  • 如果您同时配置nodeSelectornodeAffinity,则必须同时满足这两个条件才能将 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).