Kubernetes(七)——Kubernetes 集群调度
文章目录
前言
本文聚焦 Kubernetes 核心运行机制,详解组件协作、Pod 创建流程、调度器工作逻辑及亲和性调度策略,夯实 K8s 运维与部署基础。
一、Kubernetes 组件协作机制
1、kubernetes组件
Kubernetes 通过 List-Watch 机制使各个组件协作、数据同步,从而实现解耦与实时一致性。
组件列表如下:
kubectl / API 客户端:向 APIServer 发起资源创建或管理请求
APIServer:负责 API 调用、权限校验、存储交互,是集群控制的核心入口
etcd:存储集群所有状态信息
Controller Manager:维持副本数、执行自愈逻辑(扩容、重建等)
Scheduler:调度器,将未分配节点的 Pod 分配到合适的 Node
kubelet:节点代理,负责 Pod 生命周期管理和容器运行状态上报
2、组件协助流程概述
用户是通过 kubectl 根据配置文件,向 APIServer 发送命令,在 Node 节点上面建立 Pod 和 Container。 APIServer 经过 API 调用,权限控制,调用资源和存储资源的过程,实际上还没有真正开始部署应用。这里 需要 Controller Manager、Scheduler 和 kubelet 的协助才能完成整个部署过程。
在 Kubernetes 中,所有部署的信息都会写到 etcd 中保存。实际上 etcd 在存储部署信息的时候,会发送 Create 事件给 APIServer,而 APIServer 会通过监听(Watch)etcd 发过来的事件。其他组件也会监听(Watch)APIServer 发出来的事件。
二、Pod创建和工作流程机制
Pod 创建的整个生命周期由多组件配合完成
典型创建过程(List-Watch 模型)
1) 三大组件启动监听(List-Watch)
Controller Manager、Scheduler、kubelet 启动后会分别通过 Watch API Server(HTTPS 6443 端口)监听集群资源事件变化。
Controller Manager:监听副本控制类对象(如 ReplicaSet、Deployment)
Scheduler:监听未调度的 Pod
kubelet:监听分配到本节点的 Pod
2)用户创建 Pod 对象
用户通过 kubectl 或其他 API 客户端发送创建 Pod 的请求给 API Server。
kubectl apply -f pod.yaml
3)API Server 将 Pod 信息写入 etcd、
- API Server 校验请求后,将 Pod 的元数据存入 etcd。
- 写入成功后返回确认给客户端。
4)etcd 通知事件(Create)
- etcd 接受到 Pod 信息后,触发 Create 事件。
- 该事件被发送给 API Server。
5)Controller Manager 监听到 Pod 创建事件
Controller Manager 通过 Watch 机制收到 API Server 发出的 Pod 创建事件。
6)Replication Controller(RC)/ ReplicaSet 保证副本数
- Controller Manager 在接到 Create 事件以后,如果发现副本数量不足,则由 RC/ReplicaSet 创建所需副本。
- 扩容、缩容操作也都由此机制控制。
7)API Server 更新 etcd(记录详细信息)
- Controller Manager 创建完 Pod 副本后,API Server 会将 Pod 的详细信息更新写入 etcd。包括副本数量、副本模板、容器规格等
8)etcd 触发 Pod 信息更新事件
etcd 再次发送更新事件给 API Server。
9)Scheduler 监听到待调度的 Pod
- Scheduler Watch 到新创建的 Pod 处于 “Pending” 状态(尚未分配节点)。
- 通过调度算法(资源、亲和性、污点等)为其选择一个合适的 Node。
10)Scheduler 更新调度结果
- Scheduler 将选定的 Node 信息写回到 API Server。
- API Server 更新 etcd 中该 Pod 的 Node 绑定信息。
11)etcd 确认更新 & API Server 同步结果
- etcd 更新成功后向 API Server 返回确认。
- API Server 同步 Pod 的最新状态(包括 Node 绑定结果)。
12)kubelet 在 Node 上拉取并运行容器
- kubelet 监听到分配给自己的新 Pod。
- 调用容器运行时(Docker/containerd):
- 拉取镜像
- 创建容器
- 启动容器
启动成功后将 Pod 状态(Running、Failed 等)上报给 API Server。
13)API Server 更新 Pod 状态
- API Server 将 kubelet 上报的状态写入 etcd。
- etcd 确认写入成功后,集群状态完成同步,Pod 正式进入 Running 状态
三、Scheduler过程(调度器)
1、核心任务
将 未绑定 Node 的 Pod( spec.nodeName == “” ) 分配到合适的节点。
2、调度目标
公平性:节点间资源分配均衡
高效性:集群所有资源最大化被使用
效率:调度的性能要好,能够尽快地对大批量的 pod 完成调度工作
灵活性:允许自定义策略(调度策略、插件)
3、调度流程概述
Sheduler 是作为单独的程序运行的,启动之后会一直监听 APIServer,获取 spec.nodeName 为空的pod,对每个 pod 都会创建一个 binding,表明该 pod 应该放到哪个节点上。
调度分为几个部分:首先是过滤掉不满足条件的节点,这个过程称为预算策略(predicate);然后对通过的节点按照优先级排序,这个是优选策略(priorities);最后从中选择优先级最高的节点。如果中间任何一步骤有错误,就直接返回错误。
四、调度详细流程
1、过滤阶段(Predicate)
常见过率算法
PodFitsResources:检查节点剩余资源是否满足 Pod 需求
PodFitsHost:检查 NodeName 是否匹配
PodFitsHostPorts:检查端口冲突
PodSelectorMatches :label 匹配
NoDiskConflict:Volume 挂载冲突检测
2、优选阶段(Priorities)
常见算法
LeastRequestedPriority:资源使用率越低,权重越高
BalancedResourceAllocation:
CPU 与内存使用率越接近越好(这个一般和上面的一起使用,不单独使用。比如 node01 的 CPU 和 Memory 使用率20:60,node02 的 CPU 和 Memory 使用率 50:50,虽然node01 的总使用率比 node02 低,但 node02 的 CPU 和Memory 使用率更接近,从而调度时会优选 node02。)
ImageLocalityPriority:优先节点上已有目标镜像的节点
五、指定调度方式
1、强制绑定(nodeName)
pod.spec.nodeName 将 Pod 直接调度到指定的 Node 节点上,会跳过 Scheduler 的调度策略,该匹配规则是强制匹配
以nginx为例:写入pod.spec.nodeName:node01,则Pod都在node01上创建
# nginx-stack.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
namespace: default
spec:
replicas: 3 # 初始Pod数量
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
nodeName: node01
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
resources:
# 关键点2: 必须设置资源请求,这是HPA计算利用率的基础
requests:
cpu: "200m" # 请求0.2个CPU核心
limits:
cpu: "500m" # 限制最多使用0.5个CPU核心
结果如图所示:
kubectl apply -f test3.yaml
kubectl get pod -o wide

