×

亲和性是 Pod 的一个属性,它控制 Pod 首选调度的节点。反亲和性是 Pod 的一个属性,它阻止 Pod 在某个节点上调度。

在 OpenShift Container Platform 中,Pod 亲和性Pod 反亲和性允许您根据其他 Pod 上的键值标签来限制 Pod 能够调度的节点。

了解 Pod 亲和性

Pod 亲和性Pod 反亲和性允许您根据其他 Pod 上的键/值标签来限制 Pod 能够调度的节点。

  • Pod 亲和性可以告诉调度程序,如果新 Pod 上的标签选择器与当前 Pod 上的标签匹配,则在新 Pod 上找到与其他 Pod 相同节点。

  • Pod 反亲和性可以防止调度程序在新 Pod 上找到与具有相同标签的 Pod 相同节点,如果新 Pod 上的标签选择器与当前 Pod 上的标签匹配。

例如,使用亲和性规则,您可以分散或打包服务内的 Pod 或相对于其他服务中的 Pod。反亲和性规则允许您防止特定服务的 Pod 在与已知会干扰第一个服务的 Pod 性能的其他服务的 Pod 相同节点上进行调度。或者,您可以将服务的 Pod 分散到节点、可用区或可用性集中,以减少相关的故障。

标签选择器可能与多个 Pod 部署匹配。配置反亲和性规则时,请使用唯一的标签组合以避免匹配 Pod。

有两种类型的 Pod 亲和性规则:必需首选

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

根据您的 Pod 优先级和抢占设置,调度器可能无法找到合适的节点来部署 Pod 而不会违反亲和性要求。如果是这样,Pod 可能无法调度。

为了防止这种情况,请仔细配置具有相同优先级的 Pod 的 Pod 亲和性。

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

以下示例显示配置了 Pod 亲和性和反亲和性的Pod规范。

在此示例中,Pod 亲和性规则指示只有当节点上至少有一个已运行的 Pod 具有键为security且值为S1的标签时,Pod 才能调度到该节点。Pod 反亲和性规则表示如果节点上已运行具有键为security且值为S2的标签的 Pod,则 Pod 优先不调度到该节点。

包含 Pod 亲和性的示例Pod配置文件
apiVersion: v1
kind: Pod
metadata:
  name: with-pod-affinity
spec:
  securityContext:
    runAsNonRoot: true
    seccompProfile:
      type: RuntimeDefault
  affinity:
    podAffinity: (1)
      requiredDuringSchedulingIgnoredDuringExecution: (2)
      - labelSelector:
          matchExpressions:
          - key: security (3)
            operator: In (4)
            values:
            - S1 (3)
        topologyKey: topology.kubernetes.io/zone
  containers:
  - name: with-pod-affinity
    image: docker.io/ocpqe/hello-pod
    securityContext:
      allowPrivilegeEscalation: false
      capabilities:
        drop: [ALL]
1 配置 Pod 亲和性的段落。
2 定义必需规则。
3 必须匹配的键和值(标签)才能应用规则。
4 运算符表示现有 Pod 上的标签与新 Pod 规范中matchExpression参数中的一组值之间的关系。可以是InNotInExistsDoesNotExist
包含 Pod 反亲和性的示例Pod配置文件
apiVersion: v1
kind: Pod
metadata:
  name: with-pod-antiaffinity
spec:
  securityContext:
    runAsNonRoot: true
    seccompProfile:
      type: RuntimeDefault
  affinity:
    podAntiAffinity: (1)
      preferredDuringSchedulingIgnoredDuringExecution: (2)
      - weight: 100  (3)
        podAffinityTerm:
          labelSelector:
            matchExpressions:
            - key: security (4)
              operator: In (5)
              values:
              - S2
          topologyKey: kubernetes.io/hostname
  containers:
  - name: with-pod-affinity
    image: docker.io/ocpqe/hello-pod
    securityContext:
      allowPrivilegeEscalation: false
      capabilities:
        drop: [ALL]
1 配置 Pod 反亲和性的段落。
2 定义首选规则。
3 为首选规则指定权重。优先选择权重最高的节点。
4 确定反亲和性规则何时适用的 Pod 标签的描述。为标签指定键和值。
5 运算符表示现有 Pod 上的标签与新 Pod 规范中matchExpression参数中的一组值之间的关系。可以是InNotInExistsDoesNotExist

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

配置 Pod 亲和性规则

以下步骤演示了一个简单的两个 Pod 配置,该配置创建具有标签的 Pod 和一个使用亲和性来允许与该 Pod 调度的 Pod。

您不能直接向已调度的 Pod 添加亲和性。

