跳到正文
复制成功
请遵守本站许可
报告
章节_文章 // 现场报告

文章编号: RL-POD调度机制

2026.07.26

Pod 调度机制

Chavy
Chavy
#Kubernetes#Pod#调度#亲和性
档案

摘要:理解 Scheduler 的筛选、评分与绑定流程,掌握 nodeSelector、节点与 Pod 亲和性、拓扑约束、优先级和调度故障排查。

1. Kubernetes 调度架构#

1. 什么是 Scheduler?#

Scheduler 是 Kubernetes 控制平面的核心组件之一。

它的主要职责是:

为尚未分配节点的 Pod 选择合适的 Node。

Kubernetes 调度器通常运行在 Control Plane 节点上。

核心流程:

flowchart TB
    N0["用户创建 Pod"]
    N1["API Server"]
    N2["etcd 保存状态"]
    N3["Scheduler 监听 Pod"]
    N4["筛选符合条件的 Node"]
    N5["对 Node 评分"]
    N6["选择最合适的 Node"]
    N7["绑定 Pod 与 Node"]
    N8["kubelet 监听 Pod"]
    N9["拉取镜像并启动容器"]
    N0 --> N1
    N1 --> N2
    N2 --> N3
    N3 --> N4
    N4 --> N5
    N5 --> N6
    N6 --> N7
    N7 --> N8
    N8 --> N9

这里有几个重要组件:

组件职责
API Server接收和管理 Kubernetes API 请求
etcd保存集群状态数据
Scheduler为 Pod 选择 Node
kubelet在节点上管理 Pod
Container Runtime实际运行容器

注意:

Scheduler 负责选择节点,但不负责真正启动容器。

容器的启动工作由目标节点上的 kubelet 和容器运行时完成。

2. Pod 为什么会处于 Pending?#

创建 Pod 后:

PRTCL // BASH
Terminal window
kubectl get pods

可能看到:

PRTCL // TEXT
NAME READY STATUS
nginx 0/1 Pending

Pending 不一定代表调度失败。

Pod 从创建到正常运行,可能经历:

flowchart TB
    N0["Pending"]
    N1["等待调度"]
    N2["分配 Node"]
    N3["拉取镜像"]
    N4["创建容器"]
    N5["Running"]
    N0 --> N1
    N1 --> N2
    N2 --> N3
    N3 --> N4
    N4 --> N5

如果无法找到合适节点,就可能一直处于 Pending。

查看原因:

PRTCL // BASH
Terminal window
kubectl describe pod nginx

重点关注:

PRTCL // TEXT
Events:
Warning FailedScheduling

例如:

PRTCL // TEXT
0/5 nodes are available:
2 Insufficient cpu,
3 node(s) didn't match Pod's node affinity/selector.

表示:

  • 2 个节点 CPU 资源不足。
  • 3 个节点不满足节点选择条件。

2. Scheduler 调度过程:Filter 与 Score#

Kubernetes Scheduler 不是简单随机选择节点,而是经过一系列调度插件处理。

核心可以分为两个阶段:

  1. Filter:过滤不符合要求的节点。
  2. Score:给符合要求的节点评分。

1. Filter 阶段#

假设集群有 5 个节点:

NodeCPU 可分配资源是否满足要求
Node-12 CPU是
Node-20.5 CPU否
Node-38 CPU是
Node-41 CPU是
Node-50.2 CPU否

Pod 需要:

PRTCL // YAML
resources:
requests:
cpu: "1"

Filter 会过滤掉资源不足的节点。

结果:

PRTCL // TEXT
Node-1:通过
Node-2:过滤
Node-3:通过
Node-4:通过
Node-5:过滤

2. Score 阶段#

接下来对剩余节点评分。

例如:

Node资源评分其他调度评分最终评分
Node-1708075
Node-3908588
Node-4607065

最终选择:

PRTCL // TEXT
Node-3

注意:

实际 Scheduler 使用多个调度插件和权重计算得分,表格仅用于理解原理。

3. 调度的两个核心阶段#

flowchart TB
    N0["Filter<br/>过滤不符合条件的节点"]
    N1["Score<br/>对符合条件的节点进行评分"]
    N2["Bind<br/>将 Pod 绑定到选定节点"]
    N0 --> N1
    N1 --> N2

