06-Kubelet 源码解析:从启动到 Pod 管理与指标监控
本文基于1.29.0版本
Kubelet 源码解析:从启动到 Pod 管理与指标监控
摘要
Kubelet 是 Kubernetes 集群中不可或缺的节点代理,负责管理 Pod 的生命周期、监控资源并确保节点上的容器按照预期状态运行。本文旨在通过对 Kubelet 源码的深度剖析,揭示其核心工作机制,内容涵盖从启动初始化、核心工作循环、Pod 生命周期管理到基于 cAdvisor 的指标监控全流程。通过对这些关键模块的分析,我们将构建一个关于 Kubelet 如何作为节点"管家"维持集群稳定性的完整视图。
1. Kubelet 的职责与定位
在 Kubernetes 的宏伟蓝图中,Kubelet 扮演着连接"大脑"(Master 节点)与"四肢"(工作节点)的关键角色。它的核心职责可以概括为:
- Pod 管理:作为 Pod 生命周期的直接执行者,负责根据
kube-apiserver的指令或静态配置文件创建、销毁和管理 Pod。 - 健康检查:通过 Liveness 和 Readiness 探针持续监控容器的健康状况,并执行重启等恢复策略。
- 资源监控:利用内嵌的 cAdvisor 收集节点和容器的资源使用情况(CPU、内存、磁盘、网络),为
metrics-server和 HPA 提供数据基础。 - 存储卷管理:为 Pod 动态挂载和卸载所需的存储卷。
- 状态上报:定期向
kube-apiserver汇报节点状态、资源容量和运行中的 Pod 列表。
2. 启动流程:从 main 函数到 syncLoop
Kubelet 的启动过程是一个精心设计的初始化序列,它通过命令行解析、配置加载和依赖注入,最终构建出一个功能完备的 Kubelet 实例。
2.1. 入口与命令构建
Kubelet 的生命始于 cmd/kubelet/kubelet.go 的 main 函数,它通过调用 app.NewKubeletCommand() 创建一个 Cobra 命令行应用。这个过程封装了所有启动逻辑,包括参数解析和服务的最终运行。
| |
2.2. 依赖注入与初始化
NewKubeletCommand 的核心在于其 Run 函数,它负责协调整个初始化过程。关键步骤如下:
- 构建依赖 (
KubeletDeps):通过UnsecuredDependencies创建 Kubelet 运行所需的核心依赖项,如CAdvisorInterface、ContainerManager和StatsProvider等。 - 创建 Kubelet 实例:
RunKubelet->createAndInitKubelet->kubelet.NewMainKubelet,这一系列调用最终创建并初始化了Kubelet核心对象。 - 启动核心循环:初始化完成后,Kubelet 启动其"心脏"——
syncLoop。
graph TD
A[main] --> B[app.NewKubeletCommand];
B --> C{创建 Flags 和 Config};
B --> D[创建 cobra.Command];
D -- 执行 --> E[RunE 函数];
E --> F[构建 KubeletServer];
F --> G[UnsecuredDependencies -> 创建 KubeletDeps];
G --> H[RunKubelet];
H --> I[createAndInitKubelet];
I --> J[kubelet.NewMainKubelet];
J --> K[返回初始化的 Kubelet 实例];
K --> L[启动 syncLoop];graph TD
A[main] --> B[app.NewKubeletCommand];
B --> C{创建 Flags 和 Config};
B --> D[创建 cobra.Command];
D -- 执行 --> E[RunE 函数];
E --> F[构建 KubeletServer];
F --> G[UnsecuredDependencies -> 创建 KubeletDeps];
G --> H[RunKubelet];
H --> I[createAndInitKubelet];
I --> J[kubelet.NewMainKubelet];
J --> K[返回初始化的 Kubelet 实例];
K --> L[启动 syncLoop];graph TD
A[main] --> B[app.NewKubeletCommand];
B --> C{创建 Flags 和 Config};
B --> D[创建 cobra.Command];
D -- 执行 --> E[RunE 函数];
E --> F[构建 KubeletServer];
F --> G[UnsecuredDependencies -> 创建 KubeletDeps];
G --> H[RunKubelet];
H --> I[createAndInitKubelet];
I --> J[kubelet.NewMainKubelet];
J --> K[返回初始化的 Kubelet 实例];
K --> L[启动 syncLoop];graph TD
A[main] --> B[app.NewKubeletCommand];
B --> C{创建 Flags 和 Config};
B --> D[创建 cobra.Command];
D -- 执行 --> E[RunE 函数];
E --> F[构建 KubeletServer];
F --> G[UnsecuredDependencies -> 创建 KubeletDeps];
G --> H[RunKubelet];
H --> I[createAndInitKubelet];
I --> J[kubelet.NewMainKubelet];
J --> K[返回初始化的 Kubelet 实例];
K --> L[启动 syncLoop];3. 核心工作循环:syncLoop 的事件驱动模型
syncLoop 是 Kubelet 的主控制循环,它通过 syncLoopIteration 函数以事件驱动的方式工作,确保 Pod 的"期望状态"与节点的"实际状态"保持同步。
3.1. 多路事件监听
syncLoopIteration 使用 select 语句同时监听来自多个 Channel 的事件,实现了高效的并发处理:
configCh(配置变更):接收来自kube-apiserver、静态 Pod 文件或 HTTP 端点的 Pod 配置更新,触发HandlePodAdditions、HandlePodUpdates等操作。plegCh(Pod 生命周期事件):PLEG (Pod Lifecycle Event Generator) 监控容器运行时的底层变化(如容器启动、停止),生成事件以驱动 Kubelet 快速响应。syncCh(定期同步):默认每秒触发一次,确保即使没有外部事件,Kubelet 也会定期检查所有 Pod 的状态。housekeepingCh(定期清理):执行周期性任务,如清理孤儿 Pod 和无效的目录。livenessManager.Updates()(存活探针):处理 Liveness Probe 的失败结果,通常会导致容器重启。
graph TD
A[syncLoop] --> B{select};
B --> C[configCh: 配置变更];
B --> D[plegCh: 容器状态变更];
B --> E[syncCh: 定期同步];
B --> F[housekeepingCh: 定期清理];
B --> G[livenessManager: 探针结果];
C --> H[HandlePodAdditions/Updates/Removes];
D --> I[HandlePodSyncs];
E --> I;
G --> I;
H --> J[podManager: 更新 Pod 缓存];
J --> K[dispatchWork: 异步同步 Pod];
I --> K;
K --> L[syncPod: 同步单个 Pod];graph TD
A[syncLoop] --> B{select};
B --> C[configCh: 配置变更];
B --> D[plegCh: 容器状态变更];
B --> E[syncCh: 定期同步];
B --> F[housekeepingCh: 定期清理];
B --> G[livenessManager: 探针结果];
C --> H[HandlePodAdditions/Updates/Removes];
D --> I[HandlePodSyncs];
E --> I;
G --> I;
H --> J[podManager: 更新 Pod 缓存];
J --> K[dispatchWork: 异步同步 Pod];
I --> K;
K --> L[syncPod: 同步单个 Pod];graph TD
A[syncLoop] --> B{select};
B --> C[configCh: 配置变更];
B --> D[plegCh: 容器状态变更];
B --> E[syncCh: 定期同步];
B --> F[housekeepingCh: 定期清理];
B --> G[livenessManager: 探针结果];
C --> H[HandlePodAdditions/Updates/Removes];
D --> I[HandlePodSyncs];
E --> I;
G --> I;
H --> J[podManager: 更新 Pod 缓存];
J --> K[dispatchWork: 异步同步 Pod];
I --> K;
K --> L[syncPod: 同步单个 Pod];graph TD
A[syncLoop] --> B{select};
B --> C[configCh: 配置变更];
B --> D[plegCh: 容器状态变更];
B --> E[syncCh: 定期同步];
B --> F[housekeepingCh: 定期清理];
B --> G[livenessManager: 探针结果];
C --> H[HandlePodAdditions/Updates/Removes];
D --> I[HandlePodSyncs];
E --> I;
G --> I;
H --> J[podManager: 更新 Pod 缓存];
J --> K[dispatchWork: 异步同步 Pod];
I --> K;
K --> L[syncPod: 同步单个 Pod];4. Pod 生命周期管理:syncPod 的同步逻辑
syncPod 是 Kubelet 中负责同步单个 Pod 状态的核心函数。它是一个庞大而复杂的函数,包含了 Pod 从创建到销毁的全套管理逻辑。
4.1. syncPod 的核心步骤
- 终止处理:如果 Pod 被标记为删除 (
SyncPodKill),则立即调用killPod流程。 - 状态计算与更新:调用
generateAPIPodStatus计算 Pod 的最新状态,并通过statusManager异步上报给kube-apiserver。 - 运行状态检查:通过
podShouldnotBeRunning判断 Pod 是否已完成或失败,如果是,则执行清理。 - 环境准备:创建 Pod 所需的数据目录 (
makePodDataDirs) 并等待存储卷挂载就绪 (waitForVolumes)。 - 调用容器运行时 (CRI):这是最关键的一步。Kubelet 调用
containerRuntime.SyncPod,将 Pod 的期望状态传递给容器运行时(如 containerd),由其完成具体的容器操作(拉取镜像、创建/销毁容器等)。
| |
4.2. Pod 创建、更新与删除流程图
graph TD
subgraph "事件分发"
A[dispatchWork] --> B{根据事件类型};
B -- ADD/UPDATE/SYNC --> C[podWorkers.UpdatePod];
B -- REMOVE --> C;
end
subgraph "Pod 同步执行"
C --> D["工作协程 (Worker Goroutine)"];
D --> E(syncPod);
end
subgraph "syncPod 内部逻辑"
E --> F{"检查 Pod 是否需要终止 (deletionTimestamp?)"};
F -- 是 --> G[执行 killPod 流程];
F -- 否 --> L{"Pod 是否应该运行?"};
subgraph "终止流程"
G --> H[CRI: StopPodSandbox/RemovePodSandbox];
H --> I[清理 Pod 目录和卷];
end
L -- 否 --> M["执行 killPod (如果容器仍在运行)"];
L -- 是 --> O["调用 CRI: SyncPod"];
subgraph "CRI: SyncPod 内部"
O --> T{"容器运行时"};
T -- 容器不存在 --> U[创建沙箱和容器];
T -- 容器状态与期望不符 --> V[停止并重建容器];
T -- 容器状态一致 --> W[不执行操作];
end
endgraph TD
subgraph "事件分发"
A[dispatchWork] --> B{根据事件类型};
B -- ADD/UPDATE/SYNC --> C[podWorkers.UpdatePod];
B -- REMOVE --> C;
end
subgraph "Pod 同步执行"
C --> D["工作协程 (Worker Goroutine)"];
D --> E(syncPod);
end
subgraph "syncPod 内部逻辑"
E --> F{"检查 Pod 是否需要终止 (deletionTimestamp?)"};
F -- 是 --> G[执行 killPod 流程];
F -- 否 --> L{"Pod 是否应该运行?"};
subgraph "终止流程"
G --> H[CRI: StopPodSandbox/RemovePodSandbox];
H --> I[清理 Pod 目录和卷];
end
L -- 否 --> M["执行 killPod (如果容器仍在运行)"];
L -- 是 --> O["调用 CRI: SyncPod"];
subgraph "CRI: SyncPod 内部"
O --> T{"容器运行时"};
T -- 容器不存在 --> U[创建沙箱和容器];
T -- 容器状态与期望不符 --> V[停止并重建容器];
T -- 容器状态一致 --> W[不执行操作];
end
endgraph TD
subgraph "事件分发"
A[dispatchWork] --> B{根据事件类型};
B -- ADD/UPDATE/SYNC --> C[podWorkers.UpdatePod];
B -- REMOVE --> C;
end
subgraph "Pod 同步执行"
C --> D["工作协程 (Worker Goroutine)"];
D --> E(syncPod);
end
subgraph "syncPod 内部逻辑"
E --> F{"检查 Pod 是否需要终止 (deletionTimestamp?)"};
F -- 是 --> G[执行 killPod 流程];
F -- 否 --> L{"Pod 是否应该运行?"};
subgraph "终止流程"
G --> H[CRI: StopPodSandbox/RemovePodSandbox];
H --> I[清理 Pod 目录和卷];
end
L -- 否 --> M["执行 killPod (如果容器仍在运行)"];
L -- 是 --> O["调用 CRI: SyncPod"];
subgraph "CRI: SyncPod 内部"
O --> T{"容器运行时"};
T -- 容器不存在 --> U[创建沙箱和容器];
T -- 容器状态与期望不符 --> V[停止并重建容器];
T -- 容器状态一致 --> W[不执行操作];
end
endgraph TD
subgraph "事件分发"
A[dispatchWork] --> B{根据事件类型};
B -- ADD/UPDATE/SYNC --> C[podWorkers.UpdatePod];
B -- REMOVE --> C;
end
subgraph "Pod 同步执行"
C --> D["工作协程 (Worker Goroutine)"];
D --> E(syncPod);
end
subgraph "syncPod 内部逻辑"
E --> F{"检查 Pod 是否需要终止 (deletionTimestamp?)"};
F -- 是 --> G[执行 killPod 流程];
F -- 否 --> L{"Pod 是否应该运行?"};
subgraph "终止流程"
G --> H[CRI: StopPodSandbox/RemovePodSandbox];
H --> I[清理 Pod 目录和卷];
end
L -- 否 --> M["执行 killPod (如果容器仍在运行)"];
L -- 是 --> O["调用 CRI: SyncPod"];
subgraph "CRI: SyncPod 内部"
O --> T{"容器运行时"};
T -- 容器不存在 --> U[创建沙箱和容器];
T -- 容器状态与期望不符 --> V[停止并重建容器];
T -- 容器状态一致 --> W[不执行操作];
end
end5. 指标监控:cAdvisor 的集成与工作机制
Kubelet 的资源监控能力由内嵌的 cAdvisor 提供。cAdvisor 负责收集、处理和暴露容器与节点的性能指标。
5.1. 初始化与启动
cAdvisor 在 Kubelet 启动时被初始化和启动。buildKubeletDeps 函数创建 cAdvisor 实例,随后 initializeRuntimeDependentModules 调用 kl.cadvisor.Start() 启动其后台收集任务。
5.2. 指标收集周期与实现
cAdvisor 的指标收集频率由 Kubelet 的 --housekeeping-interval 参数(默认 10 秒)控制。其实现机制如下:
- 参数传递:Kubelet 通过一个"hack"方式,在启动时将自己的
--housekeeping-interval值设置给 cAdvisor 库的全局标志housekeeping_interval。 - 容器级
housekeeping:cAdvisor 为每个容器启动一个独立的housekeepinggoroutine。这个 goroutine 使用time.Timer来周期性地触发指标收集。 - 数据采集:
housekeeping循环最终调用updateStats,该函数通过容器处理器 (containerHandler) 从 cgroup 文件系统或 CRI 获取原始的 CPU、内存等数据。
| |
5.3. 指标存储:InMemoryCache
cAdvisor 采集的指标存储在名为 InMemoryCache 的内存缓存中,其核心特点是:
- 环形缓冲区 (Ring Buffer):为每个容器维护一个固定大小的环形缓冲区,用于存储最近一段时间(默认 60 秒)的时间序列数据。
- 数据写入:
updateStats函数调用memoryCache.AddStats()将新采集的指标存入缓冲区,旧数据会被自动覆盖。 - 数据读取:当外部请求(如
metrics-server)访问 Kubelet 的/stats/summary端点时,StatsProvider会调用RecentStats从缓存中提取数据用于聚合。
这种设计使得 cAdvisor 能够在不引入磁盘 I/O 的情况下,高效地提供短期、高分辨率的性能指标。
6. 总结
通过对 Kubelet 源码的深入探索,我们揭示了其作为 Kubernetes 节点核心代理的复杂而精妙的工作机制。从命令行的解析启动,到依赖注入的构建,再到事件驱动的 syncLoop 核心循环,Kubelet 的设计处处体现着健壮性与可扩展性。
syncPod 作为 Pod 生命周期管理的最终执行者,通过与容器运行时的紧密协作,精确地将声明式 API 转化为实际的容器操作。而内嵌的 cAdvisor 则为 Kubelet 提供了强大的监控能力,通过高效的周期性采集和内存缓存机制,为整个集群的调度和自动扩缩容提供了关键的数据支持。
理解 Kubelet 的内部工作原理,不仅有助于我们更好地排查节点问题,也让我们对 Kubernetes 的分布式系统设计哲学有了更深刻的认识。Kubelet 正是这一哲学在节点侧的完美体现,是确保云原生应用稳定、高效运行的基石。