主题
第十部分:Kubernetes 核心架构深度解析
本章从源码和工程实践角度深入剖析 K8s 核心架构,帮助你建立超越"会用"层面的系统认知。
10.1 控制平面组件深度剖析
10.1.1 kube-apiserver:集群的唯一入口
kube-apiserver 是 K8s 所有操作的唯一入口,理解它的请求处理流程是高级运维的基础:
客户端请求
↓
① Authentication(认证)—— 你是谁?
→ X509 证书 / Bearer Token / OIDC / Webhook
↓
② Authorization(授权)—— 你能做什么?
→ RBAC / ABAC / Node / Webhook
↓
③ Mutating Admission(变更准入)—— 修改你的请求
→ MutatingAdmissionWebhook、LimitRanger、ServiceAccount 注入等
↓
④ Schema Validation(格式校验)
→ OpenAPI Schema 校验资源字段合法性
↓
⑤ Validating Admission(验证准入)—— 业务规则校验
→ ValidatingAdmissionWebhook、ResourceQuota 等
↓
⑥ 写入 etcd关键设计:API 聚合层(API Aggregation)
K8s 支持通过 API 聚合层扩展 apiserver,注册自定义 API Server(如 metrics-server、cert-manager),使第三方资源以"一等公民"的方式出现在 K8s API 中。
bash
# 查看当前注册的聚合 API
kubectl get apiservices | grep -v kube10.1.2 etcd:集群的大脑
etcd 基于 Raft 共识算法,是 K8s 唯一的持久化存储。
Raft 协议核心要点:
| 概念 | 说明 |
|---|---|
| Leader | 处理所有写请求,负责日志复制 |
| Follower | 被动接收 Leader 的日志复制 |
| Candidate | 发起选举的节点 |
| Quorum | 多数派(N/2+1),写操作需要多数节点确认 |
| Term | 逻辑时钟,每次选举递增 |
为什么 etcd 节点数必须是奇数?
容错能力公式:最大容忍故障节点数 = (N-1)/2
- 3 节点:容忍 1 个故障
- 5 节点:容忍 2 个故障
- 偶数(如 4 节点)和 3 节点容错能力相同(都是容忍 1 个),但增加了写入延迟
etcd 运维要点:
bash
# 健康检查
etcdctl endpoint health --cluster
# 性能检查(写延迟应 < 10ms)
etcdctl endpoint status --cluster -w table
# 备份
etcdctl snapshot save /backup/etcd-$(date +%Y%m%d).db
# 恢复(会创建新集群)
etcdctl snapshot restore /backup/etcd.db \
--name=etcd-0 \
--initial-cluster=etcd-0=https://10.0.0.1:2380 \
--data-dir=/var/lib/etcd
# 碎片整理(减少存储占用,提升性能)
etcdctl defrag --endpoints=https://10.0.0.1:237910.1.3 kube-scheduler:调度框架
调度器采用插件化架构,核心流程:
SchedulingQueue(优先级队列)
↓
PreFilter Plugins(预处理,如检查 PVC 是否就绪)
↓
Filter Plugins(过滤不可用节点)
→ NodeResourcesFit / NodeAffinity / TaintToleration
→ PodTopologySpread / NodeUnschedulable
↓
Score Plugins(打分,0-100)
→ LeastAllocated / BalancedAllocation / InterPodAffinity
↓
Reserve Plugins(预留资源)
↓
Permit Plugins(允许/等待/拒绝)
↓
PreBind Plugins(绑定前操作,如挂载 Volume)
↓
Bind(绑定 Pod 到 Node)
↓
PostBind Plugins(通知,如更新调度缓存)10.1.4 kube-controller-manager:控制循环
核心设计模式——Reconciliation Loop(调谐循环):
期望状态(Desired State,来自 etcd)
↕ 对比差异
实际状态(Actual State,来自集群观察)
↓ 执行动作
调谐(Reconcile)Level-triggered vs Edge-triggered:
这是 K8s 架构最精妙的设计之一:
- Edge-triggered(边缘触发):基于事件通知,错过事件就丢失状态(如传统消息队列)
- Level-triggered(水平触发):只看当前状态和期望状态的差异,不依赖事件序列
这意味着:即使 kubelet 重启错过了若干 Pod 事件通知,重启后重新比对当前状态和期望状态,依然能自愈。
10.2 Informer 机制:K8s 的神经系统
Informer 是 K8s 内部各组件获取资源变更的核心机制:
apiserver
↓ Watch
Reflector(List-Watch)
↓
DeltaFIFO(变更队列)
↓ ↓
Pop 取出 本地缓存(Indexer)
↓ ↓
事件处理器 按字段索引查询
(Add/Update/Delete) (避免频繁访问 etcd)关键设计:
- List-Watch:初始全量 List,之后增量 Watch,保证不遗漏
- DeltaFIFO:记录变更类型(Added/Updated/Deleted),保证有序
- Indexer:基于内存的本地缓存 + 自定义索引函数,查询复杂度 O(1)
- 资源版本(ResourceVersion):用于断点续 Watch,避免重复推送
生产调优要点:
yaml
# apiserver 参数调优(大规模集群)
--max-requests-inflight=3000 # 非 mutating 请求并发
--max-mutating-requests-inflight=1000
--watch-cache-sizes=resource#1000 # Watch 缓存大小10.3 声明式 API 与 kubectl apply 全流程
从 kubectl apply -f deployment.yaml 到 Pod Running 的完整链路:
1. kubectl 将 YAML 序列化为 JSON,发送 HTTPS 请求到 kube-apiserver
2. apiserver 处理链路:
Authentication → Authorization → MutatingAdmission →
SchemaValidation → ValidatingAdmission
3. apiserver 将 Deployment 资源写入 etcd
4. Deployment Controller 通过 Informer Watch 到变更
→ 创建 ReplicaSet,ReplicaSet Controller 创建 Pod 对象写入 etcd
5. Scheduler Watch 到 Pending 状态的 Pod
→ 执行调度算法(Filter → Score → Bind),写入 nodeName
6. 目标节点的 kubelet Watch 到有 nodeName 指向自己的 Pod
→ 通过 CRI 调用 containerd 创建容器
7. kubelet 上报 Pod 状态给 apiserver,状态变为 Running
8. kube-proxy 更新 Service 端点(iptables/IPVS 规则)
9. CoreDNS 更新 DNS 记录kubectl apply 的三方合并(Three-way Merge):
kubectl apply 计算差异时涉及三方:
- Last Applied(上次 apply 的配置,存储在 annotation 中)
- Current(当前 etcd 中的实际配置)
- Desired(本次 apply 的新配置)
合并逻辑:
- Desired 有、Current 无 → 新增
- Desired 无、Current 有、Last Applied 有 → 删除(用户主动移除)
- Desired 无、Current 有、Last Applied 无 → 保留(可能是其他控制器设置的)10.4 容器运行时与 CRI
K8s 通过 CRI(Container Runtime Interface)与容器运行时解耦:
kubelet
↓ CRI(gRPC)
↓
Container Runtime(containerd / CRI-O)
↓ OCI(Open Container Initiative)
↓
runc / crun / kata-containerscontainerd 架构:
kubelet → CRI gRPC → containerd
├── shim-v2(每个 Pod 一个)
│ └── runc → 容器进程
├── 镜像管理(pull/push)
├── 存储管理(snapshotter)
└── 网络管理(通过 CNI)为什么 Docker 被弃用?
Docker 不是 CRI 兼容的运行时,kubelet 需要通过 dockershim 适配。K8s 1.24 起移除 dockershim,直接使用 containerd 或 CRI-O 更高效。
bash
# 检查节点容器运行时
kubectl get nodes -o wide
# 查看 containerd 状态
crictl info
crictl pods10.5 本章小结
| 核心概念 | 关键要点 |
|---|---|
| apiserver 请求链 | 认证 → 授权 → 变更准入 → 格式校验 → 验证准入 → 写入 etcd |
| etcd Raft | 奇数节点、多数派写入、Leader 选举 |
| Reconciliation Loop | 声明式核心模式:Watch → Diff → Act |
| Level-triggered | 只看状态差异,不依赖事件序列,天然自愈 |
| Informer | List-Watch + DeltaFIFO + Indexer,K8s 的神经系统 |
| 调度框架 | Filter → Score → Reserve → Permit → Bind |
| CRI | kubelet ↔ containerd ↔ runc,OCI 标准化 |
练习
- 在一个测试集群上执行
etcdctl endpoint status,确认 Leader 和各节点的数据库大小。 - 使用
kubectl get --raw /metrics查看 apiserver 的请求延迟指标。 - 编写一个 ValidatingAdmissionWebhook,拒绝所有未设置 resource limits 的 Pod。
- 对比
kubectl apply和kubectl replace的行为差异,解释为什么生产环境应使用 apply。