理解 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 返回成功,就等于应用已经跑起来了。真实情况是它只是把“意图”写进系统,后面还会经历一整条事件链:
kubectl把请求发给 API Server。- API Server 验证并把对象写入 etcd。
- 相关控制器发现“期望状态”和当前状态有差距。
- 控制器创建或更新 ReplicaSet、Pod 等对象。
- 调度器为尚未调度的 Pod 选择节点。
- 目标节点上的 kubelet 拉镜像、挂卷、接网络、启动容器。
- 状态再回写到 API Server。
- 控制器继续对账,直到结果尽量接近期望。
理解这条链路之后,架构图就不只是理论了,而是你排障时真正的地图。
用现象反推组件
下面这个对照关系很实用:
| 现象 | 第一优先排查层 |
|---|---|
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