4. kubelet 与 CRI shim 交互原理:kubelet 内部架构、CRI 请求路由、Streaming API 机制
kubelet 是 Kubernetes 节点上最核心的代理组件,负责管理 Pod 生命周期、容器健康检查、资源监控与上报。在容器运行时治理控制面中,kubelet 通过 CRI(Container Runtime Interface)与各类运行时 shim 交互,实现容器创建、启动、停止、删除等操作。本章深入剖析 kubelet 内部架构、CRI 请求在 kubelet 中的路由路径,以及 Streaming API 的建立与数据流转机制。
4.1 kubelet 内部架构概览
kubelet 内部采用模块化设计,核心模块包括 Pod 管理、容器运行时管理、卷管理、网络管理、状态上报等。与 CRI shim 交互的关键模块是 Container Runtime Manager 和 CRI Client。
4.2 CRI 请求路由路径
当 kubelet 需要创建或管理容器时,请求经过以下路由路径:
- Pod Manager 从 API Server 接收到 Pod 更新事件,触发 SyncPod 流程。
- Container Runtime Manager 调用
RuntimeServiceClient的对应方法(如RunPodSandbox、CreateContainer、StartContainer)。 - CRI Client 将请求序列化为 Protocol Buffers 格式,通过 gRPC 发送到 CRI shim 的 Unix Socket。
- CRI shim 的 gRPC Server 接收请求,反序列化后调用底层运行时接口执行实际操作。
- 响应沿原路径返回,最终更新 kubelet 内部状态。
| CRI 方法 | kubelet 调用模块 | CRI shim 处理模块 | 底层操作 |
|---|---|---|---|
RunPodSandbox |
Container Runtime Manager | Runtime Service | 创建 Pod 网络命名空间、cgroup 等 |
CreateContainer |
Container Runtime Manager | Runtime Service | 准备容器镜像、配置容器 spec |
StartContainer |
Container Runtime Manager | Runtime Service | 启动容器进程 |
ExecSync |
Container Runtime Manager | Runtime Service | 在容器内同步执行命令 |
PullImage |
Image Manager | Image Service | 拉取容器镜像 |
ListImages |
Image Manager | Image Service | 列出本地镜像列表 |
--runtime-request-timeout 参数控制(默认 2 分钟)。对于长时间操作(如镜像拉取),CRI shim 应在超时前返回进度信息。
4.3 Streaming API 机制
CRI 定义了 Streaming API 用于处理需要流式数据传输的场景,包括 Exec、Attach、PortForward。这些操作不适合通过标准的 gRPC 单向调用实现,因为需要双向实时数据流。
4.3.1 Streaming API 架构
Streaming API 采用 分离式架构:kubelet 通过 CRI 获取流式会话的 URL,然后 kubelet 或 kube-apiserver 直接与该 URL 建立 WebSocket 连接,数据不经过 CRI shim 的 gRPC 通道。
4.3.2 Streaming API 交互流程
以 kubectl exec 为例,Streaming API 的完整交互流程如下:
- kubectl 发起请求: 用户执行
kubectl exec -it <pod> -- /bin/bash,kubectl 向 kube-apiserver 发送子资源请求/api/v1/namespaces/<ns>/pods/<pod>/exec。 - kube-apiserver 转发: API Server 将请求转发到 kubelet 的
/exec端点(通过 Node 代理或直接连接)。 - kubelet 调用 CRI: kubelet 调用
RuntimeService.Exec方法,传入容器 ID、命令、终端设置等参数。 - CRI shim 返回 URL: CRI shim 的 Streaming Server 创建一个会话,返回一个唯一的 WebSocket URL(如
http://<node-ip>:<port>/exec/<session-id>)。 - kubelet 升级连接: kubelet 将 HTTP 连接升级为 WebSocket,并将数据流代理到 CRI shim 返回的 URL。
- 数据双向传输: 用户输入通过 WebSocket → kubelet → CRI shim → 容器进程 stdin;容器 stdout/stderr 沿反向路径返回。
127.0.0.1:0(随机端口),仅允许本地回环地址访问。kubelet 通过 --streaming-connection-idle-timeout 参数控制空闲连接超时(默认 4 小时),防止资源泄漏。生产环境中建议启用 TLS 加密 Streaming 通信。
4.3.3 Streaming API 关键参数
| 参数 | 默认值 | 说明 |
|---|---|---|
StreamServerPort |
0(随机分配) | Streaming Server 监听端口 |
StreamIdleTimeout |
4h | 空闲连接超时时间 |
StreamServerMaxConcurrentStreams |
100 | 最大并发流数量 |
EnableTLS |
false | 是否启用 TLS 加密 |
TLSCertFile |
"" | TLS 证书文件路径 |
TLSKeyFile |
"" | TLS 私钥文件路径 |
4.4 CRI 请求超时与重试机制
kubelet 对 CRI 请求实现了完善的超时控制和重试策略:
- 全局超时:
--runtime-request-timeout控制所有 CRI 请求的超时时间,默认 2 分钟。 - 操作级超时: 特定操作(如
PullImage)可以设置更长的超时,通过 CRI 请求的timeout字段传递。 - 重试策略: 对于可重试的错误(如网络抖动、临时资源不足),kubelet 使用指数退避算法重试,最大重试次数为 3 次。
- 背压机制: 当 CRI shim 返回
Unavailable状态码时,kubelet 会降低请求速率,避免雪崩效应。
// kubelet CRI 客户端重试逻辑示例(简化)
func (c *remoteRuntimeService) exec(ctx context.Context, req *runtimeapi.ExecRequest) (*runtimeapi.ExecResponse, error) {
var resp *runtimeapi.ExecResponse
err := retry.OnError(retry.DefaultBackoff, func(err error) bool {
return grpcStatus.Code(err) == codes.Unavailable
}, func() error {
var err error
resp, err = c.runtimeClient.Exec(ctx, req)
return err
})
return resp, err
}
4.5 性能与调优建议
- gRPC 连接复用: kubelet 与 CRI shim 之间保持长连接,避免频繁建立/断开连接的开销。
- Streaming 端口范围: 如果使用防火墙策略,需要开放 Streaming Server 的动态端口范围(通常 10250-10255)。
- 超时设置: 对于大规模集群,适当增加
--runtime-request-timeout到 3-5 分钟,避免大规模镜像拉取超时。 - 监控指标: 关注 kubelet 暴露的
kubelet_runtime_operations_duration_seconds指标,识别慢操作。
通过理解 kubelet 内部架构、CRI 请求路由路径和 Streaming API 机制,运维人员可以更有效地诊断容器运行时相关问题,优化集群性能,并确保生产环境的稳定性。