3. 镜像拉取流程详解:从 kubelet 到容器运行时,再到镜像仓库的完整拉取链路
当 Deployment 的 Pod 调度到某节点后,kubelet 负责执行实际的镜像拉取操作。理解这条从 kubelet → 容器运行时 → 镜像仓库的完整链路,是定位拉取超时故障的基础。任何一个环节的延迟或失败,都会表现为 Pod 状态 ImagePullBackOff 或 ErrImagePull。
3.1 整体链路架构
镜像拉取并非由 kubelet 直接发起 HTTP 请求,而是通过容器运行时接口(CRI)委托给容器运行时(如 containerd、CRI-O、Docker Engine)。运行时再根据镜像名称,依次查询本地缓存、配置的镜像仓库(Registry),最终通过 HTTPS 下载镜像层。
3.2 逐层调用细节
3.2.1 kubelet 侧:SyncPod 与镜像拉取触发
kubelet 的核心控制循环 SyncLoop 在检测到 Pod 需要更新时,调用 SyncPod 方法。该方法内部按顺序执行:挂载卷 → 拉取镜像 → 创建容器 → 启动容器。镜像拉取由 runtimeService.PullImage() 触发,这是一个 gRPC 调用,定义在 kubelet/apis/cri/services.go 中。
| 步骤 | kubelet 组件 | 动作 | 超时控制 |
|---|---|---|---|
| 1 | SyncPod | 计算期望状态,生成 PodSandbox 配置 | Pod 级别启动超时(默认 5m) |
| 2 | imageManager.EnsureImageExists | 检查本地是否已有镜像,若无则调用 PullImage | 单次拉取超时(默认 1m) |
| 3 | CRI RemoteRuntimeService.PullImage | 构造 PullImageRequest,通过 gRPC 发送 | gRPC 连接超时(默认 30s) |
SyncPod 或 EnsureImageExists 可定位到具体拉取请求。若日志显示 context deadline exceeded,说明 gRPC 调用超时,问题可能在运行时或网络层。
3.2.2 CRI 层:gRPC 协议与 PullImage 接口
CRI(Container Runtime Interface)是 kubelet 与容器运行时之间的标准 gRPC 接口。核心的 PullImage 接口定义如下:
// PullImageRequest 包含镜像名称、凭证、沙箱配置
message PullImageRequest {
// 镜像的完整引用,如 docker.io/library/nginx:1.21
string image = 1;
// 镜像仓库认证信息
AuthConfig auth = 2;
// PodSandbox 配置(用于镜像拉取策略)
PodSandboxConfig sandbox_config = 3;
}
// PullImageResponse 返回镜像的唯一标识
message PullImageResponse {
string image_ref = 1; // 如 sha256:abc123...
}
kubelet 将 imagePullSecrets 中的凭证转换为 AuthConfig,随请求发送。运行时收到请求后,解析镜像名称中的 registry 地址、仓库名和标签。
3.2.3 容器运行时侧:镜像解析与层下载
以 containerd 为例,其内部处理流程如下:
- 镜像名称解析: 将
nginx:1.21补全为docker.io/library/nginx:1.21,提取 registry 地址。 - 本地缓存检查: 查询
/var/lib/containerd/io.containerd.content.v1.content中的 blob 索引,若所有层都存在则直接返回。 - manifest 拉取: 向 registry 的
/v2/<name>/manifests/<tag>发起 GET 请求,获取镜像 manifest(描述层列表和配置)。 - 层下载: 根据 manifest 中的层 digest,并发下载每个 blob(
/v2/<name>/blobs/<digest>),支持断点续传。 - 解压与挂载: 下载完成后解压层数据,写入 snapshotter 挂载点,生成容器根文件系统。
3.3 镜像仓库交互协议
容器运行时与镜像仓库之间使用 Docker Registry HTTP API V2 进行通信,默认通过 HTTPS。核心交互流程如下:
| 请求类型 | API 端点 | 用途 | 常见超时原因 |
|---|---|---|---|
| 认证 | /v2/ 或 /v2/auth |
获取 Bearer (若需认证) | 认证服务响应慢、凭证错误 |
| Manifest 拉取 | /v2/<name>/manifests/<reference> |
获取镜像 manifest(JSON 格式) | 仓库负载高、manifest 体积大 |
| Blob 拉取 | /v2/<name>/blobs/<digest> |
下载镜像层数据(tar.gz) | 带宽不足、层体积大、连接不稳定 |
| 健康检查 | /v2/_catalog 或 / |
探测仓库是否可达 | DNS 解析失败、网络不通 |
imagePullSecrets 是否过期、仓库地址是否正确(如是否遗漏了 library/ 前缀)。
3.4 超时故障点总结
基于上述链路,超时故障可归纳为以下三类,对应不同的排查方向:
- kubelet → CRI 超时: 通常表现为
context deadline exceeded,原因可能是运行时 hang 住、磁盘 I/O 瓶颈、或 containerd 服务异常。排查方向:检查crictl info、systemctl status containerd。 - 运行时 → 仓库网络超时: 表现为
dial tcp: i/o timeout或TLS handshake timeout。排查方向:节点 DNS 配置、代理设置、防火墙规则、仓库 CDN 可用性。 - 层下载缓慢: 表现为
downloading layer ... 0 B/100 MB长时间无进度。排查方向:节点带宽、并发拉取数限制(max_concurrent_downloads)、镜像层大小。
crictl pull nginx:1.21 可以绕过 kubelet,直接测试运行时到仓库的链路。若手动拉取成功,问题大概率在 kubelet 侧或 Pod 配置;若失败,则聚焦网络或仓库配置。