Kubernetes

K8s Pod 拓扑分布约束详解

·14 分钟阅读·5496 字

K8s Pod 拓扑分布约束详解 的详细笔记

📋 目录

K8s Pod 拓扑分布约束详解

核心概念 Pod 拓扑分布约束控制 Pod 在拓扑域中的分布,实现高可用和资源均衡。

1. 一、核心定位与解决什么问题

1.1. 1. 定义

**topologySpreadConstraints**(拓扑分散约束)是调度器高级均衡能力,用于强制同业务Pod均匀打散在不同故障域(节点、机架、可用区AZ),相比 Pod 反亲和更灵活精细。

1.2. 2. 对比旧方案缺陷

  1. podAntiAffinity 硬反亲和**:****required** 拓扑域最多只能放1个Pod,副本多、节点少时直接Pending;**preferred** 仅偏好,无法严格均衡。
  2. 无约束默认调度:调度器装箱优先填满单节点/单AZ,大量副本堆在同一故障域,一旦节点/机房宕机服务全挂。

1.3. 3. 核心价值(生产高可用必备,你的Agent训练/推理集群强适用)

  1. 容灾隔离**:多副本均匀分到不同节点、不同可用区,单点故障不整体宕机;**
  2. 资源均衡**:GPU/CPU负载分散,避免单节点显卡打满;**
  3. 多AZ流量均衡**:云集群跨区部署,均衡各区实例数量,均衡负载;**
  4. 支持软硬约束,可配置不满足均衡时直接拒绝调度或尽力调度。

1.4. 基础概念:拓扑域 topology domain

以节点相同标签value划分一组节点,一组节点=一个拓扑域,划分标签键叫 **topologyKey****。

标准内置拓扑键(开箱即用):**

| | | |

|---|---|---|

|topologyKey|拓扑域粒度|用途|

|**kubernetes.io/hostname**|单台物理节点|同业务不扎堆同一服务器|

|**topology.kubernetes.io/zone**|可用区AZ(机房)|跨机房容灾,核心生产配置|

|**topology.kubernetes.io/region**|地域|异地多活极少使用|

|自定义:**rack=rack01** 机架、**gpu-type=a100** 显卡机型。|||

2. 二、五大核心字段完整拆解(必填+可选)


spec:

  topologySpreadConstraints:

  - maxSkew: 1                  # 必选:拓扑域之间允许最大Pod差值

    topologyKey: topology.kubernetes.io/zone # 必选:划分拓扑域的节点标签

    whenUnsatisfiable: DoNotSchedule # 必选:均衡不达标如何处理

    labelSelector:              # 必选:统计哪些Pod算同业务副本

      matchLabels:

        app: llm-agent

    minDomains: 2              # 可选:至少分布到几个拓扑域

    nodeAffinityPolicy: Honor  # 可选:是否遵守节点亲和

    nodeTaintsPolicy: Honor    # 可选:是否遵守节点污点容忍

2.1. 1. maxSkew 最大偏差(最关键)

控制不同拓扑域内匹配Pod数量允许的最大差值,推荐固定 **maxSkew:1** **达到完全均衡。

计算公式:

任意域Pod数 − 全局最少Pod域数量 ≤ maxSkew

示例:3个可用区A/B/C,现有Pod [2,1,1],差值=1,maxSkew=1 满足;

若现有 [3,1,1],差值=2,maxSkew=1 不满足,无法调度新Pod。**

2.2. 2. whenUnsatisfiable 两种策略(硬约束/软约束)

  1. DoNotSchedule(硬约束,生产核心业务首选)**
    均衡条件无法满足时,直接拒绝调度,Pod长期Pending,强制等待拓扑域负载均衡再创建。
    风险:副本扩容、节点故障删除Pod后,容易出现Pending。**
  2. ScheduleAnyway(软约束,测试/低优先级业务)**
    尽量往少Pod的拓扑域调度;实在无法均衡,也允许放置,不会阻塞Pod创建。**

2.3. 3. labelSelector

指定哪些Pod算作一组统计副本,必须和Deployment模板Pod标签完全一致,调度器只会统计匹配该标签的Pod来计算skew差值。

2.4. 4. minDomains(可选)最小分布域数量

强制Pod至少分散到N个拓扑域,多AZ容灾场景设 **minDomains:3**,确保3个机房都有实例。

2.5. 5. nodeAffinityPolicy / nodeTaintsPolicy

  • Honor:同时遵守节点亲和、污点容忍(默认,生产必用)
  • Ignore:忽略亲和/污点,仅做均衡,极少使用

3. 三、两种标准实战模板(GPU Agent集群直接复制)

3.1. 模板1:生产高可用双维度硬约束(跨可用区+跨节点)

需求:LLM推理Agent,副本均匀分散到不同AZ、不同节点,不均衡则不调度


apiVersion: apps/v1

kind: Deployment

metadata:

  name: llm-infer-agent

spec:

  replicas: 6

  selector:

    matchLabels:

      app: llm-infer-agent

  template:

    metadata:

      labels:

        app: llm-infer-agent

    spec:

      # 1. 第一层:跨可用区均衡(硬约束,优先保障机房容灾)

      topologySpreadConstraints:

      - maxSkew: 1

        topologyKey: topology.kubernetes.io/zone

        whenUnsatisfiable: DoNotSchedule

        minDomains: 3

        labelSelector:

          matchLabels:

            app: llm-infer-agent

      # 2. 第二层:同可用区内,分散到不同节点(软约束,防止单节点堆太多)

      - maxSkew: 1

        topologyKey: kubernetes.io/hostname

        whenUnsatisfiable: ScheduleAnyway

        labelSelector:

          matchLabels:

            app: llm-infer-agent

      # 配套GPU调度:污点容忍+节点机型筛选

      tolerations:

      - key: gpu

        operator: Equal

        value: "true"

        effect: NoSchedule

      affinity:

        nodeAffinity:

          requiredDuringSchedulingIgnoredDuringExecution:

            nodeSelectorTerms:

            - matchExpressions:

              - key: gpu-type

                operator: In

                values: ["a100-sxm4-80gb"]

      containers:

      - name: agent

        image: qwen-agent:v1

        resources:

          limits:

            nvidia.com/gpu: 1

            cpu: 4

            memory: 16Gi