步骤
  1. 在 Pod 规范中创建具有特定标签的 Pod

    1. 创建具有以下内容的 YAML 文件

      apiVersion: v1
      kind: Pod
      metadata:
        name: security-s1
        labels:
          security: S1
      spec:
        securityContext:
          runAsNonRoot: true
          seccompProfile:
            type: RuntimeDefault
        containers:
        - name: security-s1
          image: docker.io/ocpqe/hello-pod
          securityContext:
            runAsNonRoot: true
            seccompProfile:
              type: RuntimeDefault
    2. 创建 Pod。

      $ oc create -f <pod-spec>.yaml
  2. 创建其他 Pod 时,请配置以下参数以添加亲和性

    1. 创建具有以下内容的 YAML 文件

      apiVersion: v1
      kind: Pod
      metadata:
        name: security-s1-east
      # ...
      spec:
        affinity: (1)
          podAffinity:
            requiredDuringSchedulingIgnoredDuringExecution: (2)
            - labelSelector:
                matchExpressions:
                - key: security (3)
                  values:
                  - S1
                  operator: In (4)
              topologyKey: topology.kubernetes.io/zone (5)
      # ...
      1 添加 Pod 亲和性。
      2 配置requiredDuringSchedulingIgnoredDuringExecution参数或preferredDuringSchedulingIgnoredDuringExecution参数。
      3 指定必须满足的keyvalues。如果您希望将新 Pod 与另一个 Pod 一起调度,请使用与第一个 Pod 上的标签相同的keyvalues参数。
      4 指定一个operator。运算符可以是InNotInExistsDoesNotExist。例如,使用运算符In要求标签在节点中。
      5 指定一个topologyKey,这是一个预先填充的Kubernetes 标签,系统使用它来表示拓扑域。
    2. 创建 Pod。

      $ oc create -f <pod-spec>.yaml

配置 Pod 反亲和性规则

以下步骤演示了一个简单的两个 Pod 配置,该配置创建具有标签的 Pod 和一个使用反亲和性首选规则来尝试阻止与该 Pod 调度的 Pod。

您不能直接向已调度的 Pod 添加亲和性。

步骤
  1. 在 Pod 规范中创建具有特定标签的 Pod

    1. 创建具有以下内容的 YAML 文件

      apiVersion: v1
      kind: Pod
      metadata:
        name: security-s1
        labels:
          security: S1
      spec:
        securityContext:
          runAsNonRoot: true
          seccompProfile:
            type: RuntimeDefault
        containers:
        - name: security-s1
          image: docker.io/ocpqe/hello-pod
          securityContext:
            allowPrivilegeEscalation: false
            capabilities:
              drop: [ALL]
    2. 创建 Pod。

      $ oc create -f <pod-spec>.yaml
  2. 创建其他 Pod 时,请配置以下参数

    1. 创建具有以下内容的 YAML 文件

      apiVersion: v1
      kind: Pod
      metadata:
        name: security-s2-east
      # ...
      spec:
      # ...
        affinity: (1)
          podAntiAffinity:
            preferredDuringSchedulingIgnoredDuringExecution: (2)
            - weight: 100 (3)
              podAffinityTerm:
                labelSelector:
                  matchExpressions:
                  - key: security (4)
                    values:
                    - S1
                    operator: In (5)
                topologyKey: kubernetes.io/hostname (6)
      # ...
      1 添加 Pod 反亲和性。
      2 配置requiredDuringSchedulingIgnoredDuringExecution参数或preferredDuringSchedulingIgnoredDuringExecution参数。
      3 对于首选规则,指定节点的权重,1-100。优先选择权重最高的节点。
      4 指定必须满足的keyvalues。如果您希望新 Pod 不与另一个 Pod 一起调度,请使用与第一个 Pod 上的标签相同的keyvalues参数。
      5 指定一个operator。运算符可以是InNotInExistsDoesNotExist。例如,使用运算符In要求标签在节点中。
      6 指定一个topologyKey,这是一个预先填充的Kubernetes 标签,系统使用它来表示拓扑域。
    2. 创建 Pod。

      $ oc create -f <pod-spec>.yaml

Pod 亲和性和反亲和性规则示例

以下示例演示了 Pod 亲和性和 Pod 反亲和性。

Pod 亲和性

