K8S(八)—— Kubernetes 集群调度全面解析:从组件协作到实战(含亲和性、污点容忍与故障排查)
文章目录
- 前言
- 一、Kubernetes集群调度基础
- 1.1 Kubernetes组件协作机制
- 1.1.1 关键组件及职责
- 1.1.2 组件协作流程简述
- 1.2 Pod创建与工作机制流程
- 1.2.1 初始化监听(List-Watch启动)
- 1.2.2 用户发起创建Pod对象请求
- 1.2.3 etcd数据存储与事件触发
- 1.2.4 副本控制与调度
- 1.2.5 容器运行与状态维护
- 二、Scheduler工作原理
- 2.1 调度器核心任务与目标
- 2.1.1 核心任务
- 2.1.2 调度目标
- 2.2 调度流程详解
- 2.2.1 过滤阶段(Predicate)
- 2.2.2 优选阶段(Priorities)
- 三、指定调度节点的常用方式
- 3.1 nodeName:强制绑定节点
- 3.1.1 配置示例
- 3.1.2 特点
- 3.2 nodeSelector:基于标签匹配
- 3.2.1 操作流程
- 3.2.2 标签管理命令
- 四、亲和性与反亲和性调度
- 4.1 节点亲和性(NodeAffinity)
- 4.1.1 配置结构
- 4.1.2 支持的操作符
- 4.1.3 实践案例
- 案例1:硬策略(必须排除node02)
- 案例2:软策略
- 案例3:软硬策略
- 4.2 Pod亲和性与反亲和性
- 4.2.1 核心区别
- 4.2.2 实践案例
- 案例1:Pod亲和性(与myapp01同拓扑域)
- 案例2:Pod反亲和性(与myapp01不同节点)
- 五、污点(Taint)与容忍(Toleration)
- 5.1 污点(Taint)
- 5.1.1 污点格式与作用
- 5.1.2 污点管理命令
- 5.2 容忍(Toleration)
- 5.2.1 配置示例
- 5.2.2 特殊配置
- 5.2.3 污点在Node节点更新组件时的作用
- 六、节点维护与Pod生命周期
- 6.1 节点维护操作
- 6.2 Pod生命周期阶段(Phase)
- 七、故障排查常用命令
- 总结
前言
在Kubernetes(简称K8s)集群中,调度是实现资源高效利用与业务稳定运行的核心环节。它负责将Pod合理分配到集群节点上,既要满足业务的资源需求,又要保证集群整体的负载均衡。
本文将从K8s组件协作机制出发,详细解析Pod的创建流程、调度器的工作原理,以及节点选择、亲和性调度、污点与容忍等关键技术,并结合实践案例说明节点维护与故障排查方法,帮助读者全面掌握K8s集群调度的核心知识。
一、Kubernetes集群调度基础
1.1 Kubernetes组件协作机制
Kubernetes各组件通过List-Watch机制实现协同工作与数据同步,这种机制确保了组件间的解耦与集群状态的实时一致性。
1.1.1 关键组件及职责
组件 | 职责描述 |
---|---|
kubectl / API客户端 | 向APIServer发起资源创建、查询、更新等管理请求 |
APIServer | 集群控制的核心入口,负责API调用处理、权限校验、与etcd交互 |
etcd | 分布式键值存储,保存集群所有状态信息(如Pod、Node、配置等) |
Controller Manager | 运行各类控制器(如ReplicaSet、Deployment),维持资源期望状态(如副本数、自愈逻辑) |
Scheduler | 调度器,为未分配节点的Pod选择最合适的Node节点 |
kubelet | 节点代理程序,负责本节点上Pod的生命周期管理(创建、启停、状态上报) |
1.1.2 组件协作流程简述
- 用户通过kubectl或其他客户端向APIServer发送请求(如创建Pod)后,APIServer会完成权限校验并将数据存入etcd。
- etcd存储数据时会触发事件(如Create事件),并同步给APIServer;
- 其他组件(Controller Manager、Scheduler、kubelet)通过监听APIServer的事件变化,触发各自的业务逻辑(如Controller Manager维持副本数、Scheduler调度Pod、kubelet运行容器),最终完成整个资源的部署与管理。
1.2 Pod创建与工作机制流程
Pod的完整生命周期需多个组件协同完成,其核心依托于List-Watch模型实现动态响应。以下是Pod创建的典型流程:
1.2.1 初始化监听(List-Watch启动)
Controller Manager、Scheduler、kubelet 启动后会分别通过 Watch API Server(HTTPS 6443 端口)监听集群资源事件变化。
- Controller Manager:监听副本控制类对象(如ReplicaSet、Deployment),确保资源符合期望状态;
- Scheduler:监听未被调度的Pod(
spec.nodeName
为空),准备为其分配节点; - kubelet:监听分配到本节点的Pod,负责后续容器的创建与管理。
1.2.2 用户发起创建Pod对象请求
用户通过kubectl apply -f pod.yaml
等命令,向APIServer发送创建Pod的请求。配置文件pod.yaml
可能包含Pod的元数据、容器镜像、资源需求等信息。
1.2.3 etcd数据存储与事件触发
- APIServer校验请求合法性后,将Pod元数据写入etcd;
- etcd写入成功后,向APIServer返回确认,并触发Create事件;
- APIServer将事件广播给所有监听的组件。
1.2.4 副本控制与调度
- Controller Manager响应:若Pod关联ReplicaSet/Deployment,Controller Manager会检查当前副本数是否符合期望,不足则创建新副本;
- APIServer更新数据:Controller Manager 创建完 Pod 副本后,API Server 会将 Pod 的详细信息更新写入 etcd,触发更新事件;
- Scheduler调度:监听至未调度的Pod(Pending状态),通过调度算法选择合适节点,并将节点信息写入APIServer;
- 数据同步:APIServer更新etcd中Pod的节点绑定信息,完成调度确认。
1.2.5 容器运行与状态维护
- 目标节点的kubelet监听到新分配的Pod,调用容器运行时(如Docker、containerd)拉取镜像、创建并启动容器;
- kubelet将Pod状态(如Running、Failed)上报给APIServer;
- APIServer更新etcd中Pod的状态信息,etcd 确认写入成功后,集群状态同步完成,Pod进入稳定运行(running)阶段。
说明:kubelet会持续监听Pod事件,以应对副本数调整、镜像更新等动态变化,确保容器状态与期望一致。
二、Scheduler工作原理
2.1 调度器核心任务与目标
2.1.1 核心任务
Scheduler的核心职责是为未绑定节点的Pod(spec.nodeName == ""
)分配合适的Node节点,通过创建binding
对象记录调度结果。
2.1.2 调度目标
- 公平性:确保节点间资源分配均衡,避免个别节点负载过高;
- 高效性:最大化集群资源利用率,减少资源浪费;
- 效率:快速完成大批量Pod的调度,降低调度延迟;
- 灵活性:支持自定义调度策略与插件,适配复杂业务场景。
2.2 调度流程详解
调度过程分为过滤(Predicate) 和优选(Priorities) 两个阶段,最终选择最优节点绑定Pod。
2.2.1 过滤阶段(Predicate)
过滤阶段通过一系列算法排除不满足Pod需求的节点,确保剩余节点均为“可行节点”。常见过滤算法如下:
算法名 | 功能描述 |
---|---|
PodFitsResources | 检查节点剩余CPU、内存等资源是否满足Pod需求 |
PodFitsHost | 检查Pod指定的nodeName 是否匹配当前节点 |
PodFitsHostPorts | 检查Pod所需端口是否与节点已使用端口冲突 |
PodSelectorMatches | 检查节点标签是否匹配Pod的标签选择器 |
NoDiskConflict | 检查Pod挂载的Volume是否与节点已有挂载冲突 |
注意:
- 若过滤后无可行节点,Pod将保持Pending状态,调度器会不断重试直至有节点满足条件。
- 如果有多个节点满足条件,就继续 priorities 过程:按照优先级大小对节点排序。
2.2.2 优选阶段(Priorities)
优选阶段对过滤后的可行节点进行打分排序,选择得分最高的节点作为目标。常见优选算法如下:
优先级项 | 描述 |
---|---|
LeastRequestedPriority | 节点资源使用率越低,得分越高(优先分配资源充足的节点) |
BalancedResourceAllocation | 优先选择CPU与内存使用率更均衡的节点(如20%CPU+30%内存优于10%CPU+50%内存) |
ImageLocalityPriority | 优先选择已缓存Pod所需镜像的节点(减少镜像拉取时间) |
最终,调度器将得分最高的节点作为Pod的绑定目标,并更新APIServer中的Pod信息。
三、指定调度节点的常用方式
3.1 nodeName:强制绑定节点
pod.spec.nodeName
直接将Pod调度到指定节点,跳过Scheduler的调度逻辑,属于强制绑定。
3.1.1 配置示例
vim myapp.yamlapiVersion: apps/v1
kind: Deployment
metadata:name: myapp
spec:replicas: 3selector:matchLabels:app: myapptemplate:metadata:labels:app: myappspec:nodeName: node01 # 强制调度到node01containers:- name: myappimage: soscscs/myapp:v1ports:- containerPort: 80
# 执行YAML文件创建Deployment
kubectl apply -f myapp.yaml# 查看pod详细信息,全部调度到了node01
kubectl get pods -o wide
# 查看详细事件(发现未经过 scheduler 调度分配)
kubectl describe po myapp-699655c7fd-c7shz
3.1.2 特点
- 直接由kubelet负责创建容器,无需Scheduler参与;
- 若指定节点不存在或不可用,Pod会一直处于Pending状态。
3.2 nodeSelector:基于标签匹配
pod.spec.nodeSelector
通过标签选择器 label-selector
匹配节点,由Scheduler根据标签策略调度匹配 label,然后调度 Pod 到目标节点,属于强制约束。
3.2.1 操作流程
1、需要获取 node 上的 NAME 名称
kubectl get node
2、 为节点添加标签:
# 给对应的 node 设置标签分别为 yjs=a 和 yjs=b
kubectl label nodes node01 yjs=a
kubectl label nodes node02 yjs=b
# 查看标签
kubectl get nodes --show-labels
3、 配置Pod的nodeSelector:
vim myapp1.yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: myapp1
spec:replicas: 3selector:matchLabels:app: myapp1template:metadata:labels:app: myapp1spec:nodeSelector:yjs: acontainers:- name: myapp1image: soscscs/myapp:v1ports:- containerPort: 80kubectl apply -f myapp1.yaml
4、验证结果:
kubectl get pods -o wide # 所有Pod均运行在node01# 查看详细事件(通过事件可以发现要先经过 scheduler 调度分配)
kubectl describe po myapp1-64c58784f9-4mgc6
3.2.2 标签管理命令
- 查看节点标签:
kubectl get nodes --show-labels
- 筛选指定标签的节点:
kubectl get nodes -l yjs=a
- 修改标签(需加
--overwrite
):kubectl label nodes node01 yjs=b --overwrite
- 删除标签:
kubectl label nodes node01 yjs-
kubectl label nodes node01 yjs=a
kubectl get nodes --show-labels#指定标签查询 node 节点
kubectl get node -l yjs=a ##修改一个 label 的值,需要加上 --overwrite 参数
kubectl label nodes node02 yjs=b --overwrite###删除一个 label,只需在命令行最后指定 label 的 key 名并与一个减号相连即可:
kubectl label nodes node01 yjs-
四、亲和性与反亲和性调度
亲和性调度用于更灵活地控制Pod与节点、Pod与Pod之间的调度关系,分为节点亲和性、Pod亲和性与Pod反亲和性。
4.1 节点亲和性(NodeAffinity)
节点亲和性定义Pod对节点的“偏好”或“硬性要求”,类似“想去哪个班”(软策略)或“必须去哪个班”(硬策略)。
4.1.1 配置结构
affinity:nodeAffinity:requiredDuringSchedulingIgnoredDuringExecution: # 硬策略(必须满足)nodeSelectorTerms:- matchExpressions: # 匹配规则- key: <节点标签键>operator: <操作符>values: [<值列表>]preferredDuringSchedulingIgnoredDuringExecution: # 软策略(优先满足)- weight: <权重,0-100> # 多个软策略时,权重越高优先级越高preference:matchExpressions:- key: <节点标签键>operator: <操作符>values: [<值列表>]
4.1.2 支持的操作符
操作符 | 含义 | 示例 |
---|---|---|
In | 标签值在列表中 | env In (dev, test) |
NotIn | 标签值不在列表中 | env NotIn (prod) |
Gt | 标签值大于指定数值 | version Gt 3 |
Lt | 标签值小于指定数值 | version Lt 3 |
Exists | 标签存在(忽略值) | Exists zone |
DoesNotExist | 标签不存在 | DoesNotExist debug |
4.1.3 实践案例
案例1:硬策略(必须排除node02)
# requiredDuringSchedulingIgnoredDuringExecution:硬策略
mkdir /opt/affinity
cd /opt/affinity
vim pod1.yamlapiVersion: v1
kind: Pod
metadata:name: affinitylabels:app: node-affinity-pod
spec:containers:- name: with-node-affinityimage: soscscs/myapp:v1affinity:nodeAffinity:requiredDuringSchedulingIgnoredDuringExecution:nodeSelectorTerms:- matchExpressions:- key: kubernetes.io/hostname #指定node的标签operator: NotIn #设置Pod安装到kubernetes.io/hostname的标签值不在values列表中的node上values:- node02
# 创建 Pod
kubectl apply -f pod1.yaml# 查看 Pod 调度节点(确认不在 node02 上)
kubectl get pods -o wide
# 重新部署并验证(可选
kubectl delete pod --all && kubectl apply -f pod1.yaml && kubectl get pods -o wide
如果硬策略不满足条件,Pod 状态一直会处于 Pending 状态。
案例2:软策略
# preferredDuringSchedulingIgnoredDuringExecution:软策略
vim pod2.yamlapiVersion: v1
kind: Pod
metadata:name: affinity01labels:app: node-affinity-pod
spec:containers:- name: with-node-affinityimage: soscscs/myapp:v1affinity:nodeAffinity:preferredDuringSchedulingIgnoredDuringExecution:- weight: 5 #如果有多个软策略选项的话,权重越大,优先级越高preference:matchExpressions:- key: kubernetes.io/hostnameoperator: Invalues:- node01- weight: 10 #如果有多个软策略选项的话,权重越大,优先级越高preference:matchExpressions:- key: kubernetes.io/hostnameoperator: Invalues:- node02
kubectl apply -f pod2.yaml
# 查看Pod状态及调度节点(-o wide显示详细信息,包括运行节点)
# 若node02优先级高,Pod会优先调度到node02
kubectl get pods -o wide
案例3:软硬策略
如果把硬策略和软策略合在一起使用,则要先满足硬策略之后才会满足软策略。
vim pod3.yaml
apiVersion: v1
kind: Pod
metadata:name: affinity03labels:app: node-affinity-pod
spec:containers:- name: with-node-affinityimage: soscscs/myapp:v1affinity:nodeAffinity:requiredDuringSchedulingIgnoredDuringExecution: #先满足硬策略,排除有kubernetes.io/hostname=node02标签的节点nodeSelectorTerms:- matchExpressions:- key: kubernetes.io/hostnameoperator: NotInvalues:- node02preferredDuringSchedulingIgnoredDuringExecution: #再满足软策略,优先选择有yjsc=a标签的节点- weight: 1preference:matchExpressions:- key: yjsoperator: Invalues:- a
kubectl apply -f pod3.yaml
# 先满足硬策略不在Node02上,在满足软策略yjs=a的节点上
kubectl get po -owide
4.2 Pod亲和性与反亲和性
Pod亲和性/反亲和性基于已有Pod的标签控制调度,用于实现“Pod与目标Pod同节点/同拓扑域”或“Pod与目标Pod分离”的需求。
4.2.1 核心区别
调度策略 | 匹配对象 | 核心作用 | 拓扑域支持 |
---|---|---|---|
nodeAffinity | 主机 | 根据节点标签(如主机名、硬件配置、环境标识),控制 Pod 调度到指定节点(硬 / 软策略) | 不支持 |
podAffinity | 其他Pod | 使当前Pod与目标Pod在同一拓扑域 | 支持 |
podAntiAffinity | 其他Pod | 使当前Pod与目标Pod在不同拓扑域 | 支持 |
拓扑域:通过
topologyKey
指定节点标签,标签值相同的节点属于同一拓扑域(如同一机房、同一机架)。
4.2.2 实践案例
案例1:Pod亲和性(与myapp01同拓扑域)
kubectl label nodes node01 yjs=a
kubectl label nodes node02 yjs=b
# 先创建一个带标签app=myapp01的Pod(例如它运行在node02,node02标签yjs=b)
vim pod4.yaml
apiVersion: v1
kind: Pod
metadata:name: myapp01labels:app: myapp01
spec:containers:- name: with-node-affinityimage: soscscs/myapp:v1kubectl apply -f pod4.yamlkubectl get pods --show-labels -o wide
# 新Pod通过亲和性调度到与myapp01同拓扑域的节点(yjs=a)
vim pod5.yaml
apiVersion: v1
kind: Pod
metadata:name: myapp02labels:app: myapp02
spec:containers:- name: myapp02image: soscscs/myapp:v1affinity:podAffinity:requiredDuringSchedulingIgnoredDuringExecution:- labelSelector:matchExpressions:- key: appoperator: Invalues:- myapp01 # 匹配标签app=myapp01的PodtopologyKey: yjs # 拓扑域为标签yjs,值相同的节点为同一域
#仅当节点和至少一个已运行且有键为“app”且值为“myapp01”的标签 的 Pod 处于同一拓扑域时,才可以将该 Pod 调度到节点上。 (更确切的说,如果节点 N 具有带有键 yjs 和某个值 V 的标签,则 Pod 有资格在节点 N 上运行,以便集群中至少有一个具有键 yjs 和值为 V 的节点正在运行具有键“app”和值 “myapp01”的标签的 pod。)
#topologyKey 是节点标签的键。如果两个节点使用此键标记并且具有相同的标签值,则调度器会将这两个节点视为处于同一拓扑域中。 调度器试图在每个拓扑域中放置数量均衡的 Pod。
#如果 yjs 对应的值不一样就是不同的拓扑域。比如 Pod1 在 yjs=a 的 Node 上,Pod2 在 yjs=b 的 Node 上,Pod3 在 yjs=a 的 Node 上,则 Pod2 和 Pod1、Pod3 不在同一个拓扑域,而Pod1 和 Pod3在同一个拓扑域。
kubectl apply -f pod5.yamlkubectl get pods --show-labels -o wide
最终myapp02会被调度到node02(与myapp01同属yjs=a域)。
案例2:Pod反亲和性(与myapp01不同节点)
# 示例一
vim pod6.yaml
apiVersion: v1
kind: Pod
metadata:name: myapp10labels:app: myapp10
spec:containers:- name: myapp10image: soscscs/myapp:v1affinity:podAntiAffinity:preferredDuringSchedulingIgnoredDuringExecution:- weight: 100podAffinityTerm:labelSelector:matchExpressions:- key: appoperator: Invalues:- myapp01 # 匹配标签app=myapp01的PodtopologyKey: kubernetes.io/hostname # 拓扑域为节点主机名(即单个节点)#如果节点处于 Pod 所在的同一拓扑域且具有键“app”和值“myapp01”的标签, 则该 pod 不应将其调度到该节点上。
#(如果 topologyKey 为 kubernetes.io/hostname,则意味着当节点和具有键 “app”和值“myapp01”的 Pod 处于相同的拓扑域,Pod 不能被调度到该节点上。)
kubectl apply -f pod6.yamlkubectl get pods --show-labels -o wide
# 最终myapp10会被调度到与myapp01不同的节点(如node01)
# 示例二
# 前提:node01和node02都有yjs=a这个标签
vim pod7.yaml
apiVersion: v1
kind: Pod
metadata:name: myapp20labels:app: myapp20
spec:containers:- name: myapp20image: soscscs/myapp:v1affinity:podAntiAffinity:requiredDuringSchedulingIgnoredDuringExecution:- labelSelector:matchExpressions:- key: appoperator: Invalues:- myapp01topologyKey: yjs#由于指定 Pod 所在的 node01 节点上具有带有键 yjs 和标签值 a 的标签,node02 也有这个yjs=a的标签,所以 node01 和 node02 是在一个拓扑域中,反亲和要求新 Pod 与指定 Pod 不在同一拓扑域,所以新 Pod 没有可用的 node 节点,即为 Pending 状态。
kubectl apply -f pod7.yamlkubectl get pod --show-labels -owide
五、污点(Taint)与容忍(Toleration)
节点亲和性,是Pod的一种属性(偏好或硬性要求),它使Pod被吸引到一类特定的节点。Taint 则相反,它使节点能够排斥一类特定的 Pod。
污点与容忍机制用于实现节点对Pod的排斥
与例外
,节点通过污点拒绝不匹配的Pod,而Pod通过容忍突破排斥。
5.1 污点(Taint)
5.1.1 污点格式与作用
污点格式:key=value:effect
,其中effect
定义排斥行为,支持以下三种类型:
effect类型 | 描述 |
---|---|
NoSchedule | 拒绝调度新Pod到该节点(已运行的Pod不受影响) |
PreferNoSchedule | 尽量不调度新Pod到该节点(非强制) |
NoExecute | 拒绝新Pod调度,且驱逐已运行的不匹配Pod |
5.1.2 污点管理命令
- 添加污点:
kubectl taint node node01 key=value:NoSchedule
- 查看节点污点:
kubectl describe node node01 | grep Taint
- 删除污点:
kubectl taint node node01 key:NoSchedule-
kubectl get nodes
NAME STATUS ROLES AGE VERSION
master01 Ready control-plane,master 3d9h v1.20.11
node01 Ready <none> 3d9h v1.20.11
node02 Ready <none> 3d9h v1.20.11# master 就是因为有 NoSchedule 污点,k8s 才不会将 Pod 调度到 master 节点上
kubectl describe node master| grep Taint
Taints: node-role.kubernetes.io/master:NoSchedule
kubectl get pods -o wide
======================================================================================
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
affinity 1/1 Running 0 48m 10.244.1.43 node01 <none> <none>
affinity01 1/1 Running 0 44m 10.244.2.49 node02 <none> <none>
affinity03 1/1 Running 0 23m 10.244.1.45 node01 <none> <none>
myapp01 1/1 Running 0 20m 10.244.2.50 node02 <none> <none>
myapp02 1/1 Running 0 18m 10.244.2.51 node02 <none> <none>
myapp10 1/1 Running 0 11m 10.244.1.46 node01 <none> <none>
myapp20 1/1 Running 0 104s 10.244.2.52 node02 <none> <none>
nginx-5658bdf5d4-28jsk 1/1 Running 0 9s 10.244.1.49 node01 <none> <none>
nginx-5658bdf5d4-f58gr 1/1 Running 0 9s 10.244.2.53 node02 <none> <none>
nginx-5658bdf5d4-k2qsj 1/1 Running 0 9s 10.244.2.54 node02 <none> <none>
nginx-5658bdf5d4-mn7hg 1/1 Running 0 9s 10.244.1.48 node01 <none> <none>
nginx-5658bdf5d4-q84z6 1/1 Running 0 9s 10.244.1.47 node01 <none> <none>kubectl taint node node02 check=mycheck:NoExecute# 查看 Pod 状态,会发现 node02 上的 Pod 已经被全部驱逐(注:如果是 Deployment 或者 StatefulSet 资源类型,为了维持副本数量则会在别的 Node 上再创建新的 Pod)
kubectl get pods -o wide
======================================================================================
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
affinity 1/1 Running 0 49m 10.244.1.43 node01 <none> <none>
affinity03 1/1 Running 0 24m 10.244.1.45 node01 <none> <none>
myapp10 1/1 Running 0 13m 10.244.1.46 node01 <none> <none>
nginx-5658bdf5d4-28jsk 1/1 Running 0 110s 10.244.1.49 node01 <none> <none>
nginx-5658bdf5d4-mn7hg 1/1 Running 0 110s 10.244.1.48 node01 <none> <none>
nginx-5658bdf5d4-q84z6 1/1 Running 0 110s 10.244.1.47 node01 <none> <none>
nginx-5658bdf5d4-qshrj 1/1 Running 0 14s 10.244.1.50 node01 <none> <none>
nginx-5658bdf5d4-wwmr7 1/1 Running 0 14s 10.244.1.51 node01 <none> <none>
5.2 容忍(Toleration)
Pod通过容忍配置可突破节点的污点限制,需与节点污点的key
、value
、effect
匹配。
5.2.1 配置示例
kubectl taint node node01 check=mycheck:NoExecute
kubectl apply -f pod3.yaml
# 在两个 Node 上都设置了污点后,此时 Pod 将无法创建成功
kubectl get pods -o wide
vim pod3.yaml
apiVersion: v1
kind: Pod
metadata:name: myapp01labels:app: myapp01
spec:containers:- name: with-node-affinityimage: soscscs/myapp:v1tolerations:- key: "check"operator: "Equal" #operator: "Equal" #Equal意味着这个值等于value,如果是Exists,则不需要填写value,只要有这个key就容忍value: "mycheck" # 与污点的value匹配effect: "NoExecute" # 与污点的effect匹配tolerationSeconds: 3600 # 被驱逐前可在节点上保留的时间(仅对NoExecute有效)#其中的 key、vaule、effect 都要与 Node 上设置的 taint 保持一致
#operator 的值为 Exists 将会忽略 value 值,即存在即可
#tolerationSeconds 用于描述当 Pod 需要被驱逐时可以在 Node 上继续保留运行的时间
kubectl apply -f pod3.yaml# 在设置了容忍之后,Pod 创建成功
kubectl get pods -o wide
5.2.2 特殊配置
1、当不指定 key 值时,表示容忍所有的污点 key:
tolerations:
- operator: "Exists" # 忽略key和effect,容忍所有污点
2、容忍指定key的所有effect:
tolerations:
- key: "key"operator: "Exists" # 忽略effect,容忍key=key的所有effect
3、有多个 Master 存在时,防止资源浪费,可以如下设置
kubectl taint node Master-Name node-role.kubernetes.io/master=:PreferNoSchedule
5.2.3 污点在Node节点更新组件时的作用
# 如果某个 Node 更新升级系统组件,为了防止业务长时间中断,可以先在该 Node 设置 NoExecute 污点,把该 Node 上的 Pod 都驱逐出去
kubectl taint node node01 check=mycheck:NoExecute# 此时如果别的 Node 资源不够用,可临时给 Master 设置 PreferNoSchedule 污点,让 Pod 可在 Master 上临时创建
kubectl taint node master node-role.kubernetes.io/master=:PreferNoSchedule# 待所有 Node 的更新操作都完成后,再去除污点
kubectl taint node node01 check=mycheck:NoExecute-
key、value、effect 必须与 Node 上的污点匹配。
operator: Exists
表示存在即可。
六、节点维护与Pod生命周期
6.1 节点维护操作
当需要对节点进行升级、检修时,可通过以下命令暂时隔离节点并迁移Pod:
命令 | 功能描述 |
---|---|
kubectl cordon <node> | 标记节点为“不可调度”,阻止新Pod调度至此 |
kubectl drain <node> --ignore-daemonsets --delete-emptydir-data | 驱逐节点上的Pod(忽略DaemonSet,删除本地数据) |
kubectl uncordon <node> | 恢复节点为“可调度”状态 |
说明:
drain
命令等价于“cordon + 驱逐”,适用于节点离线维护场景。
kubectl get po -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
affinity03 1/1 Running 0 4m34s 10.244.1.56 node01 <none> <none>
myapp01 1/1 Running 0 2m31s 10.244.2.61 node02 <none> <none>
nginx-5658bdf5d4-kjrvc 1/1 Running 0 5m54s 10.244.1.55 node01 <none> <none>
nginx-5658bdf5d4-mp599 1/1 Running 0 5m54s 10.244.1.57 node01 <none> <none>
nginx-5658bdf5d4-pzj4t 1/1 Running 0 5m55s 10.244.1.53 node01 <none> <none>
nginx-5658bdf5d4-qtt76 1/1 Running 0 5m54s 10.244.1.54 node01 <none> <none>
nginx-5658bdf5d4-s4rhh 1/1 Running 0 5m54s 10.244.1.58 node01 <none> <none>
# 标记节点不可调度
kubectl cordon node01
kubectl describe nodes node01 |grep Taint
# 驱逐node01上的pod
kubectl drain node01 --ignore-daemonsets --delete-emptydir-data --force
kubectl get po -owide
# 将节点恢复为可调度状态
kubectl uncordon <node>
kubectl describe nodes node01|grep Taint
Kubernetes 中的驱逐(Eviction)机制是指将运行中的 Pod 从当前节点迁移到其他节点的过程,旨在释放原节点资源供其他用途。主要触发场景包括:
- 节点维护或升级时需要迁移 Pod
- 节点资源不足,需通过驱逐现有 Pod 来腾出空间
Kubernetes 通过智能驱逐策略自动管理 Pod 迁移,其决策依据包括:
- 节点负载情况
- Pod 优先级设定
驱逐过程遵循标准终止流程:
- 发送 SIGTERM 信号通知 Pod
- 预留合理终止时间窗口
- 超时后强制终止并清理资源
该机制是保障 Kubernetes 集群稳定运行的核心功能,有效提升了:
- 系统冗余性和可用性
- 资源利用效率
6.2 Pod生命周期阶段(Phase)
Pod在生命周期中会经历以下阶段,反映其当前状态:
阶段 | 说明 |
---|---|
Pending | 已创建但未调度,或正在拉取镜像 |
Running | 至少一个容器运行中(或启动/重启中) |
Succeeded | 所有容器正常终止(如Job类任务完成) |
Failed | 至少一个容器异常终止(非0退出码或被强制终止) |
Unknown | 无法获取状态(通常为通信故障) |
phase的可能状态详解:
-
Pending:表示 APIServer 已创建 Pod 资源对象并存入 etcd,但尚未完成调度(如未分配到具体节点)或仍在下载镜像过程中。
-
Running:Pod 已成功调度到节点,且所有容器均由 kubelet 创建完成。至少有一个容器处于运行状态或正在启动/重启(注意:处于 Running 状态的 Pod 不一定能正常提供服务)。
-
Succeeded:适用于非持久运行的 Pod(如 Job、CronJob)。当 Pod 中所有容器均成功终止且不再重启时进入此状态,通常用于反馈任务执行结果。
-
Failed:Pod 中所有容器均已终止,且至少有一个容器因故障退出(返回非0状态码或被系统强制终止)。
-
Unknown:表示无法获取 Pod 状态信息,通常由 kube-controller-manager 与 Pod 通信异常导致。
七、故障排查常用命令
操作需求 | 命令示例 |
---|---|
查看Pod事件(调度失败原因) | kubectl describe pod <pod-name> |
查看Pod日志 | kubectl logs <pod-name> [-c <container-name>] |
进入容器执行命令 | kubectl exec -it <pod-name> -- bash |
查看集群状态 | kubectl cluster-info |
查看节点状态 | kubectl get nodes |
查看kubelet日志 | journalctl -xefu kubelet |
总结
Kubernetes调度是集群资源管理的核心,通过组件协作、调度算法、亲和性策略、污点与容忍等机制,实现了Pod的智能分配。本文从基础机制到实践操作,详细介绍了:
- 组件通过List-Watch机制协同工作,完成Pod从创建到运行的全流程;
- 调度器通过过滤与优选阶段选择最优节点,平衡资源利用率与业务需求;
- 节点选择方式从简单的强制绑定(nodeName)到灵活的标签匹配(nodeSelector)、亲和性调度,满足不同场景需求;
- 污点与容忍机制实现节点对Pod的精细控制,配合节点维护命令保障集群稳定性。
在实际应用中,需根据业务特点选择合适的调度策略(如核心服务优先使用硬亲和性,弹性服务使用软亲和性),并通过故障排查命令快速定位问题,确保集群高效稳定运行。
一句话总结: “调度是吸引,污点是排斥,亲和性是偏好,容忍是例外。”