Kubernetes Kubelet 深度解析
Kubelet:Kubernetes 集群的节点基石
Kubelet 是在 Kubernetes 集群中每个 节点(Node) 上运行的核心代理(Agent)。它的根本职责是确保在节点上运行的 容器(Containers) 符合 控制平面(Control Plane) 通过 PodSpec 定义的期望状态。可以将其视为控制平面指令在具体节点上的执行者和状态汇报者,是连接 Master 与 Worker 节点的关键桥梁,负责 Pod 的生命周期管理、节点资源监控与汇报等核心任务。理解 Kubelet 的工作原理对于深入掌握 Kubernetes 的运行机制至关重要。
Kubelet 核心架构与交互接口
Kubelet 内部包含多个协同工作的管理器和循环,并通过标准的 API 接口与集群其他组件及外部系统交互。
Kubelet API 服务
Kubelet 暴露了若干 HTTP API 端点,用于不同的交互场景:
- 认证与授权的 HTTPS API (默认端口 :10250):这是 Kubelet 最主要的 API 服务端口,用于接收来自 API Server 的指令,例如创建、删除、更新 Pod。API Server 通过此端口向 Kubelet 下发任务。同时,Kubelet 也通过此端口对外提供节点和 Pod 的详细信息查询,但访问此端口需要严格的认证和授权(通常使用 TLS 证书)。
kubectl exec
,kubectl logs
等命令最终也会通过 API Server 代理将请求转发到 Kubelet 的这个端口。 - 非认证的只读 HTTP API (默认端口 :10255):此端口提供一个无需认证即可访问的只读接口,主要用于获取 Pod 和节点的基本状态信息(如
/pods
,/stats
等)。由于其安全性较低,已不推荐在生产环境中使用,并且在较新版本的 Kubernetes 中可能默认禁用。外部监控系统(如 Prometheus)有时会配置为从这个端口拉取指标,但更推荐使用 Metrics Server 或者通过 :10250 端口的安全接口获取。 - 健康检查 HTTP API (默认端口 :10248):这个端口主要提供 Kubelet 自身的健康状态检查端点,通常是
/healthz
。监控系统或负载均衡器可以调用此接口来判断 Kubelet 进程是否存活且正常工作。
这些 API 是 Kubelet 与外界沟通的窗口,特别是 :10250
端口,承载了 Kubelet 与控制平面交互的核心流量。
Kubelet 内部核心组件剖析
Kubelet 内部由多个并发运行的管理器(Manager)和控制循环(Loop)构成,它们各司其职,共同维护节点的 Pod 运行状态。
syncLoop: 核心协调循环
syncLoop
是 Kubelet 的心脏,它是一个持续运行的控制循环(Reconciliation Loop)。其核心任务是将节点上 Pod 的实际状态与期望状态进行同步。
- 获取期望状态:
syncLoop
主要通过 Watch 机制监听 API Server,获取分配给本节点的 Pod 的配置信息(期望状态)。此外,它还可以从静态 Pod 目录(由--pod-manifest-path
参数指定,通常是/etc/kubernetes/manifests/
)或远程 HTTP URL(由--manifest-url
参数指定)读取 Pod 定义。 - 获取实际状态:通过 PLEG (Pod Lifecycle Event Generator) 和容器运行时接口 (CRI) 获取节点上当前实际运行的 Pod 和容器状态。
- 状态比较与动作执行:
syncLoop
对比期望状态和实际状态的差异。如果发现不一致(例如,需要创建新 Pod、删除旧 Pod、重启容器等),它会计算出需要执行的操作,并将这些操作分发给 PodWorker 进行处理。这个过程体现了 Kubernetes 声明式 API 的核心思想:用户只定义期望状态,由控制器(这里是 Kubelet 的syncLoop
)负责驱动系统达到该状态。
PodWorker: Pod 操作执行单元
PodWorker
负责具体执行 syncLoop
决策出的 Pod 相关操作。它通常管理一个 Goroutine 池,并发地处理各个 Pod 的创建、更新和删除任务。例如,当需要创建一个 Pod 时,PodWorker
会调用容器运行时接口 (CRI) 来创建 Sandbox 和容器、设置网络、挂载卷等。这种并发处理机制提高了 Kubelet 管理大量 Pod 的效率。
容器运行时接口 (CRI) Shim
Kubelet 本身不直接操作容器(如 Docker、containerd、CRI-O)。它通过 容器运行时接口 (Container Runtime Interface, CRI) 这个抽象层与具体的容器运行时进行交互。CRI 定义了一套标准的 gRPC 接口,包括 RuntimeService
(管理 Pod Sandbox 和容器生命周期)和 ImageService
(管理容器镜像)。Kubelet 调用这些 gRPC 接口,由运行在节点上的 CRI Shim(如 cri-containerd
, cri-o
)负责将 CRI 请求翻译成底层容器运行时的具体命令。这种设计使得 Kubernetes 可以灵活地支持多种容器运行时,实现了 Kubelet 与容器运行时的解耦。
PLEG (Pod Lifecycle Event Generator): Pod 生命周期事件生成器
PLEG 是 Kubelet 中一个至关重要的、但有时也容易引发性能问题的模块。它的主要职责是持续监测节点上容器的真实状态,并将变化以事件的形式通知给 syncLoop
。
工作机制:PLEG 定期(默认为 1 秒)通过 CRI 调用容器运行时的
ListContainers
或类似接口,获取节点上所有容器的当前状态。然后,它会与自己维护的内部缓存进行比较,识别出状态发生变化的容器(如启动、停止、死亡等)。对于检测到的变化,PLEG 会生成相应的 Pod 生命周期事件,并将这些事件发送到一个内部通道,供syncLoop
消费。为何需要 PLEG:虽然容器运行时本身会产生事件,但这些事件可能丢失或不及时。PLEG 通过**主动轮询(Relist)**的方式,确保 Kubelet 能够可靠地感知到容器的最终状态,即使错过了某些瞬时事件。
性能考量:频繁的
relist
操作(尤其是在节点上 Pod 数量非常多时)会对容器运行时和 Kubelet 自身造成显著的性能压力。如果relist
操作耗时过长(例如超过 PLEG 的检查周期),可能导致 Kubelet 无法及时更新 Pod 状态,甚至误判节点为NotReady
。这就是为什么 Kubernetes 会建议限制每个节点的最大 Pod 数量 (maxPods
) 的原因之一。1
2
3
4# KubeletConfiguration 示例片段,限制节点 Pod 数量
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
maxPods: 110 # 默认值,可根据节点规格调整
ProbeManager: 容器健康探测器
ProbeManager
负责执行 Pod 定义中配置的 Liveness Probe (存活探针)、Readiness Probe (就绪探针) 和 Startup Probe (启动探针)。
- Liveness Probe:用于判断容器是否仍在正常运行。如果探测失败,Kubelet 会根据 Pod 的
restartPolicy
杀死并尝试重启该容器。这有助于自动恢复陷入死锁或无响应状态的应用。 - Readiness Probe:用于判断容器是否已准备好接收外部流量。如果探测失败,Kubernetes Service Controller 会将该 Pod 的 Endpoint 从相应的 Service 中移除,使其暂时不接收新的请求,直到探测成功。这确保了流量只会被发送到真正准备就绪的实例。
- Startup Probe:用于处理启动时间较长的应用。在 Startup Probe 成功之前,Liveness 和 Readiness Probe 不会执行。这可以防止启动过程中的应用被 Liveness Probe 误杀。
ProbeManager
根据探针配置(如检查方式 - HTTP GET, TCP Socket, Exec Command,以及频率、超时、阈值等),周期性地执行检查,并将结果反馈给 Kubelet 的状态管理系统。
cAdvisor: 容器与节点资源监控
cAdvisor (Container Advisor) 是 Google 开源的一个用于监控容器资源使用和性能的工具,它被内嵌在 Kubelet 的二进制文件中运行。cAdvisor 负责收集本节点上所有容器以及节点本身的资源使用数据(CPU、内存、文件系统、网络等)。
- 数据来源:cAdvisor 主要通过读取 Linux 内核提供的 cgroups 文件系统(位于
/sys/fs/cgroup
)和/proc
文件系统来获取精确的资源使用信息。 - 数据用途:
- Kubelet 通过 cAdvisor 获取的数据来更新 Pod 和节点的状态信息(如资源使用量),并汇报给 API Server。
- 调度器 (Scheduler) 使用这些信息来做出更优的 Pod 调度决策。
- 水平 Pod 自动伸缩器 (HPA) 依赖这些指标来判断是否需要增减 Pod 副本。
- Kubelet 的 EvictionManager 也使用这些数据来判断节点资源是否紧张。
- 可以通过 Kubelet 的
/metrics/cadvisor
端点(通常在 :10250 端口,需要认证)或只读端口:10255
(如果启用)暴露这些指标,供 Prometheus 等监控系统采集。
StatusManager: 状态管理器
StatusManager
负责管理和同步 Pod 的状态信息。它从 Kubelet 内部的其他组件(如 PLEG、ProbeManager)收集 Pod 的最新状态,并将其定期(通过心跳)更新到 API Server。API Server 随后将这些状态持久化到 etcd 中。用户通过 kubectl get pod
等命令看到的就是由 StatusManager
汇报的状态。如果 Kubelet 与 API Server 长时间失联,StatusManager
无法更新状态,控制平面中的 Node Controller 最终会将该节点标记为 NotReady
。
EvictionManager: 资源驱逐管理器
EvictionManager
负责监控节点的资源状况(如内存、磁盘空间、inode 使用率),并在资源低于预设的驱逐阈值 (Eviction Thresholds) 时,主动**驱逐(Evict)**节点上的 Pod 以回收资源,防止节点因资源耗尽而变得不稳定。
驱逐信号 (Eviction Signals):常见的信号包括
memory.available
,nodefs.available
(节点根文件系统可用空间),imagefs.available
(容器镜像存储文件系统可用空间),nodefs.inodesFree
(节点根文件系统可用 inode)。驱逐阈值 (Eviction Thresholds):可以配置硬驱逐 (Hard Eviction) 阈值(一旦达到立即触发驱逐)和软驱逐 (Soft Eviction) 阈值(达到后会有一个宽限期,若资源仍未恢复则触发驱逐)。
驱逐策略:当需要驱逐时,EvictionManager 会根据 Pod 的 QoS (Quality of Service) 等级(
Guaranteed
>Burstable
>BestEffort
)和资源使用情况来决定驱逐的优先级。通常优先驱逐BestEffort
级别的 Pod,或者超出其资源请求(Request)最多的Burstable
Pod。1
2
3
4
5
6
7
8
9# KubeletConfiguration 示例片段,配置硬驱逐阈值
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
evictionHard:
memory.available: "100Mi" # 当可用内存低于 100Mi 时触发驱逐
nodefs.available: "10%" # 当节点根文件系统可用空间低于 10% 时触发驱逐
imagefs.available: "15%" # 当镜像文件系统可用空间低于 15% 时触发驱逐
nodefs.inodesFree: "5%" # 当节点根文件系统可用 inode 低于 5% 时触发驱逐
# evictionSoft: ... # 可选,配置软驱逐阈值及宽限期
VolumeManager: 存储卷管理器
VolumeManager
负责 Pod 所需存储卷 (Volume) 的挂载 (Mount) 和卸载 (Unmount) 操作。它与 CSI (Container Storage Interface) 驱动程序交互,管理各种类型的持久化和非持久化存储卷。
- 挂载流程:在 Pod 启动前,
VolumeManager
会确保所有声明的卷都已准备就绪 (Attach, if necessary) 并挂载 (Mount) 到节点上的指定路径。然后,这些路径会被传递给容器运行时,以便在容器内部进行绑定挂载 (bind mount)。 - 卸载流程:当 Pod 被删除时,
VolumeManager
负责卸载这些卷,并在必要时执行清理 (Detach) 操作。 - 关键作用:确保有状态应用能够正确地访问其持久化数据。
ImageGC 与 DiskSpaceManager: 镜像与磁盘空间管理
- ImageGC (Image Garbage Collector):负责自动清理节点上未被任何运行中或最近创建的 Pod 使用的容器镜像。它根据配置的策略(如基于镜像使用时间和磁盘空间占用率的阈值)来决定回收哪些镜像,以防止节点磁盘被不再需要的镜像占满。
- DiskSpaceManager:与 ImageGC 类似,但更广泛地监控节点磁盘空间(特别是容器可写层和空目录卷使用的空间),并在必要时触发容器日志清理或其他磁盘清理操作,协同
EvictionManager
工作。
CertificateManager: 证书管理器
CertificateManager
负责管理 Kubelet 用于与 API Server 进行 TLS 安全通信所需的客户端证书。它可以配置为自动请求和轮换 (rotate) 这些证书,确保 Kubelet 与控制平面之间的通信始终是加密且经过认证的,增强了集群的安全性。
Kubelet 管理 Pod 的完整流程
理解 Kubelet 如何接收指令并最终运行一个 Pod 是掌握其工作方式的关键。
Pod 期望状态来源:
- API Server (主要来源):Kubelet 通过 Watch 机制实时监听 API Server 上与其
nodeName
匹配的 Pod 对象创建、更新和删除事件。这是最常用和动态的方式。 - 静态 Pod (Static Pods):Kubelet 可以配置一个本地文件目录 (
--pod-manifest-path
)。它会周期性扫描此目录下的 YAML 或 JSON 文件,并将这些文件定义的 Pod 直接在本节点上运行,无需 API Server 的介入。这类 Pod 通常用于运行集群关键组件(如 API Server、etcd 自身,如果它们以 Pod 形式部署的话),确保即使在控制平面不可用时,这些基础服务也能在节点上启动。 - HTTP URL:类似静态 Pod,Kubelet 可以配置一个 URL (
--manifest-url
),周期性地从该 URL 拉取 Pod 定义文件。 - (不推荐) HTTP 接口:Kubelet 曾支持通过其 HTTP 接口直接提交 Pod 定义,但这种方式已被弃用。
- API Server (主要来源):Kubelet 通过 Watch 机制实时监听 API Server 上与其
syncLoop 消费与处理:
syncLoop
从上述来源获取到 Pod 的期望状态 (Desired State)。- 它通过 PLEG 和 CRI 获取 Pod 的实际状态 (Actual State)。
- 调用内部的
computePodActions
函数,比较期望状态和实际状态,生成需要执行的操作(如SyncPod
,KillPod
)。 - 将这些操作分发给
PodWorker
。
PodWorker 执行操作:
PodWorker
接收到SyncPod
指令后,开始执行 Pod 的创建或更新流程。- 调用 CRI:
- 创建 Pod Sandbox:首先调用 CRI 的
RunPodSandbox
接口。CRI Shim 会创建一个基础的隔离环境,通常是一个非常轻量级的 “pause” 容器。这个 Pause 容器的核心作用是持有 Pod 共享的网络命名空间 (net ns),以及可能的 IPC 命名空间 (ipc ns) 和 PID 命名空间 (pid ns)。Pod 内的所有应用容器都将加入到这个 Pause 容器的命名空间中,从而实现它们之间的网络互通(共享同一个 IP 和端口空间)和 IPC 通信。 - 配置网络:Sandbox 创建后,Kubelet 会调用 CNI (Container Network Interface) 插件(通过 CRI 触发)。CNI 插件负责为 Pod Sandbox 分配 IP 地址、设置网络路由等网络相关的配置,将其接入集群网络。
- 挂载卷:
VolumeManager
介入,确保 Pod 所需的存储卷(通过 CSI (Container Storage Interface) 或内置的 Volume 插件)被正确挂载到节点上的预期位置,供后续容器使用。 - 拉取镜像:为每个应用容器调用 CRI 的
PullImage
接口,确保所需的容器镜像存在于本地。 - 创建容器:为每个应用容器调用 CRI 的
CreateContainer
接口,在 Pod Sandbox 的共享命名空间内创建容器实例,但不启动。 - 启动容器:最后,为每个应用容器调用 CRI 的
StartContainer
接口,启动容器内的进程。
- 创建 Pod Sandbox:首先调用 CRI 的
PodWorker
接收到KillPod
指令后,会逆向执行上述流程,调用 CRI 接口停止容器、删除容器、卸载卷、删除 Sandbox 等。
状态反馈:
- 在整个过程中以及 Pod 运行期间,PLEG、ProbeManager 等组件持续监控状态。
StatusManager
汇总这些状态,并定期通过心跳上报给 API Server,更新 etcd 中的 Pod 对象状态。- 用户或其他控制器可以通过查询 API Server 获取 Pod 的最新状态(如
Pending
,Running
,Succeeded
,Failed
,Unknown
)以及更详细的Conditions
和ContainerStatuses
。
节点管理与自注册
Kubelet 不仅管理 Pod,也负责将自身所在的物理机或虚拟机注册为 Kubernetes 集群的一个 Node 资源,并持续维护该 Node 的状态。
节点自注册 (Node Self-Registration):
- 通过启动参数
--register-node=true
(默认值),Kubelet 在启动时会自动尝试向 API Server 注册自己。它会收集节点信息(如操作系统、内核版本、CPU/内存容量、容器运行时版本等),创建一个 Node 对象,并提交给 API Server。 - 如果 API Server 中已存在同名的 Node 对象,Kubelet 会尝试更新它。
- 自注册需要 Kubelet 拥有与 API Server 通信的凭证(通常是
kubeconfig
文件,由--kubeconfig
参数指定)以及在 API Server 上创建/更新 Node 对象的权限。
- 通过启动参数
手动注册节点:
- 如果设置
--register-node=false
,或者 Kubelet 没有权限自注册,管理员就需要手动创建 Node 对象。 - 管理员需要准备一个 Node 对象的 YAML 或 JSON 定义文件,包含节点的名称(必须与 Kubelet 启动时通过
--hostname-override
指定或自动获取的主机名一致)、标签、容量等信息,然后使用kubectl apply -f node.yaml
创建。 - 即使是手动注册,Kubelet 仍然需要配置
--kubeconfig
以便与 API Server 通信,汇报节点状态和接收 Pod 任务。
- 如果设置
节点状态更新与心跳:
- 无论如何注册,Kubelet 都会定期(由
--node-status-update-frequency
控制,默认 10 秒)向 API Server 发送心跳,更新 Node 对象的status
字段。 - 状态信息包括:
- Node Conditions:描述节点当前状态的关键标志,如
Ready
(节点是否健康且可调度 Pod),MemoryPressure
,DiskPressure
,PIDPressure
(节点是否存在资源压力)。这些 Condition 由 Kubelet 根据内部监控(如 EvictionManager 的信号)动态更新。 - Node Capacity & Allocatable:节点的总资源容量和可供 Pod 分配的资源量。
- Node Info:操作系统、内核版本、容器运行时版本等静态信息。
- Node Conditions:描述节点当前状态的关键标志,如
- Node Controller 在控制平面会监控这些心跳。如果一个节点在一段时间内(由
--node-monitor-grace-period
控制,默认 40 秒)没有发送心跳,Node Controller 会将该节点的Ready
Condition 标记为Unknown
;如果更长时间(由--node-monitor-period
相关配置决定)没有响应,可能会标记为False
,并触发驱逐该节点上的 Pod 等操作。
- 无论如何注册,Kubelet 都会定期(由
总结
Kubelet 作为 Kubernetes 数据平面的核心组件,其内部结构复杂而精巧。它通过一系列管理器和控制循环,与 API Server、容器运行时 (CRI)、网络插件 (CNI)、存储插件 (CSI) 紧密协作,忠实地执行控制平面的指令,管理 Pod 的完整生命周期,监控并维护节点的健康状态和资源使用情况。深入理解 Kubelet 的核心机制(如 syncLoop、PLEG、CRI 交互、资源管理与驱逐、状态汇报)以及其关键配置(如 maxPods
, evictionHard
, cgroupDriver
),对于诊断集群问题、优化节点性能以及进行更高级的 Kubernetes 开发和运维至关重要。 Kubelet 是将声明式的 Pod 定义转化为节点上实际运行的容器的关键执行者,是 Kubernetes 分布式系统稳定运行的基石之一。