查看事件描述,发现未经过Scheduler调度,由kubelet直接启动
kubectl describe pod nginx-deployment-696d847d6c-7742c
2、基于标签匹配(nodeSelector)
pod.spec.nodeSelector:通过 kubernetes 的 label-selector 机制选择节点,由调度器调度策略匹配 label,然后调度 Pod 到目标节点,该匹配规则属于强制约束
# 设置k8s的node节点标签
# 获取标签使用帮助
kubectl label --help
# 获取node名称
kubectl get node
# 设置标签
kubectl label nodes node01 yjs=a
kubectl label nodes node02 yjs=b
# 查看标签
kubectl get nodes --show-labels

还是使用上述的nginx模板,增添属性pod.spec.nodeSelector:yjs=b
# nginx-stack.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
namespace: default
spec:
replicas: 3 # 初始Pod数量
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
nodeSelector:
yjs: b
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
resources:
# 关键点2: 必须设置资源请求,这是HPA计算利用率的基础
requests:
cpu: "200m" # 请求0.2个CPU核心
limits:
cpu: "500m" # 限制最多使用0.5个CPU核心
验证结果Pod是否创建在node02上
kubectl get pod -o wide
查看pod详细信息发现经过了调度
kubectl describe pod nginx-deployment-89c698d86-fdskb
3、管理Node标签命令
# 设置标签
kubectl label nodes node01 yjs=a
# 指定标签查询
Kubectl get node -l yjs=a
# 修改label
kubectl label nodes node02 yjs=b overwrite
# 删除label
kubectl label nodes node02 yjs-
六、节点亲和性和Pod亲和性
1、节点亲和性
1.1、节点亲和性介绍和标签运算关系
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution: # 硬策略
preferredDuringSchedulingIgnoredDuringExecution: # 软策略
操作符支持
In 、 NotIn 、 Exists 、 DoesNotExist 、 Gt 、 Lt
Kubernetes 中 label selector 的键值运算关系 ,在 Kubernetes 中,很多资源(比如 Pod、Deployment、Service)都会用 label selector(标签选择器) 来筛选对象。 运算符决定“选谁”或“不选谁”。
1.2、案例-硬策略
设置硬策略,结合NotIn,使得kubelet创建Pod时只创建在标签为yjs,标签值不为a的节点上,本文只有两个节点,最终显示结果为只在node02上创建
# 查看节点标签和标签值,已设置好node01 yjs=a 和 node02 yjs=b
kubectl get nodes --show-labels
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
namespace: default
spec:
replicas: 3 # 初始Pod数量
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
# 亲和性配置的根节点,用于定义Pod与节点/其他Pod的亲和/反亲和规则
affinity:
# 节点亲和性,控制Pod调度到哪些节点上(区别于podAffinity:Pod间亲和性)
nodeAffinity:
# requiredDuringSchedulingIgnoredDuringExecution:核心规则类型,分为两部分理解:
# 1. requiredDuringScheduling:调度阶段必须满足该规则,不满足则Pod无法调度(强制约束)
# 2. IgnoredDuringExecution:Pod调度成功后,如果节点标签发生变化(比如node02的hostname标签被修改),不会驱逐已运行的Pod
requiredDuringSchedulingIgnoredDuringExecution:
# 节点选择器规则列表(可以配置多个,满足任意一个即可)
nodeSelectorTerms:
# 基于表达式的节点匹配规则(另一种是matchFields,基于节点字段)
- matchExpressions:
# 要匹配的节点标签的「键」
- key: yjs #指定node的标签
# operator:匹配运算符,NotIn 表示「标签值不在指定的values列表中」
operator: NotIn #设置Pod安装到kubernetes.io/hostname的标签值不在values列
values:
- a
kubectl apply -f test3.yaml
kubectl get pod -o wide
验证结果如下:
1.3、案例-软策略
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
namespace: default
spec:
replicas: 3 # 初始Pod数量
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
affinity:
nodeAffinity:
# 软策略:可以配置多个偏好规则,每个规则有独立权重
preferredDuringSchedulingIgnoredDuringExecution:
# 规则1:优先调度到node03(权重80,优先级最高)
- weight: 80
preference:
matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- node02
# 规则2:其次调度到node01(权重50,优先级次之)
- weight: 50
preference:
matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- node01
因为node02权重大,所以会优先在node02上创建
1.4、案例-硬软策略优先级
如果把硬策略和软策略合在一起使用,则要先满足硬策略前提下才会满足软策略
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
namespace: default
spec:
replicas: 3 # 初始Pod数量
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
affinity:
nodeAffinity:
# 软策略:可以配置多个偏好规则,每个规则有独立权重
preferredDuringSchedulingIgnoredDuringExecution:
# 规则1:优先调度到node03(权重80,优先级最高)
- weight: 80
preference:
matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- node02
# 规则2:其次调度到node01(权重50,优先级次之)
- weight: 50
preference:
matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- node01
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: NotIn
values:
- node02
受硬策略影响,选择了软策略中权重小的
2、Pod亲和性与反亲和性
2.1、什么是Pod亲和性
Pod 亲和性(podAffinity) 是 Kubernetes 中一种基于已有 Pod 标签的调度规则,用于控制新 Pod的调度位置 —— 让新 Pod 和某些已运行的 Pod「靠近」或「远离」,核心作用是优化 Pod 间的网络延迟、实现服务聚合 / 隔离。
Pod亲和性和节点亲和性(nodeAffinity) 的核心区别是:
- 节点亲和性:依据节点的标签调度 Pod(Pod → 节点标签)
- Pod 亲和性:依据目标节点上已运行 Pod 的标签调度 Pod(Pod → 已运行 Pod 的标签 → 节点)
2.2、调度策略