记忆:

  • Filter:能不能运行?
  • Score:运行在哪里更合适?
  • Bind:最终绑定到哪个节点?

3. NodeSelector 节点选择#

现在我们开始学习如何主动控制 Pod 的调度位置。

最简单的方式就是 NodeSelector。

1. 什么是 NodeSelector?#

NodeSelector 是通过 Node 标签选择调度目标的机制。

例如:

集群中有三个节点:

PRTCL // TEXT
worker-1
worker-2
worker-3

我们希望某个 Pod 只运行在具有 disktype=ssd 标签的节点上。

首先给节点打标签:

PRTCL // BASH
Terminal window
kubectl label nodes worker-1 disktype=ssd

查看:

PRTCL // BASH
Terminal window
kubectl get nodes --show-labels

2. 在 Pod 中配置 NodeSelector#

PRTCL // YAML
apiVersion: v1
kind: Pod
metadata:
name: nginx-ssd
spec:
nodeSelector:
disktype: ssd
containers:
- name: nginx
image: nginx:1.27

Pod 只能被调度到满足:

PRTCL // TEXT
disktype=ssd

的节点。

3. NodeSelector 工作原理#

flowchart TB
    N0["Pod"]
    N1["Scheduler"]
    N2["Node-1<br/>ssd"]
    N3["Node-2<br/>hdd"]
    N4["Node-3<br/>ssd"]
    N5["筛选 Node-1、Node-3"]
    N6["选择其中一个节点"]
    N0 -->|"nodeSelector: disktype: ssd"| N1
    N1 --> N2
    N1 --> N3
    N1 --> N4
    N2 --> N5
    N4 --> N5
    N5 --> N6

注意:

NodeSelector 只能表达简单的标签等值匹配。

如果需要复杂的匹配条件,就需要使用 Node Affinity。

4. Node Affinity 节点亲和性#

NodeSelector 虽然简单,但在生产环境中有一个明显局限:

它只能进行简单的标签匹配,无法表达复杂的调度条件。

例如:

  • 只允许调度到 SSD 节点。
  • 允许调度到 SSD 或 NVMe 节点。
  • 优先调度到高性能节点,但没有高性能节点时也可以使用普通节点。
  • 不允许调度到某些特定节点。

这时就需要使用 Node Affinity。

1. 什么是 Node Affinity?#

Node Affinity(节点亲和性)是一种更加灵活的节点选择机制。

它允许 Pod 根据 Node 的标签表达复杂的调度规则。

Node Affinity 有两种主要类型:

类型含义是否强制
requiredDuringSchedulingIgnoredDuringExecution必须满足节点选择条件是
preferredDuringSchedulingIgnoredDuringExecution尽量满足节点选择条件否

简单理解:

  • required:必须满足,否则不能调度。
  • preferred:优先满足,不满足也可以调度。

2. requiredDuringSchedulingIgnoredDuringExecution#

这是硬性节点亲和性。

例如:

只允许 Pod 调度到 disktype=ssd 的节点。

PRTCL // YAML
apiVersion: v1
kind: Pod
metadata:
name: nginx-affinity
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values:
- ssd
containers:
- name: nginx
image: nginx:1.27

解释:

PRTCL // YAML
key: disktype

匹配节点标签的键。

PRTCL // YAML
operator: In

表示标签值必须属于指定集合。

PRTCL // YAML
values:
- ssd

指定允许的标签值。

因此:

PRTCL // TEXT
Node-1:disktype=ssd 允许
Node-2:disktype=hdd 不允许
Node-3:disktype=nvme 不允许

如果集群中没有符合条件的节点:

PRTCL // TEXT
Pod:Pending
Reason:FailedScheduling

3. preferredDuringSchedulingIgnoredDuringExecution#

这是软性节点亲和性。

例如:

优先选择 SSD 节点,但如果没有 SSD 节点,也允许使用其他节点。

PRTCL // YAML
apiVersion: v1
kind: Pod
metadata:
name: nginx-preferred
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 80
preference:
matchExpressions:
- key: disktype
operator: In
values:
- ssd
containers:
- name: nginx
image: nginx:1.27

这里:

PRTCL // YAML
weight: 80

表示该偏好规则的权重,取值范围是 1~100。

权重越高,该偏好对调度评分的影响通常越大。

注意:

