文章目录
- 前言
- 理论部分
-
- 1_调度基础
-
- 1.1_K8S组件协作机制
-
- ①_组件职责
- [②_List-Watch 机制](#②_List-Watch 机制)
- 1.2_Pod创建与工作机制流程
- 1.3_Scheduler调度器
- 1.4_调度流程
- 2_调度策略
- 3_运维操作
- 实验部分
-
- [1_nodeName 强制绑定](#1_nodeName 强制绑定)
-
- [1.1_创建强制绑定 Deployment](#1.1_创建强制绑定 Deployment)
- 1.2_验证调度结果
- [2_nodeSelector 标签匹配](#2_nodeSelector 标签匹配)
- 3_节点亲和性实验
- [4_Pod 亲和性实验](#4_Pod 亲和性实验)
- 5_污点与容忍实验
-
- 5.1_设置节点污点
- [5.2_配置 Pod 容忍](#5.2_配置 Pod 容忍)
- 5.3_节点维护操作
- 结语
前言
Kubernetes集群调度是确保工作负载高效运行的核心机制,通过组件协作、调度策略和控制机制实现资源优化分配。本文聚焦调度流程与策略,涵盖组件协作原理、调度过程、节点绑定方式、亲和性规则、污点容忍机制等关键内容。
- list-watch组件 controller-manager scheduler kubelet
- list-watch 工作机制
- 亲和性(节点亲和pod亲和)和反亲和性 以及硬策略和软策略
- 污点和容忍
- 驱逐
理论部分
1_调度基础
1.1_K8S组件协作机制
- Kubernetes 通过 List-Watch 机制使各个组件协作、数据同步,从而实现解耦与实时一致性。
- 适用于需要分布式系统实时数据同步的集群管理场景。

①_组件职责
Kubernetes 核心组件职能(关键组件定义):
- kubectl:API客户端,向 APIServer 发起资源创建或管理请求
- APIServer:负责API调用、权限校验、存储交互,是集群控制的核心入口(监听 HTTPS 6443 端口)
- etcd:存储集群所有状态信息
- Controller Manager:维持副本数、执行自愈逻辑(扩容、重建等)
- Scheduler:调度器,将未分配节点的 Pod 分配到合适的 Node
- kubelet:节点代理,负责 Pod 生命周期管理和容器运行状态上报
②_List-Watch 机制
List-Watch 协作模型:
- Controller Manager、Scheduler 和 kubelet 启动后分别通过 Watch API Server 监听集群资源事件变化
- 事件类型包括:Create(创建)、Update(更新)、Delete(删除)
- 通过 API Server 中转,实现组件间数据解耦与同步
1.2_Pod创建与工作机制流程
- Pod 创建是通过多组件协同完成资源分配与容器启动的分布式工作流。
- 适用于需要自动化容器编排的云原生应用部署场景。
Pod典型13步创建流程:
- 三大组件启动监听:Controller Manager、Scheduler、kubelet 通过 Watch API Server (6443 端口) 监听事件
- 用户创建 Pod 对象 :kubectl 发送创建请求,例如:
kubectl apply -f pod.yaml - API Server 写入 etcd:校验后将 Pod 元数据存入 etcd
- etcd 通知事件:触发 Create 事件发送给 API Server
- Controller Manager 监听:接收 Pod 创建事件
- ReplicaSet 保证副本数:创建所需 Pod 副本
- API Server 更新 etcd:写入 Pod 详细信息
- etcd 触发更新事件:再次发送更新事件
- Scheduler 监听待调度 Pod:发现 Pending 状态 Pod
- Scheduler 更新调度结果:写入 Node 绑定信息到 API Server
- etcd 确认更新:同步 Pod 最新状态
- kubelet 拉取运行容器:调用容器运行时启动容器
- API Server 更新状态:etcd 确认后 Pod 进入 Running 状态
流程可视化:
用户创建 Pod
kubectl 发送请求
APIServer 校验&写入 etcd
etcd 发出 Create 事件
Controller Manager 监听
ReplicaSet 创建 Pod 副本
API Server 更新 etcd
etcd 发出 Update 事件
Scheduler 监听 Pending Pod
Scheduler 选择 Node
API Server 更新 Pod 绑定
kubelet 监听本节点 Pod
拉取镜像/启动容器
上报 Pod 状态
APIServer 更新 etcd
Pod 进入 Running
1.3_Scheduler调度器
Scheduler 是负责将未绑定 Node 的 Pod (spec.nodeName == "")分配到合适节点的核心组件。
调度核心目标
- 公平性:节点间资源分配均衡
- 高效性:最大化集群资源利用率
- 效率:快速完成大批量 Pod 调度
- 灵活性:支持自定义调度策略
1.4_调度流程
调度是分阶段筛选和排序节点的自动化决策过程。
①_过滤阶段(Predicate)
- 通过预设条件过滤无效节点,剩余节点进入优选阶段
- 若无节点满足条件,Pod 持续处于 Pending 状态并重试调度
预算策略(Predicate)过滤算法 :
过滤掉不满足条件的节点
| 算法名称 | 功能描述 |
|---|---|
| PodFitsResources | 检查节点剩余资源是否满足 Pod 需求 |
| PodFitsHost | 检查 NodeName 是否匹配 |
| PodFitsHostPorts | 检查端口冲突 |
| PodSelectorMatches | label 匹配 |
| NoDiskConflict | Volume 挂载冲突检测 |
②_优选阶段(Priorities)
- 对可行节点按权重评分排序
- 选择分数最高节点执行调度
- 最终输出调度决策结果
优选策略(Priorities)评分算法 :
对可行节点进行打分排序
| 优先级项 | 描述 |
|---|---|
| LeastRequestedPriority | 资源使用率越低,权重越高 |
| BalancedResourceAllocation | CPU 与内存使用率越接近越好 |
| ImageLocalityPriority | 优先节点上已有目标镜像的节点 |
2_调度策略
2.1_指定调度节点方式
- 通过直接绑定或标签匹配实现 Pod 与 Node 的关联。
- 适用于需要精确控制 Pod 位置的特殊部署场景。
①_nodeName(强制绑定)
- pod.spec.nodeName 将 Pod 直接调度到指定的 Node 节点上;
- 会跳过 Scheduler 的调度策略;
- 该匹配规则是强制匹配。
②_nodeSelector(基于标签匹配)
- pod.spec.nodeSelector:通过 kubernetes 的 label-selector 机制选择节点;
- 由调度器调度策略匹配 label,然后调度 Pod 到目标节点;
- 该匹配规则属于强制约束。
2.2_Node与Pod的亲和性
- 使用规则定义 Pod 与节点/Pod 之间的吸引关系。
- 适用于需要控制 Pod 分布策略的高级拓扑场景。
①_节点亲和性(NodeAffinity)
关键特性:
- 操作符:In、NotIn、Exists、DoesNotExist、Gt、Lt
- 硬策略 (
requiredDuringSchedulingIgnoredDuringExecution):必须满足 - 软策略 (
preferredDuringSchedulingIgnoredDuringExecution):尽量满足但非强制
运算符逻辑:
| 运算符 | 含义 | 通俗理解 | 示例 |
|---|---|---|---|
| In | label 的值在列表中 | "只要值在名单里就选上" | env In (dev, test) |
| NotIn | label 的值不在列表中 | "黑名单里的不要" | env NotIn (prod) |
| Gt | label 的值大于某数 | "比数字大的才要" | version Gt 3 |
| Lt | label 的值小于某数 | "比数字小的才要" | version Lt 3 |
| Exists | label 存在即可 | "有标签就算数" | Exists zone |
| DoesNotExist | label 不存在 | "无标签才要" | DoesNotExist debug |
②_Pod亲和性与反亲和性
调度策略对比:
| 调度策略 | 匹配目标 | 操作符 | 拓扑域支持 | 调度目标 |
|---|---|---|---|---|
| nodeAffinity | 主机 | In, NotIn, Exists等 | ❌ | 指定主机 |
| podAffinity | Pod | In, NotIn, Exists等 | ✅ | 与指定 Pod 同域 |
| podAntiAffinity | Pod | In, NotIn, Exists等 | ✅ | 与指定 Pod 不同域 |
拓扑域说明:
- 由
topologyKey定义,相同键值标签的节点属于同一拓扑域(如yjs=a表示相同拓扑域)
2.3_污点和容忍
Taint and Tolerations
- 污点使节点排斥特定 Pod,容忍使 Pod 能接受带污点的节点。
- 适用于需要隔离节点资源的特殊环境管理场景。
①_污点(Taint)
污点机制:
-
格式:
key=value:effect -
effect 类型 :
NoSchedule:不调度到此节点PreferNoSchedule:尽量避免调度到该节点NoExecute:不调度 + 驱逐已存在 Pod
-
污点命令:
shellkubectl taint node node01 key1=value1:NoSchedule # 设置污点 kubectl taint node node01 key1:NoSchedule- # 清除污点
②_容忍(Tolerations)
容忍规则:
-
关键字段需与节点污点完全匹配(key, value, effect)
-
operator: "Exists"表示只要存在 key 即可容忍(忽略 value) -
tolerationSeconds定义驱逐前保留时间 -
全容忍配置:
yamltolerations: - operator: "Exists" # 容忍所有污点 key
3_运维操作
3.1_节点维护操作
cordon/drain/uncordon
- 通过指令管理节点调度状态与 Pod 迁移。
- 适用于节点维护或升级时的流量调度场景。
关键命令:
| 命令 | 功能 |
|---|---|
kubectl cordon <node> |
标记为不可调度 |
kubectl drain <node> --ignore-daemonsets --delete-local-data --force |
驱逐 Pod(drain = cordon + 驱逐) |
kubectl uncordon <node> |
恢复可调度状态 |
3.2_Pod生命周期
Phase
- Phase 反映 Pod 运行阶段的状态特征。
- 适用于诊断 Pod 异常状态的场景。
阶段状态说明:
| Phase | 描述 |
|---|---|
| Pending | 已创建但未调度/拉取镜像中 |
| Running | 容器已启动运行中 |
| Succeeded | 所有容器成功终止(Job 类) |
| Failed | 容器失败退出(非0状态) |
| Unknown | 无法获取状态(通信异常) |
3.3_故障排查命令
- 通过系统命令诊断调度问题。
- 适用于实时排查 Pod 调度失败的场景。
排错工具集:
| 操作 | 命令 |
|---|---|
| 查看事件 | kubectl describe pod <POD> |
| 查看日志 | kubectl logs <POD> [-c 容器名] |
| 进入容器 | kubectl exec -it <POD> bash |
| 查看集群状态 | kubectl cluster-info |
| 查看节点状态 | kubectl get nodes |
| 查看 kubelet 日志 | journalctl -xefu kubelet |
3.4_总结图
核心调度策略层次:
kubectl → APIServer → etcd
↓ ↑
Controller Manager ←→ Scheduler ←→ kubelet(Node)
策略演进路径:
- nodeName(直接绑定)
- nodeSelector(Label 匹配)
- nodeAffinity / podAffinity(亲和性调度)
- Taint & Toleration(污点/容忍机制)
- cordon & drain(节点维护与Pod迁移)
核心口诀 :
"调度是吸引,污点是排斥,亲和性是偏好,容忍是例外。"
实验部分
1_nodeName 强制绑定
1.1_创建强制绑定 Deployment
- 通过 nodeName 跳过 Scheduler 直接指定节点
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
nodeName: node01 # 强制绑定到 node01
containers:
- name: myapp
image: soscscs/myapp:v1
ports:
- containerPort: 80
nodeName: node01:强制将 Pod 调度到 node01 节点,直接跳过 Scheduler操作验证:执行
kubectl apply -f myapp.yaml后,所有 Pod 均在 node01 启动
1.2_验证调度结果
- 检查 Pod 分布和调度事件
shell
kubectl get pods -o wide
输出表明所有 Pod 均分配到
NODE: node01事件验证:
kubectl describe pod myapp-6bc58d7775-6wlpp显示 "Normal Scheduled" 事件缺失,证明未经过 Scheduler
2_nodeSelector 标签匹配
2.1_设置节点标签
- 为节点添加自定义标签
shell
kubectl label nodes node01 yjs=a
kubectl label nodes node02 yjs=b
kubectl label:标签管理命令,为 node01 设置yjs=a、node02 设置yjs=b验证命令:
kubectl get nodes --show-labels查看标签状态
2.2_应用标签选择部署
- 创建 nodeSelector 配置的 Deployment
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp1
spec:
replicas: 3
selector:
matchLabels:
app: myapp1
template:
metadata:
labels:
app: myapp1
spec:
nodeSelector: # 通过标签匹配节点
yjs: a # 要求节点标签 yjs=a
containers:
- name: myapp1
image: soscscs/myapp:v1
ports:
- containerPort: 80
nodeSelector:启用标签选择器调度,要求节点必须存在yjs=a标签调度引擎:Scheduler 通过标签匹配将 Pod 分配到 node01
2.3_验证调度过程
- 检查 Pod 分布及调度日志
shell
kubectl get pods -o wide
所有 Pod 分配到
NODE: node01事件验证:
kubectl describe pod myapp1-58cff4d75-52xm5显示 "Normal Scheduled" 事件,证明经过 Scheduler
3_节点亲和性实验
3.1_硬策略实验
- 创建硬策略亲和性 Pod 配置
yaml
apiVersion: v1
kind: Pod
metadata:
name: affinity
labels:
app: node-affinity-pod
spec:
containers:
- name: with-node-affinity
image: soscscs/myapp:v1
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution: # 硬策略定义
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: NotIn
values:
- node02 # 排除 node02
required...:硬策略生效条件
NotIn:Pod 不会被调度到kubernetes.io/hostname=node02的节点执行验证:Pod 被分配到
node01,如替换values为当前所有节点将导致 Pending 状态
3.2_软策略实验
- 设置软策略优先级调度
yaml
apiVersion: v1
kind: Pod
metadata:
name: affinity
labels:
app: node-affinity-pod
spec:
containers:
- name: with-node-affinity
image: soscscs/myapp:v1
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution: # 软策略定义
- weight: 1 # 权重值
preference:
matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- node01 # 优先 node01
preferred...:软策略仅影响调度优先级
weight:1:权重值越高优先级越高(最大值100)调度结果:若 node01 可用则 Pod 分配到 node01,否则分配到其他节点
3.3_软硬策略组合
- 混合策略配置示例
yaml
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution: # 先满足硬策略
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: NotIn
values:
- node02 # 排除 node02
preferredDuringSchedulingIgnoredDuringExecution: # 再满足软策略
- weight: 1
preference:
matchExpressions:
- key: yjs
operator: In
values:
- a # 优先选择 yjs=a 节点
策略优先级:硬策略 > 软策略
执行效果:先排除 node02,再优先选择 yjs=a 的节点
4_Pod 亲和性实验
4.1_亲和性调度
- 要求 Pod 与指定 Pod 部署在同一拓扑域
yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp02
labels:
app: myapp02
spec:
containers:
- name: myapp02
image: soscscs/myapp:v1
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution: # 硬策略
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- myapp01 # 必须与 app=myapp01 的 Pod 同域
topologyKey: yjs # 拓扑域标识
topologyKey: yjs:当节点 yjs 标签值相同时视为同一拓扑域验证前提:需先存在
app=myapp01的 Pod(如 node01 和 node02 都有 yjs=a 时,Pod 会调度到同一节点)
4.2_反亲和性调度
- 防止 Pod 与指定 Pod 部署在同一拓扑域
yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp20
labels:
app: myapp20
spec:
containers:
- name: myapp20
image: soscscs/myapp:v1
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- myapp01 # 排斥与 app=myapp01 的 Pod 同域
topologyKey: yjs
执行结果:当 node01 和 node02 的 yjs=a 时,Pod 无法调度(Pending);若将 node02 改为 yjs=b 则调度成功
5_污点与容忍实验
5.1_设置节点污点
- 在 node02 上创建驱逐型污点
shell
kubectl taint node node02 check=mycheck:NoExecute
NoExecute:新调度拒绝 + 驱逐现有 Pod效果:
kubectl get pods -o wide显示 node02 的 Pod 被全部驱逐
5.2_配置 Pod 容忍
- 添加匹配污点的容忍配置
yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp01
labels:
app: myapp01
spec:
containers:
- name: with-node-affinity
image: soscscs/myapp:v1
tolerations:
- key: "check"
operator: "Equal"
value: "mycheck"
effect: "NoExecute"
tolerationSeconds: 3600 # 驱逐前保留 1 小时
operator: "Equal":必须 key/value/effect 完全匹配
tolerationSeconds:定义驱逐前的等待时间验证:Pod 成功调度到被标记污点的 node01 上
5.3_节点维护操作
- 模拟节点维护流程
shell
kubectl cordon node01 # 标记为不可调度
kubectl drain node01 --ignore-daemonsets --delete-local-data --force # 驱逐 Pod
kubectl uncordon node01 # 恢复调度
drain命令等同于 "cordon + 驱逐" 操作关键选项:
--ignore-daemonsets(忽略 DaemonSet)、--force(强制执行)
结语
Kubernetes 调度核心要点:调度是吸引(亲和性)、污点是排斥、容忍是例外、节点维护保障业务连续性。硬策略确保调度刚性规则,软策略实现弹性负载分配,污点机制隔离特殊节点,List-Watch 机制维持集群状态一致性。
!question\] 请说明 Scheduler 的过滤阶段与优选阶段的区别 过滤阶段(Predicate)通过预定义条件筛选可行节点;优选阶段(Priorities)对可行节点评分排序,选出最优节点 \[!question\] 污点 effect 的 NoSchedule 与 NoExecute 有何本质差异 NoSchedule 仅阻止新调度不驱逐现有 Pod;NoExecute 既阻止新调度也强制驱逐现有 Pod \[!question\] 节点亲和性中 hard strategy 与 soft strategy 的应用场景如何选择 硬策略用于必须满足的约束场景(如安全合规);软策略用于优化资源分配但非强制的场景(如负载均衡) \[!question\] 为什么 kubelet 需要持续监听 Pod 事件而非仅完成初始化调度 为响应动态变化:副本数调整、镜像更新、节点故障等,确保集群始终处于期望状态