74·调度与资源进阶

Pod 亲和性

kubernetesschedulerpod-affinitypod-antiaffinity

Pod 亲和性

学习目标

  1. 理解 Pod 亲和性和反亲和性的概念
  2. 掌握 podAffinity 和 podAntiAffinity 的使用
  3. 了解 topologyKey 的作用

核心概念

一句话解释

Pod 亲和性控制 Pod 之间的调度关系:亲和性让 Pod 靠近运行,反亲和性让 Pod 分散运行。

两种类型

┌─────────────────────────────────────────────────────────┐
│                    Pod 亲和性类型                        │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  podAffinity(亲和性)                                  │
│  ┌─────────────────────────────────────────┐           │
│  │  让 Pod 与其他 Pod 靠近运行             │           │
│  │  例:Web 服务与 Redis 部署在同一节点     │           │
│  └─────────────────────────────────────────┘           │
│                                                         │
│  podAntiAffinity(反亲和性)                            │
│  ┌─────────────────────────────────────────┐           │
│  │  让 Pod 远离其他 Pod 运行               │           │
│  │  例:同一服务的副本分散到不同节点        │           │
│  └─────────────────────────────────────────┘           │
│                                                         │
└─────────────────────────────────────────────────────────┘

YAML 语法

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
  labels:
    app: web
spec:
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - cache
        topologyKey: kubernetes.io/hostname
    podAntiAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchExpressions:
            - key: app
              operator: In
              values:
              - web
          topologyKey: kubernetes.io/hostname
  containers:
  - name: web
    image: nginx

topologyKey 解释

topologyKey 定义"靠近"或"远离"的范围

┌─────────────────────────────────────────────────────────┐
│                    topologyKey 示例                      │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  kubernetes.io/hostname                                  │
│  ┌─────────────────────────────────────────┐           │
│  │  范围:单个节点                          │           │
│  │  应用:Pod 部署在同一节点/不同节点        │           │
│  └─────────────────────────────────────────┘           │
│                                                         │
│  topology.kubernetes.io/zone                             │
│  ┌─────────────────────────────────────────┐           │
│  │  范围:同一可用区                        │           │
│  │  应用:Pod 分散到不同可用区              │           │
│  └─────────────────────────────────────────┘           │
│                                                         │
│  kubernetes.io/os                                        │
│  ┌─────────────────────────────────────────┐           │
│  │  范围:同一操作系统                      │           │
│  │  应用:OS 特定工作负载                   │           │
│  └─────────────────────────────────────────┘           │
│                                                         │
└─────────────────────────────────────────────────────────┘

亲和性示例

# 示例:Web 服务靠近 Redis 运行
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      affinity:
        podAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - redis
            topologyKey: kubernetes.io/hostname
      containers:
      - name: web
        image: nginx

反亲和性示例

# 示例:同一服务的副本分散到不同节点
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-ha
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - web
            topologyKey: kubernetes.io/hostname
      containers:
      - name: web
        image: nginx

调度流程示例

场景:3 个 web 副本,使用 podAntiAffinity 分散到不同节点

现有集群:
┌─────────┬─────────┬─────────┐
│  Node1  │  Node2  │  Node3  │
│         │         │         │
└─────────┴─────────┴─────────┘

调度过程:
1. web-pod-1 → Node1(无反亲和性限制)
2. web-pod-2 → 检查反亲和性
   - Node1: 有 app=web 的 Pod,不满足
   - Node2: 无 app=web 的 Pod,满足 → 调度到 Node2
3. web-pod-3 → 检查反亲和性
   - Node1: 有 app=web 的 Pod,不满足
   - Node2: 有 app=web 的 Pod,不满足
   - Node3: 无 app=web 的 Pod,满足 → 调度到 Node3

结果:
┌─────────┬─────────┬─────────┐
│  Node1  │  Node2  │  Node3  │
│ web-1   │ web-2   │ web-3   │
└─────────┴─────────┴─────────┘

操作符和表达式

# 使用 matchLabels(简单匹配)
podAffinity:
  requiredDuringSchedulingIgnoredDuringExecution:
  - labelSelector:
      matchLabels:
        app: redis
    topologyKey: kubernetes.io/hostname

# 使用 matchExpressions(复杂匹配)
podAffinity:
  requiredDuringSchedulingIgnoredDuringExecution:
  - labelSelector:
      matchExpressions:
      - key: app
        operator: In
        values:
        - redis
        - memcached
      - key: version
        operator: NotIn
        values:
        - v1
    topologyKey: kubernetes.io/hostname

实践练习

练习 1:Pod 亲和性

# 创建 Redis 部署
apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis
spec:
  replicas: 1
  selector:
    matchLabels:
      app: redis
  template:
    metadata:
      labels:
        app: redis
    spec:
      containers:
      - name: redis
        image: redis
---
# 创建靠近 Redis 的 Web 部署
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-near-redis
spec:
  replicas: 2
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      affinity:
        podAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - redis
            topologyKey: kubernetes.io/hostname
      containers:
      - name: web
        image: nginx
# 部署并验证
kubectl apply -f pod-affinity.yaml
kubectl get pods -o wide
# web-near-redis 的 Pod 应该与 redis 在同一节点

练习 2:Pod 反亲和性(高可用)

# pod-antiaffinity-ha.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-ha
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web
      tier: frontend
  template:
    metadata:
      labels:
        app: web
        tier: frontend
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - web
              - key: tier
                operator: In
                values:
                - frontend
            topologyKey: kubernetes.io/hostname
      containers:
      - name: web
        image: nginx

练习 3:跨可用区反亲和性

# pod-antiaffinity-zone.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-multi-zone
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - web
              topologyKey: topology.kubernetes.io/zone
      containers:
      - name: web
        image: nginx

练习 4:组合亲和性和反亲和性

# pod-affinity-combined.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      affinity:
        # 靠近缓存服务
        podAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 80
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - cache
              topologyKey: kubernetes.io/hostname
        # 分散到不同节点
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - web
            topologyKey: kubernetes.io/hostname
      containers:
      - name: web
        image: nginx

常见使用场景

1. 高可用部署
   - 使用 podAntiAffinity 将副本分散到不同节点/可用区
   - 避免单点故障

2. 数据本地化
   - 使用 podAffinity 让应用靠近数据源
   - 减少网络延迟

3. 微服务协作
   - 相关服务部署在同一节点/可用区
   - 提高通信效率

4. 资源隔离
   - 不同租户的工作负载分散到不同节点
   - 使用 podAntiAffinity 实现隔离

小结

要点说明
podAffinity让 Pod 靠近其他 Pod 运行
podAntiAffinity让 Pod 远离其他 Pod 运行
topologyKey定义靠近/远离的范围
required硬性要求,必须满足
preferred软性偏好,尽量满足
使用场景高可用、数据本地化、资源隔离

练习编辑器

bash
Loading...

继续学习

完成本课后,建议继续学习下一课「污点与容忍」 以巩固所学知识。