一、 Pod 调度策略深度解析

Kubernetes 的默认调度器(default-scheduler)通过三个核心步骤将 Pod 分配到节点上:

  1. 预选(Predicates):排除不满足基本条件的节点(如内存不足、端口冲突)。

  2. 优选(Priorities):在剩余节点中,根据权重进行打分(如选择资源利用率低的节点)。

  3. 绑定:将 Pod 绑定到得分最高的节点。

除了默认的调度逻辑,我们可以通过以下策略控制 Pod 的去向:

1. 节点标签与调度
  • 指定节点名称调度(硬指定)

    • 特点:绕过调度器,强制 Pod 运行在特定节点。

    • 场景:测试环境或特殊硬件需求的节点。

    • 配置:在 spec.nodeName中指定节点名。

  • 指定节点标签调度(软指定)

    • 特点:通过节点标签(Labels)进行匹配,需经过调度器。

    • 逻辑步骤

      1. 给节点打标签:kubectl label nodes <node-name> <key>=<value>

      2. 编辑 Pod YAML,使用 nodeSelector指定标签。

2. 亲和性策略(Affinity)

亲和性用于表达“偏好”或“强制要求”,分为节点亲和性(Node Affinity)Pod 亲和性(Pod Affinity)

  • 节点亲和性 (nodeAffinity)

    • 作用:让 Pod 倾向于运行在带有特定标签的节点上。

    • 策略类型

      • requiredDuringSchedulingIgnoredDuringExecution硬策略,必须满足,否则 Pod 处于 Pending 状态。

      • preferredDuringSchedulingIgnoredDuringExecution软策略,尽量满足,不满足也能运行。

    • 匹配逻辑(操作符)

      • In, NotIn:包含/不包含(最常用)。

      • Exists, DoesNotExist:存在/不存在(只需判断键,无需值)。

      • Gt, Lt:大于/小于(针对整数值)。

  • Pod 亲和性 (podAffinity)

    • 作用:让 Pod 倾向于与其他 Pod 运行在同一拓扑域(如同一节点、同一可用区)。

    • 场景:微服务间的低延迟通信(如前端与后端同节点)。

    • 反亲和性 (podAntiAffinity):让 Pod 尽量与其他 Pod 运行在同一拓扑域。

    • 核心配置

      • labelSelector:选择哪些 Pod 的标签作为参照。

      • topologyKey:定义“拓扑域”的键(通常使用 kubernetes.io/hostname表示节点级别,或使用云平台标签表示可用区级别)。

3. 实战示例
  • 示例 1:节点亲和性(软策略)

    
      

    yaml

    yaml

    affinity:
      nodeAffinity:
        preferredDuringSchedulingIgnoredDuringExecution:
        - weight: 1
          preference:
            matchExpressions:
            - key: env
              operator: In
              values: [ "production" ]
    • 解释:尽量将 Pod 调度到 env=production的节点,如果没有,也可以运行在其他节点。

  • 示例 2:Pod 反亲和性(硬策略)

    
      

    yaml

    yaml

    affinity:
      podAntiAffinity:
        requiredDuringSchedulingIgnoredDuringExecution:
        - labelSelector:
            matchExpressions:
            - key: app
              operator: In
              values: [ "myapp" ]
          topologyKey: kubernetes.io/hostname
    • 解释:强制要求同一个节点上不能运行两个 app=myapp的 Pod(实现高可用,避免单点故障)。


二、 污点与容忍度(Taints & Tolerations)

污点是节点的属性,用于排斥​ Pod;容忍度是 Pod 的属性,用于允许被调度到有污点的节点。

1. 污点的作用
  • NoSchedule:不将 Pod 调度到带有该污点的节点(除非 Pod 有容忍度)。

  • PreferNoSchedule:尽量避免调度,但不是强制。

  • NoExecute:不调度新 Pod,并驱逐节点上已有的 Pod(除非 Pod 有容忍度)。

2. 设置污点

bash

bash

kubectl taint node <node-name> <key>=<value>:<effect>
  • 示例

    
      

    bash

    bash

    kubectl taint node k8s-node01 key1=value1:NoSchedule
3. 容忍度(Tolerations)

在 Pod 的 YAML 中添加 tolerations字段,允许 Pod 被调度到有特定污点的节点。

  • 配置示例

    
      

    yaml

    yaml

    tolerations:
    - key: "key1"
      operator: "Equal"
      value: "value1"
      effect: "NoSchedule"
  • 解释:该 Pod 可以容忍 key1=value1:NoSchedule的污点,因此可以被调度到 k8s-node01

4. 典型应用场景
  • 专用节点:给 GPU 节点打上 dedicated=gpu:NoSchedule污点,只有带有容忍度的 Pod(如 AI 训练任务)才能运行。

  • 维护模式:给节点打上 maintenance=true:NoExecute污点,驱逐所有非必要 Pod,进行维护。

  • 弹性伸缩:在云平台上,通过污点标记节点即将被销毁,让 Pod 自动迁移。

四、Pod 生命周期(Lifecycle)深度解析

调度完成 ≠ Pod 可用,Pod 生命周期决定了容器何时启动、何时就绪、何时销毁


1️⃣ Pod 的状态流转(Phase)

状态

说明

Pending

Pod 已被创建,但尚未调度成功或镜像未拉取

ContainerCreating

正在创建容器

Running

至少一个容器正在运行

Succeeded

所有容器正常退出(适用于 Job)

Failed