weight: 80 不代表节点有 80% 的调度概率,也不代表节点最终得分就是 80。

如果没有满足 SSD 条件的节点,Pod 仍然可以调度到其他可用节点。

4. required 与 preferred 对比#

硬性亲和性(required) 必须满足

Node-1 允许

Node-2 禁止

Node-3 允许

软性亲和性(preferred) 优先满足

Node-1 优先

Node-2 可选

Node-3 优先

5. Node Affinity 常用操作符#

Node Affinity 的强大之处在于支持多种表达式。

常用操作符:

Operator含义示例
In标签值属于指定集合ssd 或 nvme
NotIn标签值不属于指定集合排除 hdd
Exists存在指定标签存在 gpu
DoesNotExist不存在指定标签不存在 gpu
Gt标签值大于指定值CPU 代数大于 8
Lt标签值小于指定值CPU 代数小于 16

注意:Gt 和 Lt 比较的是可解析为整数的标签值。

1. In:匹配指定集合#

PRTCL // YAML
matchExpressions:
- key: disktype
operator: In
values:
- ssd
- nvme

表示:

PRTCL // TEXT
disktype=ssd
或者
disktype=nvme

满足其中一个即可。

2. NotIn:排除指定集合#

PRTCL // YAML
matchExpressions:
- key: disktype
operator: NotIn
values:
- hdd

表示:

不允许调度到 disktype=hdd 的节点。

注意:如果节点根本没有 disktype 标签,NotIn 条件也可以满足。

3. Exists:标签必须存在#

PRTCL // YAML
matchExpressions:
- key: gpu
operator: Exists

表示:

节点必须存在 gpu 标签,不关心标签值。

例如:

PRTCL // TEXT
gpu=nvidia
gpu=amd

都可以满足条件。

4. DoesNotExist:标签不能存在#

PRTCL // YAML
matchExpressions:
- key: gpu
operator: DoesNotExist

表示:

节点不能存在 gpu 标签。

5. Gt 和 Lt#

例如:

PRTCL // YAML
matchExpressions:
- key: cpu-generation
operator: Gt
values:
- "8"

表示:

节点标签 cpu-generation 的整数值必须大于 8。

6. NodeSelectorTerms 与 matchExpressions 的逻辑关系#

这是 CKA 容易考查的细节。

Node Affinity 中有两层逻辑关系:

  • 不同的 nodeSelectorTerms 之间是 OR。
  • 同一个 nodeSelectorTerm 内的多个 matchExpressions 之间是 AND。

例如:

PRTCL // YAML
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values:
- ssd
- key: region
operator: In
values:
- east
- matchExpressions:
- key: disktype
operator: In
values:
- nvme

逻辑表达式:

PRTCL // TEXT
(disktype=ssd AND region=east)
OR
(disktype=nvme)

也就是说:

满足以下任意一个条件就可以调度:

  1. SSD 磁盘,并且位于 east 区域。
  2. 使用 NVMe 磁盘。

记忆:

Node Affinity 逻辑关系

nodeSelectorTerms 不同 Term 之间 OR

Term 1 AND disktype=ssd region=east

Term 2 AND disktype=nvme

Term 1 OR Term 2

1. 逻辑关系总结#

层级逻辑关系
多个 nodeSelectorTermsOR
同一 Term 内多个 matchExpressionsAND
同一 Term 内多个 matchFieldsAND
matchExpressions 与 matchFieldsAND

2. 一个常见陷阱#

如果这样写:

PRTCL // YAML
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values: [ssd]
- matchExpressions:
- key: disktype
operator: In
values: [nvme]

表示:

PRTCL // TEXT
disktype=ssd OR disktype=nvme

而不是要求节点同时具有两个值。

7. NodeSelector 与 Node Affinity 同时使用#

在实际生产中,可以同时使用这两种机制。

例如:

PRTCL // YAML
apiVersion: v1
kind: Pod
metadata:
name: nginx-combined
spec:
nodeSelector:
environment: production
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values:
- ssd
containers:
- name: nginx
image: nginx:1.27

它的逻辑是:

PRTCL // TEXT
environment=production
AND
disktype=ssd

必须同时满足。

例如:

Nodeenvironmentdisktype是否允许
Node-1productionssd是
Node-2productionhdd否
Node-3testingssd否
Node-4testinghdd否

