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个不同节点上,实现了可用区与节点级的双重容错隔离。
4.6 调度策略验证与故障注入准备
完成亲和性配置后,建议执行以下验证步骤,确保调度策略按预期生效:
- 检查Pod调度状态:使用
kubectl get pods -n bookinfo -o wide确认所有Pod的NODE列显示不同的节点名称。 - 验证节点标签:使用
kubectl get nodes --show-labels | grep us-east-1a确认目标节点具有正确的可用区标签。 - 模拟节点故障:在后续章节中,我们将通过Istio故障注入或直接
kubectl cordon节点来验证亲和性策略的容错效果。
故障注入测试预期:当
nodeAffinity 与 podAntiAffinity 同时生效时,即使某个节点发生故障,其他节点上的服务副本仍能继续处理流量,实现高可用。在后续章节中,我们将通过Istio的故障注入机制模拟节点级故障,验证这一容错能力。