目录

1、Kubernetes 组件协作机制

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

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

(2)用户创建 Pod 对象用户

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

(4)etcd 通知事件(Create)

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

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

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

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

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

(10)Scheduler 更新调度结果

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

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

(13)API Server 更新 Pod 状态

4、调度流程

4.1 过滤阶段(Predicate)

4.2 优选阶段(Priorities)

5、指定调度节点方式

5.1 nodeName(强制绑定)

5.2 nodeSelector(基于标签匹配)

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

6.1 节点亲和性(NodeAffinity)

6.2 Pod 亲和性与反亲和性

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

7.1 污点(Taint)

7.2 容忍 (Tolerations)

8、节点维护操作

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. 拉取镜像
    • 2. 创建容器
    • 3. 启动容器
  • 启动成功后将 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 标签命令:

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)

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 上。

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

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