注意:NodeSelector 与 required Node Affinity 是 AND 关系。如果两者条件冲突,Pod 无法调度。

8. IgnoredDuringExecution 到底是什么意思?#

你可能注意到了,Node Affinity 的两个字段名称都包含:

PRTCL // TEXT
IgnoredDuringExecution

为什么叫这个名字?

因为 Kubernetes 将节点亲和性分成两个阶段:

  1. Pod 调度之前:检查节点是否满足条件。
  2. Pod 运行期间:节点标签发生变化时,是否驱逐 Pod。

例如:

Pod 要求:

PRTCL // YAML
disktype: ssd

Node-1 原本具有:

PRTCL // TEXT
disktype=ssd

Pod 被成功调度到 Node-1。

现在管理员修改节点标签:

PRTCL // BASH
Terminal window
kubectl label node worker-1 disktype=hdd --overwrite

会发生什么?

Pod 不会因为这个标签变化而自动被驱逐。

因为:

PRTCL // YAML
requiredDuringSchedulingIgnoredDuringExecution

只在调度阶段强制检查条件,不会在运行期间因为条件失效而自动驱逐 Pod。

目前 Kubernetes Node Affinity 没有对应的 requiredDuringSchedulingRequiredDuringExecution 原生配置。

如果业务需要节点标签变化后迁移 Pod,需要借助其他控制器或人工重新创建 Pod。

9. Pod Affinity(Pod 亲和性)#

前面学习的 Node Affinity 是:

根据 Node 的标签决定 Pod 应该运行在哪个节点。

现在考虑另一个问题:

假设有一个 Web 应用和一个 Redis 缓存服务。

为了降低网络延迟,希望 Web Pod 尽量和 Redis Pod 部署在同一个节点。

这时,仅仅根据 Node 标签选择节点可能不够。

因为我们希望根据其他 Pod 的位置来决定当前 Pod 的调度位置。

这就是 Pod Affinity。

1. 什么是 Pod Affinity?#

Pod Affinity(Pod 亲和性)是一种根据已有 Pod 的标签和拓扑位置决定新 Pod 调度位置的机制。

例如:

flowchart TB
    N0["Node-1"]
    N1["Redis Pod"]
    N2["Web Pod"]
    N0 --> N1
    N0 --> N2

Web Pod 希望与 Redis Pod 尽可能靠近。

Pod Affinity 有两种主要类型:

类型含义
requiredDuringSchedulingIgnoredDuringExecution必须满足 Pod 亲和性条件
preferredDuringSchedulingIgnoredDuringExecution尽量满足 Pod 亲和性条件

2. required Pod Affinity#

假设 Redis Pod 有标签:

PRTCL // YAML
labels:
app: redis

现在创建 Web Pod,要求它必须与 Redis Pod 位于同一个 Node。

配置:

PRTCL // YAML
apiVersion: v1
kind: Pod
metadata:
name: web
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app: redis
topologyKey: kubernetes.io/hostname
containers:
- name: nginx
image: nginx:1.27

重点理解两个字段。

1. labelSelector#

PRTCL // YAML
labelSelector:
matchLabels:
app: redis

表示选择具有:

PRTCL // TEXT
app=redis

标签的 Pod。

2. topologyKey#

PRTCL // YAML
topologyKey: kubernetes.io/hostname

表示以节点主机名作为拓扑范围。

也就是说:

当前 Pod 必须调度到存在匹配 Redis Pod 的同一个 Node 上。

3. topologyKey 是什么?#

topologyKey 是 Pod Affinity 和 Pod Anti-Affinity 的核心概念。

它定义了拓扑分组的依据。

例如:

topologyKey含义
kubernetes.io/hostname同一个 Node
topology.kubernetes.io/zone同一个可用区
topology.kubernetes.io/region同一个区域

举例:

flowchart TB
    N0["Zone-A"]
    N1["Node-1"]
    N2["Redis"]
    N3["Node-2"]
    N4["Web"]
    N0 --> N1
    N1 --> N2
    N0 --> N3
    N3 --> N4

如果使用:

PRTCL // YAML
topologyKey: topology.kubernetes.io/zone

Web 可以运行在 Zone-A 内的不同 Node 上,只要满足 Pod 选择条件即可。

如果使用:

PRTCL // YAML
topologyKey: kubernetes.io/hostname