以下示例演示了具有匹配标签和标签选择器的 Pod 的 Pod 亲和性。

  • Pod team4 具有标签team:4

    apiVersion: v1
    kind: Pod
    metadata:
      name: team4
      labels:
         team: "4"
    # ...
    spec:
      securityContext:
        runAsNonRoot: true
        seccompProfile:
          type: RuntimeDefault
      containers:
      - name: ocp
        image: docker.io/ocpqe/hello-pod
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            drop: [ALL]
    # ...
  • Pod team4apodAffinity下具有标签选择器team:4

    apiVersion: v1
    kind: Pod
    metadata:
      name: team4a
    # ...
    spec:
      securityContext:
        runAsNonRoot: true
        seccompProfile:
          type: RuntimeDefault
      affinity:
        podAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: team
                operator: In
                values:
                - "4"
            topologyKey: kubernetes.io/hostname
      containers:
      - name: pod-affinity
        image: docker.io/ocpqe/hello-pod
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            drop: [ALL]
    # ...
  • team4a Pod 与 team4 Pod 调度到同一节点。

Pod 反亲和性

以下示例演示了具有匹配标签和标签选择器的 Pod 的 Pod 反亲和性。

  • Pod pod-s1 具有标签security:s1

    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-s1
      labels:
        security: s1
    # ...
    spec:
      securityContext:
        runAsNonRoot: true
        seccompProfile:
          type: RuntimeDefault
      containers:
      - name: ocp
        image: docker.io/ocpqe/hello-pod
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            drop: [ALL]
    # ...
  • Pod pod-s2podAntiAffinity下具有标签选择器security:s1

    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-s2
    # ...
    spec:
      securityContext:
        runAsNonRoot: true
        seccompProfile:
          type: RuntimeDefault
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: security
                operator: In
                values:
                - s1
            topologyKey: kubernetes.io/hostname
      containers:
      - name: pod-antiaffinity
        image: docker.io/ocpqe/hello-pod
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            drop: [ALL]
    # ...
  • pod-s2 Pod 不能与pod-s1调度到同一节点。

没有匹配标签的 Pod 亲和性

以下示例演示了没有匹配标签和标签选择器的 Pod 的 Pod 亲和性。

  • Pod pod-s1 具有标签security:s1

    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-s1
      labels:
        security: s1
    # ...
    spec:
      securityContext:
        runAsNonRoot: true
        seccompProfile:
          type: RuntimeDefault
      containers:
      - name: ocp
        image: docker.io/ocpqe/hello-pod
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            drop: [ALL]
    # ...
  • Pod pod-s2 具有标签选择器security:s2

    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-s2
    # ...
    spec:
      securityContext:
        runAsNonRoot: true
        seccompProfile:
          type: RuntimeDefault
      affinity:
        podAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: security
                operator: In
                values:
                - s2
            topologyKey: kubernetes.io/hostname
      containers:
      - name: pod-affinity
        image: docker.io/ocpqe/hello-pod
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            drop: [ALL]
    # ...
  • 除非存在具有security:s2标签的 Pod 的节点,否则不会调度pod-s2 Pod。如果没有其他具有该标签的 Pod,则新 Pod 将保持挂起状态。

    示例输出
    NAME      READY     STATUS    RESTARTS   AGE       IP        NODE
    pod-s2    0/1       Pending   0          32s       <none>

使用 Pod 亲和性和反亲和性来控制 Operator 的安装位置

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

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

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

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

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

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

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

以下示例显示如何使用 Pod 反亲和性来阻止在具有特定标签的 Pod 的任何节点上安装自定义指标自动缩放 Operator

将 Operator Pod 放置在一个或多个特定节点上的 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:
      podAffinity: (1)
        requiredDuringSchedulingIgnoredDuringExecution:
        - labelSelector:
            matchExpressions:
            - key: app
              operator: In
              values:
              - test
          topologyKey: kubernetes.io/hostname
#...
1 将 Operator 的 Pod 放置在具有app=test标签的 Pod 的节点上的 Pod 亲和性。
阻止 Operator Pod 从一个或多个特定节点上的 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:
      podAntiAffinity: (1)
        requiredDuringSchedulingIgnoredDuringExecution:
        - labelSelector:
            matchExpressions:
            - key: cpu
              operator: In
              values:
              - high
          topologyKey: kubernetes.io/hostname
#...
1 阻止 Operator 的 Pod 调度到具有cpu=high标签的 Pod 的节点上的 Pod 反亲和性。
步骤

要控制 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:
          podAntiAffinity: (1)
            requiredDuringSchedulingIgnoredDuringExecution:
              podAffinityTerm:
                labelSelector:
                  matchExpressions:
                  - key: kubernetes.io/hostname
                    operator: In
                    values:
                    - ip-10-0-185-229.ec2.internal
                topologyKey: topology.kubernetes.io/zone
    #...
    1 添加podAffinitypodAntiAffinity
验证
  • 要确保 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>