至少一个容器非正常退出

Unknown

无法获取 Pod 状态(通常是节点失联)

📌 调度发生在 Pending 阶段


2️⃣ 容器状态(ContainerStatus)


bash

bash

kubectl describe pod <pod-name>

状态

含义

Waiting

等待启动(镜像拉取、初始化)

Running

容器正在运行

Terminated

容器已退出

常见原因:

  • ImagePullBackOff

  • CrashLoopBackOff

  • Completed


3️⃣ Pod 生命周期核心阶段


纯文本

纯文本

Pod 创建
   ↓
调度(Scheduler)
   ↓
Pod 进入 Pending
   ↓
Init Container(初始化容器)
   ↓
主容器启动
   ↓
PostStart Hook(可选)
   ↓
Readiness Probe 成功 → 接收流量
   ↓
Liveness Probe 失败 → 重启容器
   ↓
PreStop Hook(可选)
   ↓
Pod 删除 / 驱逐

4️⃣ Init Container(初始化容器)

在主容器启动前执行,按顺序运行

特点:

  • 必须全部成功才会启动主容器

  • 常用于:

    • 数据库初始化

    • 配置文件准备

    • 依赖服务等待


yaml

yaml

spec:
  initContainers:
  - name: init-db
    image: busybox
    command: ["sh", "-c", "until nslookup mysql; do sleep 2; done"]

5️⃣ 容器探针(Probes)—— 决定 Pod 是否“可用”

✅ 三种探针

探针

作用

livenessProbe

判断容器是否存活(失败则重启)

readinessProbe

判断容器是否就绪(失败则摘除流量)

startupProbe

防止慢启动应用被误判为失败

示例

yaml

yaml

livenessProbe:
  httpGet:
    path: /health
    port: 8080
  periodSeconds: 10

readinessProbe:
  tcpSocket:
    port: 8080
  initialDelaySeconds: 5

📌 调度器不关心探针结果,Service 才关心 Readiness


6️⃣ 生命周期钩子(Hooks)

Hook

触发时机

postStart

容器启动后立即执行

preStop

容器终止前执行


yaml

yaml

lifecycle:
  postStart:
    exec:
      command: ["sh", "-c", "echo Hello > /tmp/hello"]
  preStop:
    exec:
      command: ["sh", "-c", "sleep 10"]

📌 优雅删除 Pod 的关键机制


7️⃣ Pod 删除流程(Graceful Shutdown)


纯文本

纯文本

kubectl delete pod
   ↓
Pod 标记为 Terminating
   ↓
执行 preStop Hook
   ↓
发送 SIGTERM
   ↓
等待 terminationGracePeriodSeconds(默认 30s)
   ↓
发送 SIGKILL

yaml

yaml

spec:
  terminationGracePeriodSeconds: 60

8️⃣ 重启策略(RestartPolicy)

策略

行为

Always(默认)

容器退出即重启

OnFailure

非 0 退出码才重启

Never

永不重启


yaml

yaml

spec:
  restartPolicy: OnFailure

📌 Job / CronJob 必须使用 Never 或 OnFailure


9️⃣ 生命周期与调度、亲和性的关系

组件

关注点

Scheduler

只关心 调度前

Lifecycle

关注 调度后 → 运行 → 销毁

Affinity

影响 Pod 去哪

Probe

影响 Pod 是否可用

Taint/Toleration

影响 是否允许调度


🔟 总结速记表

阶段

关键机制

调度前

亲和性、污点、资源请求

启动期

InitContainer、postStart

运行期

liveness / readiness / startup

删除期

preStop、SIGTERM、优雅下线


三、 综合实战场景

场景:我们有一个 Redis 集群,希望:

  1. Redis Pod 尽量运行在可用区 A(杭州)。

  2. Redis Pod 之间不能运行在同一节点(避免单点故障)。

  3. 只有带有 redis-role=master标签的节点才能运行 Redis Pod。

YAML 配置


yaml

yaml

apiVersion: v1
kind: Pod
metadata:
  name: redis-pod
  labels:
    app: redis
spec:
  containers:
  - name: redis
    image: redis:latest
  affinity:
    # 1. 节点亲和性:尽量运行在可用区A(假设可用区A的标签是 zone=hangzhou)
    nodeAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        preference:
          matchExpressions:
          - key: zone
            operator: In
            values: [ "hangzhou" ]
    # 2. Pod反亲和性:不能运行在同一节点
    podAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values: [ "redis" ]
        topologyKey: kubernetes.io/hostname
  # 3. 节点亲和性(硬策略):必须运行在带有 redis-role=master 标签的节点
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
    - matchExpressions:
      - key: redis-role
        operator: In
        values: [ "master" ]

四、 总结

概念

作用

方向

示例

节点亲和性

Pod 倾向于运行在特定标签的节点

Pod → Node

env=production

Pod 亲和性

Pod 倾向于与其他 Pod 同拓扑域

Pod → Pod

同节点、同可用区

Pod 反亲和性

Pod 倾向于不与其他 Pod 同拓扑域

Pod → Pod

不同节点、不同可用区

污点 (Taint)

节点排斥 Pod

Node → Pod

dedicated=gpu:NoSchedule

容忍度 (Toleration)

Pod 允许被调度到有污点的节点

Pod → Node

容忍 dedicated=gpu:NoSchedule

通过合理组合亲和性和污点,可以实现复杂的调度策略,满足生产环境的高可用、资源隔离、成本优化等需求。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