Skip to content

第十部分: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 kube

10.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:2379

10.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-containers

containerd 架构:

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 pods

10.5 本章小结

核心概念关键要点
apiserver 请求链认证 → 授权 → 变更准入 → 格式校验 → 验证准入 → 写入 etcd
etcd Raft奇数节点、多数派写入、Leader 选举
Reconciliation Loop声明式核心模式:Watch → Diff → Act
Level-triggered只看状态差异,不依赖事件序列,天然自愈
InformerList-Watch + DeltaFIFO + Indexer,K8s 的神经系统
调度框架Filter → Score → Reserve → Permit → Bind
CRIkubelet ↔ containerd ↔ runc,OCI 标准化

练习

  1. 在一个测试集群上执行 etcdctl endpoint status,确认 Leader 和各节点的数据库大小。
  2. 使用 kubectl get --raw /metrics 查看 apiserver 的请求延迟指标。
  3. 编写一个 ValidatingAdmissionWebhook,拒绝所有未设置 resource limits 的 Pod。
  4. 对比 kubectl applykubectl replace 的行为差异,解释为什么生产环境应使用 apply。

下一章:第十一部分:Pod 与工作负载深度解析