写在前面
承接前八篇。前面讲了 Pod/Deployment/Service/配置/调度/安全/运维——都是"资源怎么用"。本篇补上地基:K8s 到底由哪些组件组成、各自干什么。
篇1 的架构概览只列了组件名,这篇把每个组件掰开讲透:控制平面、工作节点、插件体系。理解组件,才能看懂下一篇(篇10)的调用链路——一次 kubectl apply、一次外部请求,在组件之间到底怎么流转;也才能排查"Pod 没调度上"“Service 不通"这类深层问题。
一、K8s 架构总览
K8s 是主从架构:一个控制平面(Control Plane,俗称 master)管着一堆工作节点(Worker Node)。控制平面是"大脑”,工作节点是"手脚"。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| ┌─────────────────────────────────┐
│ Control Plane(控制平面) │
│ ┌──────────┐ ┌───────────────┐ │
│ │apiserver │ │ etcd │ │
│ └──────────┘ └───────────────┘ │
│ ┌────────────┐ ┌─────────────┐ │
│ │ scheduler │ │ controllers │ │
│ └────────────┘ └─────────────┘ │
└─────────────────────────────────┘
▲
kubectl / 应用 / 组件 都走 apiserver
▼
┌──────────────┬──────────────┬──────────────┐
▼ ▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
│ Worker1 │ │ Worker2 │ │ Worker3 │ │ ... │
│ kubelet │ │ kubelet │ │ kubelet │ │ │
│kube-proxy│ │kube-proxy│ │kube-proxy│ │ │
│ runtime │ │ runtime │ │ runtime │ │ │
│ Pods │ │ Pods │ │ Pods │ │ │
└─────────┘ └─────────┘ └─────────┘ └─────────┘
|
三类角色:
- 控制平面组件:决策(调度、reconcile)、存状态(etcd)、对外暴露 API(apiserver)
- 工作节点组件:执行(跑 Pod、转发流量)
- 插件(addons):必需但不在核心二进制里,以 Pod 形式跑在
kube-system 命名空间
二、控制平面(Control Plane)
2.1 kube-apiserver —— 唯一入口
整个集群唯一的对外接口。所有操作(kubectl、组件间通信、dashboard、CI/CD)都通过它。
1
2
3
4
5
6
7
| 职责:
✓ RESTful API(HTTPS),所有资源的 CRUD
✓ 认证(你是谁)→ 授权(你能干啥,RBAC)→ 准入(改不改请求体)
✓ 唯一能直接读写 etcd 的组件
✓ 无状态(状态全在 etcd),可水平扩展(多实例 + LB)
口诀:apiserver 是"前台",etcd 是"账本",前台不存钱只转手
|
为什么所有组件都走 apiserver 而不直接读写 etcd?因为 apiserver 做认证 / 授权 / 准入 / 校验 / 乐观锁 / 审计 / watch 机制——这些不该让每个组件自己实现。集中到 apiserver,安全且一致。
2.2 etcd —— 集群的大脑
强一致性的键值存储,K8s 把所有集群状态(有哪些 Pod / Service / 节点 / 配置…)都存在 etcd 里。
1
2
3
4
5
6
7
| 特点:
✓ KV 存储(不是关系库),key 按资源路径组织
✓ Raft 共识协议:强一致(写要多数节点确认)
✓ 整个集群唯一有状态的组件 → 必须备份!
✓ etcd 挂了 = 集群失忆(apiserver 读不到现状,但已跑的 Pod 不影响)
备份:etcdctl snapshot save;恢复 = 从快照重建
|
etcd 是 K8s 的"唯一真相源"。控制平面其他组件(apiserver / scheduler / controller)都是无状态的——它们从 apiserver(背后是 etcd)读状态、写期望。所以etcd 备份 = 集群备份。
2.3 kube-scheduler —— 决定 Pod 跑在哪
新 Pod 创建后(还没绑定节点),scheduler 负责"给它选一个节点"。
1
2
3
4
5
6
7
| 调度两步:
1. 过滤(Filter):哪些节点能用?(资源够、亲和、污点容忍、nodeSelector)
2. 打分(Score):能用里挑最优(资源均衡、亲和优先、反亲和)
选定后 → 写 Pod 的 nodeName(绑定),交给 kubelet 去起
注意:scheduler 只"决定",不"启动"——启动是 kubelet 的活
|
Pod 卡在 Pending 多半是 scheduler 没找到合适节点(资源不足 / 亲和冲突 / 污点)。kubectl describe pod 看 Events 里的 FailedScheduling 是关键线索。
2.4 kube-controller-manager —— 调谐循环
跑一堆控制器,每个控制器管一类资源,核心是 reconcile(调谐)循环:持续观察"实际状态",趋近"期望状态"。
1
2
3
4
5
6
7
8
9
10
11
12
13
| 内置控制器(部分):
Deployment Controller → 维持 N 个副本、滚动更新
ReplicaSet Controller → 维持 Pod 副本数(Deployment 底层用它)
Node Controller → 节点失联检测、标记 NotReady
Endpoint Controller → 维护 Service 的 Endpoints(哪些 Pod)
ServiceAccount Controller → 保证每个 ns 有默认 SA
Job / CronJob Controller → 批处理任务的完成 / 重试
统一模式:
期望状态(存在 etcd,如 replicas: 3)
↕ reconcile
实际状态(从 apiserver 观察到的运行 Pod 数)
不一致 → 创建 / 删除 Pod,直到匹配
|
这是 K8s “声明式"的本质:你声明 replicas: 3,controller 替你维持。Pod 挂了它补,多了它删——你不用写"创建 3 个 Pod"的命令,只声明期望。
2.5 cloud-controller-manager —— 云特定逻辑
把"和云厂商打交道"的逻辑从核心分离(节点管理 / 负载均衡 / 路由)。这样 K8s 核心不知道"是 Azure 还是 AWS”,云厂商各自实现自己的 CCM。
1
2
3
4
| 内部控制器:
Node Controller → 给云上 VM 打标签、检查存活
Route Controller → 配置云路由(Pod 网段到节点)
Service Controller → 创建云 LoadBalancer(type=LoadBalancer 时)
|
自建集群通常不跑 CCM;云托管(AKS/EKS/GKE)一定跑——type=LoadBalancer 的 Service 就是 CCM 调云 API 建的。
三、工作节点(Worker Node)
3.1 kubelet —— 节点代理
每个节点上跑一个,管这个节点上的 Pod。
1
2
3
4
5
6
7
8
| 职责:
✓ 接收 apiserver 下发的 Pod 清单("这个节点该跑哪些 Pod")
✓ 调 container runtime(CRI)起 / 停容器
✓ 执行健康检查(liveness / readiness probe)
✓ 上报节点 / Pod 状态给 apiserver("这个 Pod Running / 这个节点 CPU 60%")
✓ 挂载 volume
口诀:kubelet 是节点上的"包工头",按 apiserver 的图施工、汇报进度
|
3.2 kube-proxy —— 服务转发
每个节点上跑一个,负责 Service 的网络规则。
1
2
3
4
5
6
7
8
| 职责:
✓ 监听 Service / Endpoints 变化
✓ 在节点上维护 iptables 或 ipvs 规则:
访问 Service 的 ClusterIP → DNAT 到某个 Pod IP
✓ 默认 iptables 模式(小集群),大规模用 ipvs(性能好)
注意:kube-proxy 不真正转发流量(那是内核 netfilter 干的)
它只是"写规则的人",规则匹配后内核改目的地址
|
Service 的 ClusterIP 是个"虚拟 IP",没有真实网卡。流量能到 Pod,全靠每个节点上 kube-proxy 写的 iptables / ipvs 规则做 DNAT。篇10 数据面链路会详演。
3.3 container runtime —— 跑容器
真正启动容器的组件,通过 CRI(Container Runtime Interface)和 kubelet 交互。
1
2
3
4
5
6
| 主流 runtime:
containerd ← 当前主流(Docker 内核部分独立出来)
CRI-O ← Red Hat 系(OpenShift 默认)
Docker ← 已弃(K8s 1.24 起移除 dockershim),新集群别用
K8s 不关心你用哪个 runtime,只要实现 CRI 接口
|
“K8s 不再支持 Docker"的真相:K8s 通过 CRI 调 runtime,Docker 曾需要 dockershim 适配,1.24 移除了 shim。但 Docker 构建的镜像(OCI 格式)任何 runtime 都能跑——镜像照用,只是 K8s 不直接调 Docker daemon 了。
四、组件协作一览
1
2
3
4
5
6
7
8
9
10
11
| kubectl apply → apiserver → etcd(存期望)
↓ watch
controller-manager(看到要 3 副本,创建 Pod 对象)
↓ watch
scheduler(给 Pod 选节点,写 nodeName)
↓ watch
目标节点的 kubelet(收到,调 runtime 起容器)
↓
kube-proxy(Service 变了,更新 iptables)
↓
Pod 跑起来,Service 可访问
|
每个组件都是独立被动的——它们不互相直接调用,而是通过 watch apiserver(背后 etcd)感知变化、各自干活。这种"事件驱动 + watch"的解耦是 K8s 架构的精髓。完整链路留篇10 详演。
五、插件体系(Addons)
addons 是"集群跑起来必需、但不在核心二进制里"的组件,以 Pod / DaemonSet 形式跑在 kube-system 命名空间。
1
2
3
4
5
| 什么是 addon:
✓ 不是 K8s 核心(不在 kubelet / apiserver 等二进制里)
✓ 但集群要正常工作离不开它们(DNS、网络、监控)
✓ 通常以 Deployment / DaemonSet 部署在 kube-system
✓ 可替换(CNI 选 Calico 还是 Cilium,DNS 用 CoreDNS 还是别的)
|
5.1 CoreDNS —— 集群 DNS
1
2
3
4
5
6
7
| 职责:Service 名字解析
访问 http://web-app → 同 ns 内解析到 Service ClusterIP
访问 http://web-app.default → 跨 ns 显式指定
访问 web-app.default.svc.cluster.local → 完整 FQDN
形式:Deployment(2 副本)+ Service,跑在 kube-system
没它:Service 名字不通,只能用 IP(痛苦)
|
5.2 CNI —— Pod 网络
1
2
3
4
5
6
| 职责:给 Pod 分配 IP + 跨节点 Pod 互通
主流:Calico(BGP / 网络策略强)、Cilium(eBPF,新锐)、Flannel(简单老牌)
云托管:Azure CNI / Amazon VPC CNI / GKE alias(Pod 拿 VPC IP)
没它:Pod 拿不到 IP、跨节点 Pod ping 不通
K8s 核心(apiserver 等)不管网络——网络全是 CNI 插件干的
|
CNI 的对比详见本站「云托管 K8s 实战」系列,以及本系列网络篇(04)。
5.3 Metrics Server —— 指标源
1
2
3
4
5
| 职责:聚合各节点资源用量(CPU / 内存),通过 Metrics API 暴露
下游:HPA(按 CPU 扩缩)、kubectl top(看节点 / Pod 占用)
没它:HPA 不工作、kubectl top 报错
形式:单 Pod,从 kubelet 的 summary API 抓数据
|
5.4 Ingress Controller —— 七层入口
1
2
3
4
5
| 职责:把外部 HTTP / HTTPS 流量按 Host / Path 路由到 Service
主流:NGINX Ingress(最常见)、Traefik、HAProxy、云厂商 Ingress
本质:一个反向代理 Pod + 读 Ingress 资源动态配置
没它:Ingress 资源没人执行(声明了也没用)
|
5.5 CSI —— 存储插件
1
2
3
4
5
| 职责:对接具体存储后端(云盘、NFS、Ceph、分布式存储)
三阶段:Provision(建卷)→ Attach(挂到节点)→ Mount(挂进 Pod)
形式:一堆组件(Controller / Node Plugin)以 Pod 跑
没它:PV / PVC 只能用手动建好的静态卷;动态分配靠 CSI
|
5.6 其他常见 addon
1
2
3
4
| Dashboard Web UI(生产慎开,安全风险)
认证 Webhook 扩展认证授权(对接 LDAP/OIDC)
Cluster Autoscaler 节点自动扩缩(节点不够加机器)
cert-manager 自动 TLS 证书(Let's Encrypt 等)
|
六、实地看:kubectl get pods -n kube-system
1
2
3
4
5
6
7
8
9
10
| kubectl get pods -n kube-system
# NAME READY STATUS AGE
# coredns-xxx-xxx 1/1 Running 10d ← CoreDNS addon
# etcd-master 1/1 Running 10d ← 控制平面(静态 Pod)
# kube-apiserver-master 1/1 Running 10d ← 控制平面(静态 Pod)
# kube-controller-manager-master 1/1 Running 10d ← 控制平面(静态 Pod)
# kube-proxy-xxxxx 1/1 Running 10d ← DaemonSet(每节点一个)
# kube-scheduler-master 1/1 Running 10d ← 控制平面(静态 Pod)
# metrics-server-xxx-xxx 1/1 Running 10d ← Metrics addon
# calico-node-xxxxx 1/1 Running 10d ← CNI(DaemonSet)
|
几个现象:
- 控制平面组件是"静态 Pod”(由 kubelet 直接管,清单在
/etc/kubernetes/manifests),自建集群如此;云托管的控制平面你看不到(微软 / AWS / Google 替你跑了)。 - kube-proxy / CNI 是 DaemonSet(每节点一个)。
- addons 是普通 Deployment / DaemonSet。
七、小结
1
2
3
4
5
6
7
8
9
10
11
12
13
| K8s 组件全景:
控制平面(决策 + 存状态)
apiserver 唯一入口,认证授权
etcd 集群状态库(唯一有状态,必须备份)
scheduler Pod 选节点
controller-manager reconcile 循环维持期望
cloud-controller-manager 云特定逻辑
工作节点(执行)
kubelet 管 Pod 生命周期
kube-proxy 写 Service 转发规则(iptables / ipvs)
runtime 跑容器(containerd / CRI-O)
插件(以 Pod 跑在 kube-system)
CoreDNS / CNI / Metrics Server / Ingress Controller / CSI / ...
|
1
2
3
4
5
| 核心认知:
✓ 所有组件通过 apiserver(背后 etcd)通信,互相 watch,不直连
✓ 声明式 = 你写期望状态,controller / scheduler 替你维持
✓ apiserver 无状态可横扩;etcd 唯一有状态,是命脉
✓ 网络全靠 CNI、DNS 全靠 CoreDNS——K8s 核心不管这些
|
下一篇:调用链路深挖——一次 kubectl apply 在组件间怎么流转(管理面),一次外部 HTTP 请求怎么从公网打到 Pod(数据面),把本篇的组件全串起来。