Web 必须和匹配的 Redis Pod 位于同一节点。

4. preferred Pod Affinity#

如果只是希望 Web 尽量和 Redis 位于同一个节点,而不是强制要求:

PRTCL // YAML
affinity:
podAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 80
podAffinityTerm:
labelSelector:
matchLabels:
app: redis
topologyKey: kubernetes.io/hostname

含义:

优先选择已经运行 Redis Pod 的节点,但如果不存在这样的节点,也可以调度到其他合适节点。

10. Pod Anti-Affinity(Pod 反亲和性)#

现在反过来思考:

如果 Web 应用有三个副本,我们不希望它们全部运行在同一个节点。

为什么?

假设:

flowchart TB
    N0["Node-1"]
    N1["Web-1"]
    N2["Web-2"]
    N3["Web-3"]
    N0 --> N1
    N0 --> N2
    N0 --> N3

如果 Node-1 宕机,三个 Web 副本会同时不可用。

生产环境通常希望将副本分散到不同节点,提升可用性。

这就是 Pod Anti-Affinity。

1. 什么是 Pod Anti-Affinity?#

Pod Anti-Affinity(Pod 反亲和性)用于避免符合指定标签条件的 Pod 被调度到相同拓扑范围。

例如:

flowchart TB
    N0["Node-1"]
    N1["Node-2"]
    N2["Node-3"]
    N3["Web-1"]
    N4["Web-2"]
    N5["Web-3"]
    N0 --> N3
    N1 --> N4
    N2 --> N5

2. required Pod Anti-Affinity#

示例:

PRTCL // YAML
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app: web
topologyKey: kubernetes.io/hostname
containers:
- name: nginx
image: nginx:1.27

这里:

PRTCL // YAML
labelSelector:
matchLabels:
app: web

表示选择已经存在的 Web Pod。

PRTCL // YAML
topologyKey: kubernetes.io/hostname

表示同一台 Node 上不能再放置匹配的 Web Pod。

因此三个副本会尽量分布到三个不同节点。

但是注意:

如果集群只有两个符合条件的节点,那么第三个 Pod 就无法调度。

因为这是硬性反亲和性。

3. preferred Pod Anti-Affinity#

如果希望尽量分散,但允许节点不足时共置,可以使用:

PRTCL // YAML
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app: web
topologyKey: kubernetes.io/hostname

这种方式不会因为没有足够节点而直接阻止 Pod 调度。

4. Pod Affinity 与 Anti-Affinity 对比#

类型作用典型场景
Pod Affinity尽量或强制靠近指定 PodWeb 与缓存服务靠近
Pod Anti-Affinity尽量或强制远离指定 PodWeb 副本分散部署

两种调度关系 Pod Affinity

Node-1 Redis Web

Node-2 其他应用

目标:Web 与 Redis 位于相同拓扑范围。

Pod Anti-Affinity

Node-1 Web-1

Node-2 Web-2

Node-3 Web-3

目标:Web 副本分散到不同节点。

11. Pod Topology Spread Constraints(拓扑分布约束)#

前面我们学习了 Pod Anti-Affinity,可以让多个 Pod 尽量分散到不同节点。

但生产环境中还有一个问题:

假设 Kubernetes 集群有三个可用区:

PRTCL // TEXT
Zone-A:Node-1、Node-2
Zone-B:Node-3、Node-4
Zone-C:Node-5、Node-6

现在部署 6 个 Web Pod。

我们希望它们在三个可用区尽可能均匀分布:

PRTCL // TEXT
Zone-A:2 个 Pod
Zone-B:2 个 Pod
Zone-C:2 个 Pod

如果只使用 Pod Anti-Affinity,虽然可以控制 Pod 不在同一个节点,但不一定能够保证三个可用区的副本数量均衡。

这时可以使用 Pod Topology Spread Constraints。

1. 什么是拓扑分布约束?#

它用于控制 Pod 在不同拓扑域之间的分布情况。

常见拓扑域:

  • Node:节点。
  • Zone:可用区。
  • Region:区域。

例如:

PRTCL // YAML
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app: web

重点理解三个字段。

1. maxSkew#

PRTCL // YAML
maxSkew: 1

表示不同拓扑域之间,匹配 Pod 数量的最大允许差值为 1。

