2. Docker 与 Kubernetes 中的镜像拉取机制
理解镜像拉取流程是设计 Secrets 加密传输方案的前提。Docker 作为容器运行时,其 docker pull 流程决定了镜像层如何从 Registry 传输到本地;而 Kubernetes 中的 kubelet 则在此基础上增加了认证、镜像拉取策略(ImagePullPolicy)和 Secrets 挂载等控制逻辑。本章将分别拆解这两个流程,并对比其关键差异。
2.1 Docker pull 流程详解
docker pull 命令的执行过程可划分为 5 个阶段:认证、Manifest 获取、层校验、并行下载、解压与索引更新。下图展示了完整的请求链路:
2.1.1 各阶段详细说明
| 阶段 | 触发条件 | 核心操作 | 涉及协议/数据 |
|---|---|---|---|
| ① 认证 | Registry 返回 401 Unauthorized | 向 Auth Service 请求 Bearer | HTTP Basic / OAuth2 |
| ② 获取 Manifest | 验证通过 | 请求 /v2/<name>/manifests/<tag> |
Docker V2 Manifest (JSON) |
| ③ 层校验 | Manifest 返回后 | 比对本地已有层的 digest,确定需下载的层 | SHA256 摘要 |
| ④ 并行下载 | 确定缺失层列表 | 并发 HTTP GET 请求 /v2/<name>/blobs/<digest> |
分块传输 / 断点续传 |
| ⑤ 解压 & 索引 | 所有层下载完成 | 解压 tar.gz 层,更新本地镜像索引 | overlay2 / aufs 存储驱动 |
优化切入点: 阶段④的并行下载是网络 I/O 最密集的环节。若 Registry 返回的 Manifest 或 Blob 数据被篡改,将直接威胁镜像完整性。Secrets 加密传输方案应重点保护 Manifest 和 Blob 的传输通道。
2.2 kubelet 拉取镜像流程
Kubernetes 中,kubelet 负责为 Pod 拉取容器镜像。与 docker pull 不同,kubelet 的流程增加了 Pod 级别的认证管理 和 ImagePullPolicy 控制。下图展示了 kubelet 从 Pod 调度到镜像就绪的完整路径:
2.2.1 ImagePullPolicy 决策逻辑
kubelet 在步骤③中根据 ImagePullPolicy 决定是否发起拉取。以下是三种策略的行为对比:
| 策略 | 行为 | 适用场景 | 网络请求次数 |
|---|---|---|---|
| Always | 每次启动 Pod 都拉取最新镜像 | 开发环境、使用 :latest 标签 |
每次 Pod 启动至少 1 次 |
| IfNotPresent | 仅当本地不存在该镜像时拉取 | 生产环境、使用固定版本标签 | 仅首次部署或镜像被清理时 |
| Never | 从不拉取,仅使用本地镜像 | 离线环境、预置镜像场景 | 0 次 |
2.2.2 imagePullSecrets 的传递路径
Secrets 从创建到被 kubelet 使用的完整路径如下:
- 用户创建 Secret:
kubectl create secret docker-registry <name> --docker-server=<server> --docker-username=<user> --docker-password=<pass> - Secret 存储于 etcd:API Server 将 Secret 以 Base64 编码存入 etcd,默认未加密。
- Pod 引用 Secret:在 Pod Spec 的
spec.imagePullSecrets字段中引用 Secret 名称。 - kubelet 读取 Secret:kubelet 通过 API Server 的 Watch 机制获取 Pod 更新,同时请求关联的 Secret 资源。
- 构造 dockerconfigjson:kubelet 将 Secret 中的
.dockerconfigjson数据传递给容器运行时。 - 运行时认证:容器运行时(如 containerd)使用该凭证向 Registry 发起认证请求。
安全风险提示: 默认情况下,etcd 中的 Secret 以明文 Base64 存储。若 etcd 被攻破或备份泄露,所有 Registry 凭证将暴露。这正是后续章节引入 Secrets 加密传输方案的核心动因。
2.3 Docker pull 与 kubelet 拉取流程对比
下表从认证管理、触发方式、并发控制、安全边界四个维度对比两种拉取机制:
| 对比维度 | Docker pull | kubelet 拉取 |
|---|---|---|
| 认证来源 | 本地 ~/.docker/config.json |
Pod 关联的 imagePullSecrets |
| 触发方式 | 用户手动执行命令 | Pod 调度 / 重启 / ImagePullPolicy 触发 |
| 并发下载 | Docker Engine 内部并发(默认 3 个 goroutine) | 由容器运行时控制(如 containerd 支持并发层下载) |
| 凭证生命周期 | 持久化在本地文件,长期有效 | 随 Pod 生命周期,可动态更新 |
| 安全边界 | 依赖本地文件权限(0600) | 依赖 RBAC + etcd 存储安全 |
| 镜像缓存 | 本地镜像层缓存,全局共享 | 节点级缓存,由容器运行时管理 |
2.4 流程中的安全薄弱点
基于上述流程分析,可以识别出以下与 Secrets 相关的安全薄弱点:
- etcd 存储未加密:imagePullSecrets 在 etcd 中仅 Base64 编码,无加密保护。
- kubelet 与 API Server 通信:虽然使用 TLS,但若证书管理不当,存在中间人攻击风险。
- 容器运行时与 Registry 通信:默认使用 HTTPS,但部分私有 Registry 可能降级为 HTTP。
- Secrets 在节点上的临时缓存:kubelet 可能将 Secrets 缓存在内存或磁盘中,若节点被入侵,凭证可能泄露。
- 镜像拉取日志泄露:kubelet 日志可能包含 Registry URL 和认证头信息。
本章小结: Docker pull 是单机手动操作,kubelet 拉取是集群级自动化流程。两者都依赖 Registry 认证,但 kubelet 的凭证管理更复杂,涉及 etcd、API Server、RBAC 等多个组件。后续章节将针对这些薄弱点,设计端到端的 Secrets 加密传输方案。