4、配置Pod亲和性:使用nodeAffinity与podAntiAffinity将服务实例调度到特定节点

在云原生环境中,Pod的调度策略直接影响服务的高可用性与故障隔离能力。本章将聚焦于Kubernetes调度器的核心机制——节点亲和性(nodeAffinity)与Pod反亲和性(podAntiAffinity),通过配置将服务实例精确调度到特定节点,为后续的Istio故障注入测试奠定基础设施层面的容错基础。

4.1 调度亲和性策略概述

亲和性策略分为两类:节点亲和性决定Pod可以调度到哪些节点;Pod间亲和/反亲和性决定Pod与其他Pod的相对位置。在故障注入场景中,我们主要利用nodeAffinity将服务绑定到特定可用区节点,利用podAntiAffinity确保同一服务的多个副本分散在不同节点上,避免单点故障。

策略类型 作用对象 典型场景 调度约束强度
nodeAffinity 节点标签 将服务调度到GPU节点、特定可用区 required(硬) / preferred(软)
podAntiAffinity Pod标签 同一服务的多个副本分布在不同节点 required(硬) / preferred(软)
podAffinity Pod标签 将缓存服务与计算服务调度到同一节点 required(硬) / preferred(软)
最佳实践:在故障注入测试中,建议对关键服务使用 requiredDuringSchedulingIgnoredDuringExecution 硬约束,确保调度器严格遵循亲和性规则;对于非关键服务,可使用 preferredDuringSchedulingIgnoredDuringExecution 软约束,提高调度灵活性。

4.2 节点亲和性(nodeAffinity)配置

节点亲和性通过匹配节点的标签(Label)来控制Pod的调度目标。以下示例将服务实例强制调度到具有 topology.kubernetes.io/zone: us-east-1a 标签的节点上。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: productpage-v1
  namespace: bookinfo
spec:
  replicas: 3
  selector:
    matchLabels:
      app: productpage
      version: v1
  template:
    metadata:
      labels:
        app: productpage
        version: v1
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: topology.kubernetes.io/zone
                operator: In
                values:
                - us-east-1a
      containers:
      - name: productpage
        image: docker.io/istio/examples-bookinfo-productpage-v1:1.18.0
        ports:
        - containerPort: 9080
关键参数说明:
  • requiredDuringSchedulingIgnoredDuringExecution:调度时必须满足,运行期间忽略节点标签变化。
  • operator: In:节点标签值必须在给定的列表中。
  • 支持的操作符:In、NotIn、Exists、DoesNotExist、Gt、Lt。

4.3 Pod反亲和性(podAntiAffinity)配置

Pod反亲和性确保同一服务的多个副本不会调度到同一个节点上,从而避免节点故障导致整个服务不可用。以下配置强制要求每个 productpage Pod 必须运行在不同的节点上。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: productpage-v1
  namespace: bookinfo
spec:
  replicas: 3
  selector:
    matchLabels:
      app: productpage
      version: v1
  template:
    metadata:
      labels:
        app: productpage
        version: v1
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - productpage
            topologyKey: kubernetes.io/hostname
      containers:
      - name: productpage
        image: docker.io/istio/examples-bookinfo-productpage-v1:1.18.0
        ports:
        - containerPort: 9080
注意:topologyKey 定义了反亲和性的作用域。使用 kubernetes.io/hostname 表示不同节点;使用 topology.kubernetes.io/zone 表示不同可用区。在故障注入测试中,建议使用 kubernetes.io/hostname 实现节点级隔离。

4.4 组合配置:nodeAffinity + podAntiAffinity

在实际生产环境中,通常需要同时使用两种策略:先用 nodeAffinity 将服务限定到特定可用区,再用 podAntiAffinity 将副本分散到该可用区内的不同节点上。以下为完整的组合配置示例:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: productpage-v1
  namespace: bookinfo
spec:
  replicas: 3
  selector:
    matchLabels:
      app: productpage
      version: v1
  template:
    metadata:
      labels:
        app: productpage
        version: v1
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: topology.kubernetes.io/zone
                operator: In
                values:
                - us-east-1a
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - productpage
            topologyKey: kubernetes.io/hostname
      containers:
      - name: productpage
        image: docker.io/istio/examples-bookinfo-productpage-v1:1.18.0
        ports:
        - containerPort: 9080
验证方法:部署后使用 kubectl get pods -n bookinfo -o wide 查看每个Pod所在的节点。如果所有Pod的 NODE 列都不同,且节点标签包含 us-east-1a,则配置生效。

4.5 调度亲和性策略的SVG架构图

下图展示了组合亲和性策略下的Pod调度结果:3个 productpage 副本被强制调度到 us-east-1a 可用区的3个不同节点上,实现了可用区与节点级的双重容错隔离。

组合亲和性策略调度架构图 可用区:us-east-1a(nodeAffinity 强制约束) 节点 A kubernetes.io/hostname: node-a productpage-v1-xxx app=productpage 节点 B kubernetes.io/hostname: node-b productpage-v1-yyy app=productpage 节点 C kubernetes.io/hostname: node-c productpage-v1-zzz app=productpage podAntiAffinity 强制约束 topologyKey: kubernetes.io/hostname → 每个节点最多一个副本 节点标签:topology.kubernetes.io/zone=us-east-1a(nodeAffinity 强制匹配)

4.6 调度策略验证与故障注入准备

完成亲和性配置后,建议执行以下验证步骤,确保调度策略按预期生效:

  1. 检查Pod调度状态:使用 kubectl get pods -n bookinfo -o wide 确认所有Pod的 NODE 列显示不同的节点名称。
  2. 验证节点标签:使用 kubectl get nodes --show-labels | grep us-east-1a 确认目标节点具有正确的可用区标签。
  3. 模拟节点故障:在后续章节中,我们将通过Istio故障注入或直接 kubectl cordon 节点来验证亲和性策略的容错效果。
故障注入测试预期:当 nodeAffinity 与 podAntiAffinity 同时生效时,即使某个节点发生故障,其他节点上的服务副本仍能继续处理流量,实现高可用。在后续章节中,我们将通过Istio的故障注入机制模拟节点级故障,验证这一容错能力。