例如:

PRTCL // TEXT
Zone-A:2 个
Zone-B:2 个
Zone-C:2 个

满足要求。

如果:

PRTCL // TEXT
Zone-A:3 个
Zone-B:2 个
Zone-C:1 个

最大差值为:

[ 3-1=2 ]

超过 maxSkew=1。

在其他条件满足且使用硬性约束时,新 Pod 不能调度到进一步扩大不均衡的拓扑域。

2. topologyKey#

PRTCL // YAML
topologyKey: topology.kubernetes.io/zone

表示以可用区作为分布单位。

如果改为:

PRTCL // YAML
topologyKey: kubernetes.io/hostname

则按照节点进行分布。

3. whenUnsatisfiable#

有两种主要取值:

值含义
DoNotSchedule无法满足分布约束时,不允许调度
ScheduleAnyway无法满足时,仍然调度,但优先选择更均衡的节点

2. 完整 Deployment 示例#

PRTCL // YAML
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 6
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app: web
containers:
- name: nginx
image: nginx:1.27

这个配置希望 Web Pod 在不同可用区均匀分布。

注意:实际分布还受到节点标签、节点可用性、资源容量、调度条件和拓扑域资格条件影响。拓扑分布约束不是强制每个可用区都必须有 Pod。

3. minDomains#

还可以使用:

PRTCL // YAML
minDomains: 3

表示计算拓扑分布时,期望至少存在 3 个符合条件的拓扑域。

如果符合条件的拓扑域数量少于 minDomains,计算全局最小值时会按 0 处理。

它适合对可用区数量有明确要求的高可用部署。

4. Pod Anti-Affinity 与 Topology Spread 对比#

对比Pod Anti-AffinityTopology Spread
主要目标避免共置控制数量均衡
节点分散支持支持
可用区均衡可以实现部分约束更适合
数量差控制不直接提供maxSkew
硬性约束requiredDoNotSchedule
软性约束preferredScheduleAnyway

生产建议:如果你的目标是让应用副本均匀分布到不同节点和可用区,优先考虑 Topology Spread Constraints。

12. nodeName:直接指定节点#

前面我们学习的 NodeSelector、Node Affinity 都是通过 Scheduler 进行节点选择。

但 Kubernetes 还提供了一种直接指定节点的方式:

PRTCL // YAML
nodeName: worker-1

例如:

PRTCL // YAML
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
nodeName: worker-1
containers:
- name: nginx
image: nginx:1.27

含义:

直接将 Pod 指定到 worker-1。

与 NodeSelector 的区别:

对比nodeNamenodeSelector
指定方式直接指定节点名称根据标签选择
是否经过 Scheduler 选节点不经过经过
是否检查节点资源不经过调度器筛选Scheduler 检查
是否灵活较低较高

注意:

nodeName 会绕过正常的 Scheduler 节点选择过程,并不代表 Pod 一定能正常运行。如果节点不存在或资源不足,Pod 可能无法启动。

生产环境通常优先使用 Node Affinity 或 NodeSelector,而不是直接指定 nodeName。

13. Taints 与 Tolerations:节点排斥机制#

有时你不是希望某个 Pod 选择某台 Node,而是希望某台 Node 默认不接收普通 Pod。

这就是 Taints(污点)和 Tolerations(容忍)。

例如,GPU 节点只希望运行 GPU 任务:

PRTCL // BASH
Terminal window
kubectl taint nodes gpu-1 dedicated=gpu:NoSchedule

此时,没有匹配容忍条件的普通 Pod 不会被调度到该节点。

GPU Pod 可以这样配置:

PRTCL // YAML
apiVersion: v1
kind: Pod
metadata:
name: gpu-job
spec:
tolerations:
- key: dedicated
operator: Equal
value: gpu
effect: NoSchedule
containers:
- name: job
image: busybox:1.36
command: ["sh", "-c", "sleep 3600"]

但这里有一个重要区别:

Toleration 只表示可以容忍污点,不代表 Pod 一定会被调度到这台节点。

如果还希望 Pod 只能运行在 GPU 节点上,需要配合 nodeSelector 或 Node Affinity。

三种常见污点效果:

Effect含义
NoSchedule不调度不容忍该污点的新 Pod
PreferNoSchedule尽量避免调度不容忍该污点的 Pod
NoExecute不仅限制新调度,还可能驱逐已运行且不容忍该污点的 Pod

