4. 镜像拉取原理:kubelet 如何拉取镜像?imagePullSecrets 的工作流程

理解 kubelet 拉取镜像的完整流程,是诊断 “镜像拉取失败” 类问题的前提。当 RBAC 权限不足导致 Secret 无法被读取时,kubelet 会在拉取镜像阶段因缺少认证凭据而报错 ImagePullBackOff 或 ErrImagePull。本节将拆解 kubelet 的拉取链路,并重点剖析 imagePullSecrets 的注入与使用机制。

4.1 kubelet 镜像拉取全流程

kubelet 是节点上的核心代理,负责将 Pod 声明转化为运行中的容器。其镜像拉取流程可概括为以下步骤:

  1. Pod 调度与分配:API Server 将 Pod 绑定到某节点,kubelet 通过 watch 机制获取该 Pod 对象。
  2. Pod 状态初始化:kubelet 创建 Pod 的 sandbox(pause 容器),准备容器运行环境。
  3. 读取镜像拉取凭据:kubelet 检查 Pod 的 spec.imagePullSecrets 字段,并尝试从本地缓存或 API Server 读取对应的 Secret 对象。
  4. 镜像拉取决策:kubelet 调用容器运行时(如 containerd、CRI-O)的 PullImage gRPC 接口,传入镜像名称及可选的认证凭据。
  5. 容器运行时执行拉取:运行时根据凭据向镜像仓库(Docker Hub、ACR、ECR 等)发起 HTTP/HTTPS 请求,下载镜像层。
  6. 结果反馈:拉取成功则创建容器;失败则更新 Pod 状态为 ImagePullBackOff 或 ErrImagePull,并记录错误事件。
关键点:步骤 3 是 RBAC 权限问题的“重灾区”。如果 kubelet 使用的 ServiceAccount 没有 get Secret 的权限,或者 Secret 所在的命名空间与 Pod 不一致,kubelet 将无法获取 imagePullSecrets,导致拉取失败。
kubelet 镜像拉取流程 API Server kubelet (Watch Pod) 读取 imagePullSecrets 容器运行时 PullImage 镜像仓库 (Registry) ⚠️ RBAC 权限检查点 • kubelet 使用 Pod 的 ServiceAccount • 需要 get Secret 权限 • Secret 必须在 Pod 同一命名空间

4.2 imagePullSecrets 的工作流程

imagePullSecrets 是 Pod 规范中的一个字段,用于向 kubelet 提供访问私有镜像仓库的认证凭据。其工作流程包含 定义、关联、读取 和 传递 四个阶段。

阶段 操作者 动作描述 常见失败原因
1. 定义 用户 / 管理员 创建 kubernetes.io/dockerconfigjson 类型的 Secret,包含 registry 地址、用户名、密码或 。 Secret 格式错误、base64 编码不正确
2. 关联 用户 / 控制器 在 Pod 的 spec.imagePullSecrets 中引用 Secret 名称,或通过 ServiceAccount 的 imagePullSecrets 字段自动注入。 Secret 名称拼写错误、命名空间不匹配
3. 读取 kubelet kubelet 使用 Pod 绑定的 ServiceAccount 向 API Server 发起 GET 请求,读取 Secret 的 .dockerconfigjson 数据。 RBAC 权限不足(ServiceAccount 缺少 get secret 权限)
4. 传递 kubelet → 容器运行时 kubelet 将解析后的认证信息(registry、username、password)通过 CRI 接口传递给容器运行时。 运行时版本不兼容、认证信息过期
最佳实践:推荐使用 ServiceAccount 自动注入 方式管理 imagePullSecrets,避免在每个 Pod 中手动声明。只需在 ServiceAccount 的 imagePullSecrets 字段中列出 Secret,kubelet 会自动将其注入到使用该 ServiceAccount 的所有 Pod 中。

4.3 自动注入 vs 手动指定

两种方式在 RBAC 权限检查路径上存在差异,理解这一点对排查问题至关重要:

  • 手动指定(spec.imagePullSecrets):kubelet 直接读取 Pod 中声明的 Secret。权限检查基于 Pod 的 ServiceAccount。
  • 自动注入(ServiceAccount 的 imagePullSecrets):kubelet 先读取 ServiceAccount 对象,再读取其引用的 Secret。权限检查同样基于 Pod 的 ServiceAccount,但多了一次 get ServiceAccount 的 API 调用。
imagePullSecrets 注入方式对比 手动指定 Pod spec.imagePullSecrets kubelet 直接 GET Secret 传递认证信息给运行时 自动注入(推荐) ServiceAccount.imagePullSecrets kubelet 读取 ServiceAccount kubelet 读取引用的 Secret 自动注入到 Pod 并传递

4.4 权限不足时的典型错误事件

当 RBAC 权限不足导致 kubelet 无法读取 imagePullSecrets 时,通常会触发以下事件:

# 通过 kubectl describe pod 查看事件
Events:
  Type     Reason     Age   From               Message
  ----     ------     ----  ----               -------
  Normal   Scheduled  10s   default-scheduler  Successfully assigned default/myapp to node-1
  Warning  Failed     5s    kubelet            Failed to pull image "myregistry.azurecr.io/myapp:v1": 
                                               rpc error: code = Unknown desc = failed to pull and unpack image: 
                                               unauthorized: authentication required
  Warning  Failed     5s    kubelet            Error: ErrImagePull
  Normal   BackOff    3s    kubelet            Back-off pulling image "myregistry.azurecr.io/myapp:v1"
  Warning  Failed     3s    kubelet            Error: ImagePullBackOff
排查要点:如果事件中显示 unauthorized 或 authentication required,但确认 Secret 内容正确,请立即检查 Pod 的 ServiceAccount 是否拥有 get Secret 的 RBAC 权限。使用 kubectl auth can-i get secret <secret-name> --as=system:serviceaccount:<namespace>:<sa-name> 快速验证。

4.5 关键总结

  • kubelet 拉取镜像的完整链路:API Server → kubelet → 读取 imagePullSecrets → 容器运行时 → 镜像仓库。
  • imagePullSecrets 的读取阶段是 RBAC 权限问题的“瓶颈点”,kubelet 使用 Pod 的 ServiceAccount 进行 API 调用。
  • 自动注入方式(通过 ServiceAccount)比手动指定更易于管理,但同样受 RBAC 约束。
  • 权限不足时,错误事件表现为 ImagePullBackOff + unauthorized,容易与 Secret 内容错误混淆,需结合 RBAC 检查进行区分。