Kubernetes 架构解剖:从 Node 到 Control Plane 的完整通信路径
文章目录
引言
大多数 Kubernetes 入门文章把集群组件拆成两类平行介绍:Control Plane 有什么、Node 上有什么。读完能记住"API Server 是入口"“etcd 存数据”“Kubelet 在节点上”——但问起"一个 Pod 从提交 YAML 到真正跑起来,中间经历了什么",往往答不上来。
本文换一个角度:从一次完整的 Pod 创建出发,沿调用链路追踪每个组件的职责与协作方式。每一步都给出具体的数据流向和命令验证方法。读完之后,"K8s 架构"不再是一张静态架构图,而是一条活的通信路径。
一、组件总览与核心职责
在进入调用链路之前,先梳理 Control Plane 和 Node 上各自有哪些组件,以及它们各自的角色。
etcd:整个集群的持久化存储,键值对形式保存所有资源对象。所有组件的状态最终都落在这里。
API Server:集群的唯一入口。所有组件(kubectl、Scheduler、Controller Manager、Kubelet)都只与 API Server 通信,不直接访问 etcd。API Server 本身是无状态的,会话状态存在 etcd 里。
Controller Manager:包含多个内置控制器(Deployment、ReplicaSet、Endpoint、ServiceAccount 等),每个控制器都是一条独立的控制循环,持续对比"期望状态"与"实际状态"。
Scheduler:监听未调度的 Pod,为其选择一个最优节点。它只负责决策,不负责执行——选好节点之后,把 nodeName 字段写回 API Server,剩下的事交给目标节点的 Kubelet。
Kubelet:运行在每个节点上的代理。负责向 API Server 注册节点、管理 Pod 的完整生命周期(从下载镜像到启动容器),以及报告节点和 Pod 状态。
Kube-proxy:负责维护节点上的网络规则(iptables 或 IPVS),实现 Service 的负载均衡。Kubelet 和 Kube-proxy 的职责容易混淆:Kubelet 管理 Pod 本身,Kube-proxy 管理 Pod 之外的 Service 流量。
二、Pod 创建完整时序
下面是最关键的部分。一个 kubectl apply -f pod.yaml 提交之后,集群内部发生了什么?
这张图涵盖了四个核心机制:API Server 的 etcd 写入、Scheduler 的 Watch + Filter/Score 决策、Kubelet 的 CRI 调用,以及状态回写的完整闭环。下面逐一展开。
三、API Server 的三层入口
API Server 接收请求后,经过认证(Authentication)、授权(Authorization)、准入控制(Admission Control)三层处理:
认证层:支持客户端证书(x.509)、Bearer Token、OIDC 等多种方式。kubectl 默认使用 x.509 客户端证书,证书信息(CN=用户名、O=用户组)会在这一步解析出来。
授权层:基于 RBAC(Role-Based Access Control)。如果请求方的 ServiceAccount 没有对应 Role 绑定的权限,直接返回 403 Forbidden。
准入控制层:最有意思的部分。内置插件包括:
LimitRanger:强制 Pod 必须声明 Resource Request/Limit(未声明的 Pod 默认值为零,生产环境建议配合 LimitRange 设置默认配额)。ResourceQuota:检查命名空间总资源是否超配额。MutatingAdmissionWebhook:在写入 etcd 前修改对象(如自动注入 sidecar 容器)。ValidatingAdmissionWebhook:在写入 etcd 前验证对象(如 OPA/Gatekeeper 的策略检查)。
三层全部通过后,请求才会写入 etcd。任何一个环节拒绝,请求都不会到达 etcd——这是 K8s 安全的纵深防御设计。
四、Scheduler 的调度决策
Scheduler 并不是一次性完成调度的。它通过 Watch 机制持续监听 API Server,收到未调度 Pod 的事件后,进入两阶段决策:Filter(预选)和Score(优选)。
Filter 阶段会并行执行多个过滤条件(Predicates),任何一个条件不满足,节点直接被淘汰。常见条件包括:
PodFitsResources:节点剩余 CPU/内存是否满足 Pod 的 Resource RequestPodFitsHostPorts:目标端口是否被占用(hostPort独占)NoDiskConflict:存储卷是否冲突MatchNodeSelector:节点 Label 是否满足nodeSelector或nodeAffinityNoUnschedulable:节点不能有node.kubernetes.io/unreachable标签
Score 阶段对通过 Filter 的节点打分,分数最高的节点胜出。K8s 1.26 之后,Scheduler 架构从旧的 Predicates/Priorities 模型迁移到了 Scheduling Framework,Filter 和 Score 成为标准扩展点:
| 旧术语 | 新术语 | 说明 |
|---|---|---|
| Predicate | Filter | 过滤不合格节点 |
| Priority | Score | 为合格节点打分 |
默认的 Score 插件包括:
LeastRequestedPriority:优先调度到资源使用率低的节点MostRequestedPriority:优先调度到资源使用率高的节点(适合批量任务)ImageLocalityPriority:如果镜像已经在节点上,会给高分(减少拉镜像时间)
K8s 1.26 之后,调度器引入了 Scheduler Framework,支持在 Filter 和 Score 之间插入自定义插件(通过 kube-scheduler 的 --config 指定)。如果默认策略不够用,可以写一个自定义插件注册进去,而不是用旧的 Extender API(后者性能差,因为需要额外的 HTTP 调用)。
验证调度决策
调度完成之后,Pod 的 nodeName 字段被填充。可以用以下命令验证:
# 查看 Pod 当前状态,spec.nodeName 已填充说明调度完成
kubectl get pod nginx -o jsonpath='{.spec.nodeName}'
# 查看 Pod 的调度事件(谁调度了它)
kubectl describe pod nginx | grep -A5 "Events:"
# 查看调度器的调度决策日志(需要调度器开启了 verbose 日志)
kubectl logs -n kube-system kube-scheduler-<node-name> --tail=50 | grep nginx
# 如果 Pod 一直处于 Pending 状态,查看原因
kubectl describe pod nginx | grep -A10 "Conditions:"
# 常见原因:
# - No nodes available(资源不足)
# - 0/N nodes are available(Filter 阶段全部淘汰)
五、Controller Manager 的控制器链路
Pod 调度完成之后,Kubelet 还没来得及创建容器,Controller Manager 的控制器们已经开始工作了。其中最核心的是 Endpoints Controller 和 ReplicaSet Controller。
ReplicaSet Controller:监听 Deployment 的期望副本数,确保集群中始终有指定数量的 Pod 副本运行。当某个 Pod 被删除或节点宕机时,它会自动创建新 Pod 来补齐。
Endpoints Controller:这往往是入门文章里最容易被忽略的。Endpoints Controller 监听所有 Pod 的变化(创建/删除/状态变更),实时维护每个 Service 对应的 Endpoints 对象。Endpoints 对象的结构是:Service 名称 → 一组 Pod IP + 端口。
关键点在于:Endpoints 对象是 Kube-proxy 更新网络规则的直接依据。如果 Endpoints Controller 没有及时更新(Pod 卡在 Pending、或者控制器与 API Server 之间 Watch 断开),Service 会突然失去后端 Pod,流量直接打空。
# 查看某 Service 的 Endpoints(即后端 Pod 列表)
kubectl get endpoints nginx-service -o yaml
# 对比 Endpoints 和实际 Pod IP 是否一致
kubectl get pods -l app=nginx -o jsonpath='{range .items[*]}{.status.podIP}{"\n"}{end}'
# 如果 Endpoints 为空但 Pod 正在运行,说明 Endpoints Controller 有问题
# 检查 Controller Manager 日志
kubectl logs -n kube-system kube-controller-manager-<node-name> --tail=20 | grep endpoint
六、Kubelet 与容器运行时
调度完成后,目标节点的 Kubelet 收到了 Watch 推送,开始执行 Pod 的实际创建。整个过程通过 CRI(Container Runtime Interface)接口与容器运行时通信。
**CRI(Container Runtime Interface)**是 Kubelet 与容器运行时之间的标准化接口。容器运行时负责实际的操作:拉取镜像、创建网络命名空间、启动容器。常见的实现有:
- containerd:Docker 默认使用的运行时,CNCF 毕业项目
- cri-o:专门为 K8s 设计的轻量级运行时
- Docker(dockershim):K8s 1.24 之前内置的 shim,已在 K8s 1.24 中移除
K8s 1.24 移除了内置的 dockershim,这意味着使用 Docker 作为容器运行时的集群需要显式安装 docker-shim 或迁移到 containerd。这是一个经常被忽视的升级陷阱——如果集群使用 kubeadm 搭建且运行时为 Docker,升级到 1.24 之前必须完成迁移。
Pause 容器是每个 Pod 都会首先创建的"基础设施容器"。它的唯一目的是:持有 Pod 的网络命名空间(network namespace),让 Pod 内的所有业务容器共享同一个网络栈,而不需要每个容器都单独配置网络。当业务容器崩溃重启时,Pause 容器保持不变,Pod IP 不会变化——这是 K8s Service 稳定性的底层保障之一。
验证 Kubelet 的 Pod 创建过程
# 查看节点上所有容器(crictl 是 containerd 的 CLI)
crictl ps -a --name=nginx
# 查看 Pod 的详细启动日志(由 Kubelet 写入)
kubectl describe pod nginx | grep -A20 "Events:"
# 查看 Kubelet 日志(排查镜像拉取失败、OOM 等问题)
sudo journalctl -u kubelet --since "10 minutes ago" | grep nginx
# 查看节点磁盘空间(镜像拉取失败常见原因)
df -h /var/lib/docker # Docker
df -h /var/lib/containerd # containerd
七、etcd 在整个链路中的位置
虽然 etcd 出现在架构图里,但大多数入门文章只说"etcd 存数据",没有说明它在 Pod 创建链路中扮演的具体角色。
需要特别注意的是:etcd 不仅仅是"存放最终状态"的被动存储,它同时是 Controller Manager 的 Watch 数据源。Controller Manager 并不依赖 API Server 推送事件,而是直接 Watch etcd 的变更(API Server 是 etcd 的 Watch 代理)。当 etcd 中某个 key 发生变化时,Watch 链立即触发相关控制器的逻辑。
这带来一个运维层面的重要结论:etcd 的性能直接决定了整个集群的响应速度。etcd 的写入延迟通常要求在 1ms 以内,如果 etcd 所在磁盘发生 I/O 争用(例如与其他进程共享 SSD),API Server 的请求会开始排队,Pod 创建延迟从毫秒级跳升到秒级。
# 查看 etcd 写入延迟(etcd pod 内)
kubectl exec -it -n kube-system etcd-<node-name> -- etcdctl endpoint status --write-out=table
# 查看 etcd 的 wal_fsync_duration_seconds(磁盘同步延迟)
kubectl exec -it -n kube-system etcd-<node-name> -- etcdctl endpoint status | grep "db size"
# 检查 etcd 磁盘健康(etcd 强烈建议使用独立 SSD)
kubectl exec -it -n kube-system etcd-<node-name> -- df -h /var/lib/etcd
八、架构全景:一条请求的完整生命周期
把所有组件串起来,得到一个完整的请求生命周期:
整个链路在正常情况下耗时约 5~15 秒,主要瓶颈在镜像拉取(首次部署时镜像较大)和容器启动时间。如果镜像已经在节点上(ImageLocality 调度器优先派到已有镜像的节点),整个 Pod 创建过程可以压缩到 2 秒以内。
九、快速验证命令清单
以下命令覆盖了 Pod 创建链路每个阶段的排查:
# ① API Server 是否收到请求
kubectl auth can-i create pods --namespace default
# ② Pod 是否已在 etcd 中
kubectl get pod nginx --watch &
kubectl apply -f pod.yaml
# ③ Scheduler 是否分配了节点
kubectl get pod nginx -o wide
# ④ Kubelet 是否开始创建容器(节点侧)
ssh <node> "crictl ps | grep nginx"
# ⑤ Pod 是否达到 Running 状态
kubectl get pod nginx -o jsonpath='{.status.phase}'
# ⑥ Endpoints 是否正确填充
kubectl get endpoints nginx-svc
# ⑦ Kube-proxy 规则是否生效
ssh <node> "iptables -L -t nat | grep nginx | head -20"
# ⑧ 如果 Pod 卡在 Pending,查看详细原因
kubectl describe pod nginx | grep -E "Conditions|Events:"
kubectl get pod nginx -o jsonpath='{.spec.schedulerName}'
# ⑨ 检查 etcd 是否正常(API Server 和 Controller Manager 依赖它)
kubectl get pods -n kube-system | grep etcd
十、总结
K8s 架构的核心不是"有哪些组件",而是组件之间通过 API Server + etcd Watch 机制串联成的协作网络:
- API Server 是唯一的写入入口,认证、授权、准入控制三层全部通过才会写入 etcd。
- etcd 是唯一的真相来源,Controller Manager 和 Scheduler 都通过 Watch etcd 来感知集群状态变化,而不是依赖彼此直接通信。
- Scheduler 只做决策,把
nodeName写回 API Server 就完成任务,不负责后续的 Pod 创建。 - Kubelet 只对自己节点的 Pod 负责,通过 CRI 与容器运行时交互,创建出真正的容器。
- Pause 容器是 Pod 网络稳定性的保障,理解它就能理解为什么 Pod 重启后 IP 不变。
- Endpoints Controller 经常被忽视,但它是 Service 与后端 Pod 之间的关键桥梁。
理解了这六点,K8s 的"架构"就不再是一张静态图片,而是一条随时可以在生产环境中用命令追踪的活路径。
如果觉得这篇文章有帮助,欢迎收藏、转发。
相关阅读
更多推荐

所有评论(0)