理解 Kubernetes 架构,最重要的不是背组件名,而是先把系统拆成两层:控制平面负责做决策,节点负责执行决策。这个划分一旦清楚,很多排障动作都会变得直接很多。

用一句话先记住

  • 控制平面:决定“应该发生什么”
  • 节点:负责“把它真的跑起来”
  • 控制器:不断比较期望状态与实际状态
  • 对账循环:只要没收敛,就一直继续推进

如果你只记住这一件事,已经能解决很多“为什么 apply 成功了但东西没跑起来”的困惑。

控制平面的核心组件

API Server

API Server 是整个集群的正门。kubectl、调度器、控制器、各种 operator,最后都要通过它和集群交互。

如果你发现请求超时、鉴权失败、对象写不进去,优先考虑 API Server 这一层。

etcd

etcd 是集群状态的持久化存储,可以理解成控制平面的“记忆体”。

一旦 etcd 变慢、异常或者发生网络分区,整个集群的读写都会受影响,因为所有人都在依赖它记录当前状态和目标状态。

Scheduler

调度器只做一件事:为还没有绑定节点的 Pod 选择一个合适的节点。

它会综合考虑:

  • requests / limits
  • taints / tolerations
  • affinity / anti-affinity
  • topology 约束
  • 其他调度规则

如果一个 Pod 长时间停在 Pending,调度器和约束条件往往就在问题链路里。

Controller Manager

Controller Manager 是声明式系统真正的发动机。Deployment、ReplicaSet、StatefulSet、Node 等背后都依赖不同控制器持续工作。

控制器不会“帮你执行一次命令就完了”,它会一直盯着状态,只要实际结果和 Spec 不一致,就继续推动系统收敛。

节点上的核心组件

kubelet

kubelet 是节点上的大管家。它不断观察“有哪些 Pod 已经被分配到我这台机器”,然后配合底层容器运行时把这些容器真正拉起来。

如果你遇到镜像拉不下来、卷挂载失败、探针一直失败,kubelet 往往就在排障核心位置。

Container Runtime

通常是 containerd 或 CRI-O。它负责真正拉镜像、创建容器、管理容器生命周期。

Kubernetes 决定跑什么,runtime 决定怎么把它跑起来。

kube-proxy

kube-proxy 会根据 Service 和 Endpoints 的变化更新转发表规则,让流量能被送到正确的后端。

当你看到 Service 明明存在却访问不通时,kube-proxy 可能不是唯一根因,但肯定在流量路径上。

CNI / CSI

CNI 管网络,CSI 管存储挂载。

如果 Pod 连 IP 都拿不到,或者卷一直挂不上,就说明问题已经超出了 Deployment/Pod 本身,进入插件层了。

一张图记住整体链路

kubectl
  |
  v
API Server ---> etcd
  |
  +---> Scheduler
  |
  +---> Controllers
  |
  +---> kubelet on nodes ---> container runtime
                       |
                       +---> CNI / CSI / kube-proxy

kubectl apply 之后到底发生了什么

很多人以为 kubectl apply -f xxx.yaml 返回成功,就等于应用已经跑起来了。真实情况是它只是把“意图”写进系统,后面还会经历一整条事件链:

  1. kubectl 把请求发给 API Server。
  2. API Server 验证并把对象写入 etcd。
  3. 相关控制器发现“期望状态”和当前状态有差距。
  4. 控制器创建或更新 ReplicaSet、Pod 等对象。
  5. 调度器为尚未调度的 Pod 选择节点。
  6. 目标节点上的 kubelet 拉镜像、挂卷、接网络、启动容器。
  7. 状态再回写到 API Server。
  8. 控制器继续对账,直到结果尽量接近期望。

理解这条链路之后,架构图就不只是理论了,而是你排障时真正的地图。

用现象反推组件

下面这个对照关系很实用:

现象 第一优先排查层
kubectl apply 卡住或超时 API Server、鉴权、连通性
Pod 长时间 Pending Scheduler、资源约束、PVC 绑定
Pod 长时间 ContainerCreating kubelet、镜像、CNI、CSI
Pod 持续重启 应用进程、探针、kubelet
Service 在,但流量不通 selector、endpoints、kube-proxy、策略
PVC 一直不绑定 StorageClass、provisioner、拓扑

这个对照不是绝对真理,但非常适合作为第一轮缩小范围的起点。

如何区分“控制面问题”还是“节点问题”

排障时早点问自己这个问题,会省很多时间:

  • 是集群“决策错了”?
  • 还是节点“执行不出来”?

例如:

  • Pod 根本没有被调度 -> 更像控制面或调度约束问题
  • Pod 已经有节点了,但镜像拉不下来 -> 更像节点执行问题
  • Deployment 改了但没有生成新副本 -> 更像控制器或 API 层问题
  • Service 有对象但没有 endpoints -> 更像对象关系或标签问题,不一定是网络栈本身

一些很常见的误解

“Kubernetes 会执行我的命令”

不准确。kubectl 只是提交对象或者读取状态,真正持续干活的是控制器和 kubelet。

“apply 成功就说明工作负载已经正常了”

也不对。apply 成功只说明请求被接受了,后面还有调度、镜像拉取、挂卷、探针、服务发现等一整串动作。

“Pod Pending 就是节点坏了”

有时候是,但更多时候是调度条件、资源请求、存储或约束不满足。

最小实验链路

你可以用下面这组命令把架构链路跑一遍:

kubectl create namespace demo
kubectl apply -f deployment.yaml -n demo
kubectl get deploy,pods -n demo
kubectl describe deploy -n demo app
kubectl describe pod -n demo <pod-name>
kubectl get events -n demo --sort-by=.metadata.creationTimestamp

这一轮下来,你基本就能观察到 API Server、控制器、调度器、kubelet 之间是怎么接力的。

不同卡点该怎么查

Pod 卡在 Pending

  • kubectl describe pod
  • 看 requests / limits
  • 看亲和性 / 反亲和性
  • 看 taints / tolerations
  • 看 PVC 是否已绑定

Pod 卡在 ContainerCreating

  • 看镜像拉取错误
  • 看卷挂载失败
  • 看 CNI 是否分配 IP 失败
  • 看节点是否 NotReady

发布卡住或很慢

  • 看 Deployment conditions
  • 看 ReplicaSet 是否创建正确
  • 看 readiness probe 是否太严格
  • maxUnavailable / maxSurge 配置

越早建立越轻松的习惯

  • Manifest 放入版本控制
  • Label 体系稳定下来
  • requests / limits 不要长期空着
  • 监控和日志尽早接入
  • 发布前先想好回滚路径

这些习惯会让整个架构更容易被你“看懂”,而不是每次都像在看黑盒。

FAQ

Q: 为什么 Kubernetes 一定要靠对账循环,而不是执行一次命令就结束? A: 因为集群状态一直在变化:节点会掉、容器会崩、配置会改。对账循环保证系统能持续把实际状态拉回期望状态。

Q: kubectl apply 成功了,为什么后面还是会失败? A: 因为对象被接受只是第一步,后面还有调度、拉镜像、挂载、探针和流量接入等一系列动作。

Q: 架构排障时最有用的问题是什么? A: 问自己“链路断在哪一段了”:API 接收、控制器创建、调度、节点执行,还是流量暴露。

下一步阅读

  • 接着读 kubernetes-quickstart-pod.md
  • 再读 kubernetes-quickstart-deployment-replicaset.md
  • 然后读 kubernetes-quickstart-service.md

参考链接