删除污点:

PRTCL // BASH
Terminal window
kubectl taint nodes gpu-1 dedicated=gpu:NoSchedule-

14. PriorityClass 与抢占机制#

假设集群资源不足,有两个 Pod 等待调度:

  • 普通业务 Pod:优先级 100。
  • 关键业务 Pod:优先级 100000。

你可以使用 PriorityClass 定义优先级:

PRTCL // YAML
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: high-priority
value: 100000
globalDefault: false
description: "关键业务工作负载"

然后在 Pod 模板中指定:

PRTCL // YAML
spec:
priorityClassName: high-priority

当高优先级 Pod 无法调度时,调度器可能尝试通过 Preemption(抢占) 驱逐低优先级 Pod,为其腾出资源。

但高优先级不意味着一定能运行。如果节点存在无法满足的硬性约束、污点不兼容或其他不可通过抢占解决的限制,调度仍可能失败。

15. 如何排查 Pod 一直 Pending?#

这是生产环境中很常见的问题。

先执行:

PRTCL // BASH
Terminal window
kubectl get pods -A -o wide
kubectl describe pod <pod-name>
kubectl get nodes
kubectl describe nodes

重点看 Pod 的 Events。

常见事件提示可能原因
Insufficient cpu可分配 CPU 不足
Insufficient memory可分配内存不足
node(s) didn't match Pod's node affinity/selector节点标签或亲和性不匹配
node(s) had untolerated taintPod 无法容忍节点污点
pod has unbound immediate PersistentVolumeClaimsPVC 尚未绑定,阻碍调度

建议按以下顺序排查:

  1. 检查节点是否处于 Ready。
  2. 检查 Pod 的 CPU、内存 requests。
  3. 检查 nodeSelector 和 Node Affinity。
  4. 检查节点 Taints 与 Pod Tolerations。
  5. 检查 PVC 是否满足绑定条件。
  6. 查看调度事件,确认真正阻止调度的原因。

16. 调度机制综合对比#

现在把本节学习的所有调度机制整理起来。

调度机制主要作用约束对象
nodeSelector根据节点标签选择Node
Node Affinity灵活选择节点Node
Pod Affinity靠近指定 PodPod
Pod Anti-Affinity远离指定 PodPod
Topology Spread控制跨拓扑域分布Pod
Taints限制节点接收 PodNode
Tolerations容忍节点污点Pod
nodeName直接指定节点Node

整个调度过程可以理解为:

flowchart TB
    N0["创建 Pod"]
    N1["Scheduler 调度"]
    N2["节点资源与调度条件检查"]
    N3["Node Affinity"]
    N4["Taints/Tolerations"]
    N5["Pod Affinity 检查"]
    N6["Topology Spread 检查"]
    N7["Filter 过滤"]
    N8["Score 评分"]
    N9["Bind 节点绑定"]
    N10["kubelet 启动 Pod"]
    N0 --> N1
    N1 --> N2
    N2 --> N3
    N2 --> N4
    N3 --> N5
    N4 --> N5
    N5 --> N6
    N6 --> N7
    N7 --> N8
    N8 --> N9
    N9 --> N10

这张图是学习上的逻辑归纳,实际 Scheduler 的插件执行顺序由调度框架和插件配置决定。

17. CKA 必须掌握的调度命令#

操作命令
查看节点标签kubectl get nodes --show-labels
添加节点标签kubectl label node worker-1 disktype=ssd
修改节点标签kubectl label node worker-1 disktype=nvme --overwrite
删除节点标签kubectl label node worker-1 disktype-
查看节点污点kubectl describe node worker-1
添加节点污点kubectl taint node worker-1 dedicated=db:NoSchedule
删除节点污点kubectl taint node worker-1 dedicated=db:NoSchedule-
查看 Pod 调度节点kubectl get pods -o wide
查看调度失败原因kubectl describe pod nginx
查看 Pod YAMLkubectl get pod nginx -o yaml
归档于 2026.07.26
// 档案结束
Classified
章节_06
协议编号: CC-BY-NC-SA-4.0

Pod 调度机制

作者:Chavy发布日期:2026.07.26

基于 CC BY-NC-SA 4.0

© 2026 Chavy
Powered by Astro