本节摘要:镜像与仓库的交互有三条路径:podman pull/push 的短路径、skopeo copy 的可控直传路径、归档文件的过桥路径。核心概念是 tag 与 digest 的语义差异——tag 是会移动的指针,digest 是内容指纹,生产环境应当用 digest 锁定镜像。本节把三条路径与两个概念讲透,并给出一条供应链可追溯的镜像流转方案。
先立概念,否则后面所有操作都会含糊。tag(如 nginx:1.27-alpine)是仓库侧的"会移动的指针":维护者可以随时把同一个 tag 指向新的内容——安全补丁、配置变更,甚至完全不同的构建。digest(sha256:后面跟一长串十六进制)是镜像内容的密码学指纹:内容由层与配置共同决定,任何一比特变化指纹就变。
推论很直接:用 tag 拉取,你得到的是"拉取那一刻它碰巧指向的东西";用 digest 拉取,你得到的是"你指定过的那份数据"。开发环境用 tag 方便升级,生产环境必须用 digest 保证可复现——这原则对 Docker 与 Podman 一视同仁,但家族工具链让"digest 贯穿"变得顺手:
# 拉取时顺带拿到 digest podman pull docker.io/library/nginx:1.27-alpine # Resolved "nginx" as an alias # ... sha256:3e4a5b...(完整摘要回显) # 之后所有环境用 digest 精确锁定 podman run -d docker.io/library/nginx@sha256:3e4a5b...:版本略 # 注意写法:镜像名与 digest 之间是 @ 而不是冒号 # 查看本地镜像的指纹 podman images --digests | head -3 # REPOSITORY TAG DIGEST IMAGE ID ... # digest 列即内容指纹,可用于核对两台机器是否持有同一份镜像
路径一:podman 的短路径。pull 与 push,最接近 Docker 习惯。适合日常开发:交互简单,直接进共享存储。它的"短"也意味着控制粒度少——想改镜像格式、想跨仓库搬运,它没有开关。
路径二:skopeo 的可控直传。仓库到仓库直接复制,不落本地磁盘,可带格式转换与签名同步:
# 从 Docker Hub 搬到内部镜像仓库,一步到位 skopeo copy --dest-creds dev:token \ docker://docker.io/library/postgres:16-alpine \ docker://registry.internal.example.com/base/postgres:16-alpine # Copying blob ... done(层直传,不占本地空间) # 需要格式转换时(目标仓库要求 OCI 布局): skopeo copy --format oci \ docker://docker.io/library/postgres:16-alpine \ docker://registry.internal.example.com/base/postgres:16 # docker 格式与 OCI 格式在此一行互转——Docker 工作流里 # 等价操作需要 pull、export、convert、push 多段接力
路径三:归档过桥。离线环境或跨引擎搬运的保险路径。三种归档格式各有用处:oci-archive(OCI 标准布局的 tar 包,通用性最好)、docker-archive(兼容 docker save 的产物,与 Docker 机器互通)、dir(解开的目录树,便于检查与打补丁)。
# 打包发往离线环境 skopeo copy containers-storage:localhost/myapp:1.0 \ oci-archive:/tmp/myapp-1.0.tar # 离线环境从归档加载进本地存储 skopeo copy oci-archive:/tmp/myapp-1.0.tar \ containers-storage:localhost/myapp:1.0 # 检查归档内容不需要解包 skopeo inspect oci-archive:/tmp/myapp-1.0.tar

把概念与路径串成一条真实流程。背景:团队需要把第三方基础镜像引入内部仓库,并保证半年后仍能证明"我们运行的就是当初审计过的那一份"。
第一步,引入时锁定指纹:skopeo inspect 拿到 digest,登记进团队的基础镜像台账。第二步,直传入内部仓库并保留 digest:skopeo copy 默认保持内容不变,digest 不会漂移;如果目标仓库启用内容信任,签名随镜像同步(签名细节在第 6.3 节)。第三步,应用镜像引用一律写 digest,CI 里的部署清单由 digest 而非 tag 生成。第四步,升级时走同一流程:新 digest 入台账、换引用、留旧记录。
这套流程对 Docker 用户同样成立,差别在工具顺手程度:家族链路里 inspect、copy、storage 三段无缝衔接,不需要中间文件;Docker 路径里 inspect 远程镜像要先拉取、跨仓库搬运要本地中转。变式:如果团队有多套运行时(部分机器仍是 Docker),把过桥格式换成 docker-archive,归档在两种引擎间通用。
再补一个让流程落地的细节:digest 台账本身放哪。小团队一张受版本管理的表格就够,列四项——镜像名、引入时的 digest、引入日期、用途备注。规模变大后把这份台账变成 CI 里的一等公民:部署清单模板只接受 digest 变量、变量取值来自台账文件、台账变更走代码评审。这条演进路线的关键在于台账从"文档"升级为"部署的输入"——一旦部署脚本只认台账,忘记登记的镜像根本进不了生产,流程从靠自觉变成了靠机制。镜像管理的成熟度标尺,说到底就是这条链从人肉到机制的长度。