Kubernetes 集群调度 【K8S (五)】

目录

[1、Kubernetes 组件协作机制](#1、Kubernetes 组件协作机制)

[2、Pod 创建与工作机制流程](#2、Pod 创建与工作机制流程)

(1)三大组件启动监听(List-Watch)

[(2)用户创建 Pod 对象用户](#(2)用户创建 Pod 对象用户)

[(3)API Server 将 Pod 信息写入 etcd](#(3)API Server 将 Pod 信息写入 etcd)

[(4)etcd 通知事件(Create)](#(4)etcd 通知事件(Create))

[(5)Controller Manager 监听到 Pod 创建事件](#(5)Controller Manager 监听到 Pod 创建事件)

[(6)Replication Controller(RC)/ ReplicaSet 保证副本数](#(6)Replication Controller(RC)/ ReplicaSet 保证副本数)

[(7)API Server 更新 etcd(记录详细信息)](#(7)API Server 更新 etcd(记录详细信息))

[(8)etcd 触发 Pod 信息更新事件](#(8)etcd 触发 Pod 信息更新事件)

[(9)Scheduler 监听到待调度的 Pod](#(9)Scheduler 监听到待调度的 Pod)

[(10)Scheduler 更新调度结果](#(10)Scheduler 更新调度结果)

[(11)etcd 确认更新 & API Server 同步结果](#(11)etcd 确认更新 & API Server 同步结果)

[(12)kubelet 在 Node 上拉取并运行容器](#(12)kubelet 在 Node 上拉取并运行容器)

[(13)API Server 更新 Pod 状态](#(13)API Server 更新 Pod 状态)

4、调度流程

[4.1 过滤阶段(Predicate)](#4.1 过滤阶段(Predicate))

[4.2 优选阶段(Priorities)](#4.2 优选阶段(Priorities))

5、指定调度节点方式

[5.1 nodeName(强制绑定)](#5.1 nodeName(强制绑定))

[5.2 nodeSelector(基于标签匹配)](#5.2 nodeSelector(基于标签匹配))

[6、节点亲和性与 Pod 亲和性](#6、节点亲和性与 Pod 亲和性)

[6.1 节点亲和性(NodeAffinity)](#6.1 节点亲和性(NodeAffinity))

[6.2 Pod 亲和性与反亲和性](#6.2 Pod 亲和性与反亲和性)

[7、污点(Taint) 和 容忍(Tolerations)](#7、污点(Taint) 和 容忍(Tolerations))

[7.1 污点(Taint)](#7.1 污点(Taint))

[7.2 容忍 (Tolerations)](#7.2 容忍 (Tolerations))

8、节点维护操作

[9、Pod 生命周期(Phase)](#9、Pod 生命周期(Phase))

10、故障排查命令


1、Kubernetes 组件协作机制

Kubernetes 通过List-Watch机制使各个组件协作、数据同步,从而实现解耦与实时一致性。

关键组件关系:

|--------------------|--------------------------------|
| 组件 | 职责 |
| kubectl / API 客户端 | 向 APIServer 发起资源创建或管理请求 |
| APIServer | 负责 API 调用、权限校验、存储交互,是集群控制的核心入口 |
| etcd | 存储集群所有状态信息 |
| Controller Manager | 维持副本数、执行自愈逻辑(扩容、重建等) |
| Scheduler | 调度器,将未分配节点的 Pod 分配到合适的 Node |
| kubelet | 节点代理,负责 Pod 生命周期管理和容器运行状态上报 |

2、Pod 创建与工作机制流程

Pod 创建的整个生命周期由多组件配合完成:

2.1典型创建过程(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):
      1. 拉取镜像
      1. 创建容器
      1. 启动容器
  • 启动成功后将 Pod 状态(Running、Failed 等)上报给 API Server。
(13)API Server 更新 Pod 状态
  • API Server 将 kubelet 上报的状态写入 etcd。
  • etcd 确认写入成功后,集群状态完成同步,Pod 正式进入Running状态

kubelet 持续监听 Pod 事件,是为了应对副本数变化、镜像更新等动态操作。

注意:在创建 Pod 的工作就已经完成了后,为什么 kubelet 还要一直监听呢?原因很简单,假设这个 时候 kubectl 发命令,要扩充 Pod 副本数量,那么上面的流程又会触发一遍,kubelet 会根据最新的 Pod 的部署情况调整 Node 的资源。又或者 Pod 副本数量没有发生变化,但是其中的镜像文件升级 了,kubelet 也会自动获取最新的镜像文件并且加载。

核心任务

未绑定 Node 的 Pod(spec.nodeName == "") 分配到合适的节点。

调度目标

  • **公平性:**节点间资源分配均衡
  • **高效性:**集群所有资源最大化被使用
  • **效率:**调度的性能要好,能够尽快地对大批量的 pod 完成调度工作
  • **灵活性:**允许自定义策略(调度策略、插件)

Sheduler 是作为单独的程序运行的,启动之后会一直监听 APIServer,获取 spec.nodeName 为空的pod,对每个 pod 都会创建一个 binding,表明该 pod 应该放到哪个节点上。

调度分为几个部分:首先是过滤掉不满足条件的节点,这个过程称为预算策略(predicate);然后对通过的节点按照优先级排序,这个是优选策略(priorities);最后从中选择优先级最高的节点。如果中间任何一步骤有错误,就直接返回错误。

4、调度流程

4.1 过滤阶段(Predicate)

过滤掉不满足条件的节点。

常见过滤算法:

|--------------------|---------------------|
| 算法名 | 功能描述 |
| PodFitsResources | 检查节点剩余资源是否满足 Pod 需求 |
| PodFitsHost | 检查 NodeName 是否匹配 |
| PodFitsHostPorts | 检查端口冲突 |
| PodSelectorMatches | label 匹配 |
| NoDiskConflict | Volume 挂载冲突检测 |

若无节点满足条件,Pod 进入 Pending 状态,不断重试。

如果在 predicate 过程中没有合适的节点,pod 会一直在 pending 状态,不断重试调度,直到有

节点满足条件。 经过这个步骤,如果有多个节点满足条件,就继续 priorities 过程:按照优先级大

小对节点排序。

4.2 优选阶段(Priorities)

常见算法:

|----------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 优先级项 | 描述 |
| LeastRequestedPriority | 资源使用率越低,权重越高 |
| BalancedResourceAllocation | CPU 与内存使用率越接近越好(这个一般和上面的一起使用,不单独使用。比如 node01 的 CPU 和 Memory 使用率20:60,node02 的 CPU 和 Memory 使用率 50:50,虽然node01 的总使用率比 node02 低,但 node02 的 CPU 和Memory 使用率更接近,从而调度时会优选 node02。) |
| ImageLocalityPriority | 优先节点上已有目标镜像的节点 |

5、指定调度节点方式

5.1 nodeName(强制绑定)

pod.spec.nodeName 将 Pod 直接调度到指定的 Node 节点上,会跳过 Scheduler 的调度策略,该匹

配规则是强制匹配

5.2 nodeSelector(基于标签匹配)

pod.spec.nodeSelector:通过 kubernetes 的 label-selector 机制选择节点,由调度器调度策略匹

配 label,然后调度 Pod 到目标节点,该匹配规则属于强制约束

管理 Node 标签命令:

bash 复制代码
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 node02 yjs-

6、节点亲和性与 Pod 亲和性

6.1 节点亲和性(NodeAffinity)

bash 复制代码
affinity:
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:   # 硬策略
    preferredDuringSchedulingIgnoredDuringExecution:  # 软策略

类比理解:

你更"想去"张老师的班(软策略),还是"必须去"张老师的班(硬策略)。

操作符支持:

In、NotIn、Exists、DoesNotExist、Gt、Lt

Kubernetes 中 label selector 的键值运算关系 ,在 Kubernetes 中,很多资源(比如 Pod、

Deployment、Service)都会用 label selector(标签选择器) 来筛选对象。运算符决定"选谁"或"不选谁"。

简单理解

In / NotIn 看"名单",

Gt / Lt 看"数值",

Exists / DoesNotExist 看"有没有"。

6.2 Pod 亲和性与反亲和性

7、污点(Taint) 和 容忍(Tolerations)

7.1 污点(Taint)

节点亲和性,是Pod的一种属性(偏好或硬性要求),它使Pod被吸引到一类特定的节点。Taint 则相反,它使节点能够排斥一类特定的 Pod。

Taint 和 Toleration 相互配合,可以用来避免 Pod 被分配到不合适的节点上。每个节点上都可以应用一个或多个 taint ,这表示对于那些不能容忍这些 taint 的 Pod,是不会被该节点接受的。如果将 toleration 应用于 Pod 上,则表示这些 Pod 可以(但不一定)被调度到具有匹配 taint 的节点上。

使用 kubectl taint 命令可以 给某个 Node 节点设置污点,Node 被设置上污点之后就和 Pod 之间存在了一种相斥的关系,可以让 Node 拒绝 Pod 的调度执行,甚至将 Node 已经存在的 Pod 驱逐出去。

污点格式:

key=value:effect

每个污点有一个 key 和 value 作为污点的标签,其中 value 可以为空,effect 描述污点的作用。

当前 taint effect 支持如下三个选项:

|------------------|-------------------|
| 类型 | 描述 |
| NoSchedule | 不调度到此节点 |
| PreferNoSchedule | 尽量避免调度具有该污点的Node上 |
| NoExecute | 不调度+驱逐已存在的Pod |

7.2 容忍 (Tolerations)

设置了污点的 Node 将根据 taint 的 effect:NoSchedule、PreferNoSchedule、NoExecute 和 Pod 之间产生互斥的关系,Pod 将在一定程度上不会被调度到 Node 上。但我们可以在 Pod 上设置容忍(Tolerations),意思是设置了容忍的 Pod 将可以容忍污点的存在,可以被调度到存在污点的 Node 上。

bash 复制代码
kubectl taint node node01 check=mycheck:NoExecute
vim pod3.yaml
    
kubectl apply -f pod3.yaml
//在两个 Node 上都设置了污点后,此时 Pod 将无法创建成功
kubectl get pods -o wide
NAME      READY   STATUS    RESTARTS   AGE   IP       NODE     NOMINATED NODE   
READINESS GATES
myapp01   0/1     Pending   0          17s   <none>   <none>   <none>           
<none>

vim pod3.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"  #operator: "Equal" #Equal意味着这个值等于value,如果是Exists,则不需要填写value,只要有这个key就容忍
    value: "mycheck"
    effect: "NoExecute"
    tolerationSeconds: 3600
    
#其中的 key、vaule、effect 都要与 Node 上设置的 taint 保持一致
#operator 的值为 Exists 将会忽略 value 值,即存在即可
#tolerationSeconds 用于描述当 Pod 需要被驱逐时可以在 Node 上继续保留运行的时间
kubectl apply -f pod3.yaml
//在设置了容忍之后,Pod 创建成功
kubectl get pods -o wideREADY   STATUS    RESTARTS   AGE   IP           NODE     
NOMINATED NODE   READINESS GATES
myapp01   1/1     Running   0          10m   10.244.1.5   node01   <none>         
  <none>
NAME      
//其它注意事项
(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
//如果某个 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-

8、节点维护操作

cordon & drain

kubectl cordon <node> #标记为不可调度

kubectl drain <node> --ignore-daemonsets --delete-local-data --force #驱逐 Pod

kubectl uncordon <node> #恢复可调度状态

9、Pod 生命周期(Phase)

|-----------|-----------------|
| 阶段 | 说明 |
| Pending | 已创建但未调度或拉取镜像中 |
| Running | 容器已启动运行中 |
| Succeeded | 所有容器成功终止(Job 类) |
| Failed | 容器失败退出(非0或异常) |
| Unknown | 无法获取状态(通信异常) |

详解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 通信。

10、故障排查命令

|---------------|---------------------------------|
| 操作 | 命令 |
| 查看事件 | kubectl describe pod <POD> |
| 查看日志 | kubectl logs <POD> [-c 容器名] |
| 进入容器 | kubectl exec -it <POD> bash |
| 查看集群状态 | kubectl cluster-info |
| 查看节点状态 | kubectl get nodes |
| 查看 kubelet 日志 | journalctl -xefu kubelet |

相关推荐
༺๑Tobias๑༻2 小时前
K8S简易实现快速部署HTTPS方法
容器·https·kubernetes
-dcr2 小时前
53.k8s的pod管理
云原生·容器·kubernetes
stark张宇3 小时前
逃离 Docker Hub 限速!国内镜像 + 完整 Docker Compose 部署 Node 与 MySQL 服务
mysql·docker·容器
無森~3 小时前
ZooKeeper
分布式·zookeeper·云原生
Chan164 小时前
【 微服务SpringCloud | 模块拆分 】
java·数据结构·spring boot·微服务·云原生·架构·intellij-idea
chinesegf4 小时前
docker迁移镜像并运行
运维·docker·容器
输出输入4 小时前
云原生是什么?
云原生
Zfox_5 小时前
【Docker#1】技术架构演进之路
后端·docker·容器·架构
H Journey5 小时前
Docker基本使用
docker·容器·eureka