调度效果:3个可用区,每个AZ固定2个Pod;每个AZ内尽量分散到不同GPU节点。

3.2. 模板2:训练任务软均衡(Volcano Job搭配拓扑分散)

批量训练任务不希望阻塞扩容,使用ScheduleAnyway:


spec:

  template:

    spec:

      topologySpreadConstraints:

      - maxSkew: 1

        topologyKey: topology.kubernetes.io/zone

        whenUnsatisfiable: ScheduleAnyway

        labelSelector:

          matchLabels:

            app: torch-train-job

4. 四、完整调度计算示例(直观理解maxSkew)

4.1. 场景

3个可用区 zone-a / zone-b / zone-c,maxSkew=1,DoNotSchedule,label匹配app=agent

  1. 初始0副本,创建第1个Pod:任意区均可
  2. 第2个Pod:必须放到另外空区,避免差值=2
  3. 第3个Pod:三区各1个,均衡
  4. 创建第4个Pod:只能放到现有1个Pod的区,每个区最多2个(差值1)
  5. 若zone-a已有3个,其他两区各1个:差值=2,新Pod无法调度,Pending

5. 五、与其他调度约束协同优先级

调度器校验顺序(全部同时生效,叠加限制)

  1. 污点Taints & Tolerations:过滤无资格节点
  2. nodeSelector / nodeAffinity:筛选机型、GPU标签
  3. topologySpreadConstraints:均衡拓扑域分布
  4. podAntiAffinity:同节点禁止重复副本
  5. 资源(CPU/GPU)配额校验

5.1. 叠加约束极易Pending场景

同时配置:

  1. zone硬均衡 DoNotSchedule maxSkew=1
  2. hostname硬反亲和,单节点只能1个Pod
    集群节点不足时,两个约束交集为空,Pod永久Pending。
    解决方案:其中一层改为 ScheduleAnyway 软约束。

6. 六、常见Pod Pending根因(拓扑约束专属)

  1. maxSkew=1,拓扑域Pod数量差值超过1,DoNotSchedule拒绝调度**
    排查:****kubectl get pods -o wide** 统计各AZ/节点副本数量,删除多余Pod或增加节点。
  2. **minDomains** 指定3个可用区,但集群只有2个AZ,永远无法满足,持续Pending。
  3. 多套拓扑约束(zone+hostname)均为DoNotSchedule,无节点同时满足两层均衡。
  4. labelSelector写错标签,调度统计不到现有副本,计算skew错误导致拒绝。
  5. 节点缺少 **topology.kubernetes.io/zone** 标签,无法划分拓扑域。

7. 七、生产最佳实践(AI/GPU集群专用)

  1. 核心线上推理服务**
    两层拓扑约束:zone使用DoNotSchedule硬均衡,hostname使用ScheduleAnyway软均衡,minDomains匹配集群可用区数量。**
  2. 批量训练任务**
    全部使用ScheduleAnyway,避免扩容阻塞,保证训练任务正常启动。**
  3. GPU集群搭配规则
    拓扑约束 + GPU节点污点容忍 + nodeAffinity筛选显卡型号三位一体;
    均衡不同A100/H100节点负载,避免单节点8卡全部占满。
  4. 副本扩容规划
    副本总数 ÷ 可用区数量 尽量整除,保证完美均衡无差值。
  5. 故障预案
    节点宕机删除Pod后,拓扑均衡被打破,新扩容Pod会自动补齐差值;若长期Pending,临时调高maxSkew。

8. 八、拓扑分散 vs Pod反亲和 选型对比

| | | |

|---|---|---|

|特性|topologySpreadConstraints|podAntiAffinity required硬反亲和|

|单拓扑域副本上限|由maxSkew控制,可放多个|最多1个|

|均衡能力|自动均衡各域数量|仅限制单域数量,无法均衡|

|阻塞风险|DoNotSchedule时可能Pending|节点不足直接Pending|

|适用场景|多副本高可用、GPU负载均衡|单副本独占节点、数据库主从隔离|

|推荐优先级|生产首选|仅特殊独占场景使用|

9. 九、高频踩坑总结

  1. topologyKey必须是节点存在的标签,云集群默认带zone,自建裸机需手动打标签;
  2. labelSelector必须和Pod模板labels完全一致,否则统计副本数量错误;
  3. 多层DoNotSchedule约束极易冲突导致Pending,至少一层改为ScheduleAnyway;
  4. maxSkew不能设0,最小合法值为1;
  5. minDomains不能超过集群实际拓扑域总数,否则永久无法调度;
  6. 批量删除节点后,副本分布失衡会触发新Pod Pending,可临时调大maxSkew快速恢复;
  7. 拓扑分散只控制调度,不会驱逐已运行Pod;存量Pod分布不均不会自动重排,仅影响新创建Pod。

关联文档

Yanche Blog

记录云原生、Linux、数据库等技术领域的学习心得,以及日常生活的思考与感悟。

© 2026 Yanche Blog. All rights reserved.

Powered by Astro