2.3、Pod亲和性调度案例
kubectl label nodes node01 yjs=a pod1
kubectl label nodes node02 yjs=b pod2
# 先在节点node02上创建一个运行的Pod
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment2
namespace: default
spec:
replicas: 1 # 初始Pod数量
selector:
matchLabels:
app: myapp01
template:
metadata:
labels:
app: myapp01
spec:
nodeName: node02
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80

创建亲和性Pod
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment3
namespace: default
spec:
replicas: 3 # 初始Pod数量
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
affinity:
# Pod亲和性(区别于nodeAffinity节点亲和性)
podAffinity:
# 硬约束规则:调度时必须满足,运行后忽略节点变化
requiredDuringSchedulingIgnoredDuringExecution:
# 目标Pod的标签选择器(要匹配的已有Pod标签)
- labelSelector:
matchExpressions:
- key: app
operator: In
# 匹配标签值为myapp01的Pod
values:
- myapp01
# 拓扑维度:按节点的yjs标签维度判断“同一位置”
topologyKey: yjs
结果示例:都创建在node02上,因为myapp01标签运行中的pod在node02上
2.4、Pod反亲和性调度案例
调度这个 myapp10 Pod 时,优先避免 将它调度到「运行着带有 app=myapp01 标签的 Pod」的同一节点上
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment4
namespace: default
spec:
replicas: 3 # 初始Pod数量
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
affinity:
podAntiAffinity: # 反亲和性规则
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- myapp01
topologyKey: yjs
Pod反亲和性结果,新的Pod都不在标签为app, 标签值为myapp01, 维度为yjs=b的节点上。
七、污点(Taint) 和 容忍(Tolerations)
1、污点(Taint)
1.1、污点概述
节点亲和性,是Pod的一种属性(偏好或硬性要求),它使Pod被吸引到一类特定的节点。Taint 则相反,它使节点能够排斥一类特定的 Pod。Taint 和 Toleration 相互配合,可以用来避免 Pod 被分配到不合适的节点上。每个节点上都可以应用一个或多个 taint ,这表示对于那些不能容忍这些 taint 的 Pod,是不会被该节点接受的。如果toleration 应用于 Pod 上,则表示这些 Pod 可以(但不一定)被调度到具有匹配 taint 的节点上。
使用 kubectl taint 命令可以 给某个 Node 节点设置污点,Node 被设置上污点之后就和 Pod 之间存在了一种相斥的关系,可以让 Node 拒绝 Pod 的调度执行,甚至将 Node 已经存在的 Pod 驱逐出去。
1.2、污点格式
key=value:effect
每个污点有一个 key 和 value 作为污点的标签,其中 value 可以为空,effect 描述污点的作用。
当前 taint effect 支持如下三个选项:
NoSchedule:不调度到此节点
PreferNoSchedule:尽量避免调度具有该污点的 Node 上
NoExecute:不调度 + 驱逐已存在 Pod
1.3、命令示例
# 查看node
kubectl get nodes
kubectl describe node master01
>>>输出
CreationTimestamp: Mon, 05 Jan 2026 15:33:37 +0800
Taints: node-role.kubernetes.io/master:NoSchedule
# 设置污点 key=value给污点打的自定义标签,可以自己定义
kubectl taint node node02 key=value:NoExecute
kubectl taint node node02 key=value:NoSchedule
kubectl taint node node02 key=value:PreferNoSchedule
# 去除污点
kubectl taint node node02 key=value:NoExecute-
NoExecute测试:
2、容忍(Tolerations)
2.1、容忍概述
设置了污点的 Node 将根据 taint 的 effect:NoSchedule、PreferNoSchedule、NoExecute 和 Pod 之间产生互斥的关系,Pod 将在一定程度上不会被调度到 Node 上。但我们可以在 Pod 上设置容忍(Tolerations),意思是设置了容忍的 Pod 将可以容忍污点的存在,可以被调度到存在污点的 Node 上。
2.2、容忍示例
# 将仅有的两个节点都设置污点,发现Pod创建不了
kubectl taint node node01 key=value:NoExecute
kubectl taint node node02 key2=value2:NoExecute
# 在创建Pod的yaml文件加上容忍即可创建成功
## yaml文件内容
apiVersion: v1
kind: Pod
metadata:
name: myapp01
labels:
app: myapp01
spec:
containers:
- name: with-node-affinity
image: nginx
tolerations:
- key: "key" # 污点的键
operator: "Equal" #operator: "Equal" #Equal意味着这个值等于value,如果是Exists,则不需要填写value,只要有这个key就容忍
value: "value" # 污点的值
effect: "NoExecute" # 污点的类型
tolerationSeconds: 3600 # 污点被驱逐存活的时间
创建Pod
kubectl apply -f Pod1.yaml
查看pod所在node01的污点设置
其他注意事项:
1)当不指定 key 值时,表示容忍所有的污点 key
tolerations:
- operator: "Exists"
2)当不指定 effect 值时,表示容忍所有的污点作用
tolerations:
- key: "key"
operator: "Exists"
3)有多个 Master 存在时,防止资源浪费,可以如下设置
kubectl taint node Master-Name node-role.kubernetes.io/master=:PreferNoSchedule
2.3、node更新升级操作
1)如果某个 Node 更新升级系统组件,为了防止业务长时间中断,可以先在该 Node 设置 NoExecute 污点,把该 Node 上的 Pod 都驱逐出去。
kubectl taint node node01 check=mycheck:NoExecute
2)此时如果别的 Node 资源不够用,可临时给 Master 设置 PreferNoSchedule 污点,让 Pod 可在Master 上临时创建。
kubectl taint node master node-role.kubernetes.io/master=:PreferNoSchedule
3)待所有 Node 的更新操作都完成后,再去除污点
kubectl taint node node01 check=mycheck:NoExecute-
八、节点维护

drain 等价于 “cordon + 驱逐”。
在 Kubernetes 中,驱逐(Eviction)是指将运行中的 Pod 从一个节点上迁移到另一个节点的过程,同时释放原节点上的资源以供其他使用。驱逐通常发生在以下情况:
- 需要将 Pod 迁移到其他节点以维护节点或进行软硬件升级。
- 某个节点的资源不足以容纳新的 Pod,需要将旧的 Pod 驱逐以释放资源。
Kubernetes 可以使用自动驱逐机制来管理 Pod 的迁移。它可以基于节点负载、Pod 优先级等条件来自动选择需要驱逐的 Pod,并将它们迁移到其他节点上。在执行驱逐时,Kubernetes 会首先将 SIGTERM 信号发送给 Pod,然后等待一段时间,让 Pod 自行终止。如果自我终止未成功,则Kubernetes 会强制终止 Pod 并进行清理工作。
驱逐是 Kubernetes 集群中必不可少的机制之一,它可以确保系统的高冗余性和高可用性,并优化集群中的资源利用率。
九、Pod生命周期(Phase)

详解phase 的可能状态有:
● Pending:表示APIServer创建了Pod资源对象并已经存入了etcd中,但是它并未被调度完成(比如还没有调度到某台node上),或者仍然处于从仓库下载镜像的过程中。
● Running:Pod已经被调度到某节点之上,并且Pod中所有容器都已经被kubelet创建。至少有一个容器正在运行,或者正处于启动或者重启状态(也就是说Running状态下的Pod不一定能被正常访问)。
● Succeeded:有些pod不是长久运行的,比如job、cronjob,一段时间后Pod中的所有容器都被成功终止,并且不会再重启。需要反馈任务执行的结果。
● Failed:Pod中的所有容器都已终止了,并且至少有一个容器是因为失败终止。也就是说,容器以非0状态退出或者被系统终止,比如 command 写的有问题。
● Unknown:表示无法读取 Pod 状态,通常是 kube-controller-manager 无法与 Pod 通信。
十、故障排除命令
1)查看事件
kubectl describe pod
2)查看日志
kubectl logs [-c 容器名]
3)进入容器
kubectl exec -it bash
4)查看集群状态
kubectl cluster-info
5)查看节点状态
kubectl get nodes
6)查看 kubelet 日志
journalctl -xefu kubelet
十一、小结
kubectl → APIServer → etcd
↓ ↑
Controller Manager ←→ Scheduler ←→ kubelet(Node)
核心调度策略层次:
1)nodeName(直接绑定)
2)nodeSelector(Label 匹配)
3)nodeAffinity / podAffinity(亲和性调度)
4)Taint & Toleration(污点/容忍机制)
5)cordon & drain(节点维护与Pod迁移)
注意:“调度是吸引,污点是排斥,亲和性是偏好,容忍是例外。”
总结
本文系统梳理 K8s 组件协作、Pod 创建与调度全流程,深入解析调度算法及亲和性策略,提供容器调度的方法。
更多推荐


所有评论(0)