重新标记Docker镜像时如何跨Registry保留Digest?
Docker跨Registry镜像标记时保留Digest的解决方案
背景
我们的镜像仓库有两个访问地址:一个是VPC内部地址,供内部使用;另一个是外部地址,供客户拉取镜像。目前已切换为基于digest的引用系统,通过sha256摘要拉取镜像。现在希望为客户提供离线安装选项,使用docker save导出镜像后再通过docker load加载,但此过程无法保留digest信息。
核心问题
使用docker tag重新标记镜像时,如何将digest从一个Registry名称转移到另一个?
场景示例
1. 拉取内部Registry镜像并查看Digest
$ docker pull internal.registry.local/development/img:0.23.0@sha256:9c3c425cc0114e358c58800b544e104be5d5c8f3b594871dafbaf9f28444d267 internal.registry.local/development/img@sha256:9c3c425cc0114e358c58800b544e104be5d5c8f3b594871dafbaf9f28444d267: Pulling from development/img Digest: sha256:9c3c425cc0114e358c58800b544e104be5d5c8f3b594871dafbaf9f28444d267 Status: Image is up to date for internal.registry.local/development/img:0.23.0@sha256:9c3c425cc0114e358c58800b544e104be5d5c8f3b594871dafbaf9f28444d267 internal.registry.local/development/img:0.23.0@sha256:9c3c425cc0114e358c58800b544e104be5d5c8f3b594871dafbaf9f28444d267
查看镜像digest信息:
$ docker image ls --digests internal.registry.local/development/img 0.23.0 sha256:9c3c425cc0114e358c58800b544e104be5d5c8f3b594871dafbaf9f28444d267 dc9c4901ced1 8 weeks ago 10.7GB
通过inspect查看镜像元数据:
$ docker image inspect internal.registry.local/development/img@sha256:9c3c425cc0114e358c58800b544e104be5d5c8f3b594871dafbaf9f28444d267 | jq '.[] | { Id, RepoTags, RepoDigests }' { "Id": "sha256:dc9c4901ced19676f90c95d0f82c85ba97d15ba1c39d38ca9d692f3d3658bd43", "RepoTags": [ "internal.registry.local/development/img:0.23.0" ], "RepoDigests": [ "internal.registry.local/development/img@sha256:9c3c425cc0114e358c58800b544e104be5d5c8f3b594871dafbaf9f28444d267" ] }
2. 同一Registry内打标签,Digest保留
$ docker tag internal.registry.local/development/img@sha256:9c3c425cc0114e358c58800b544e104be5d5c8f3b594871dafbaf9f28444d267 internal.registry.local/development/img:0.23.0-custom
查看结果:
$ docker image ls --digests internal.registry.local/development/img 0.23.0 sha256:9c3c425cc0114e358c58800b544e104be5d5c8f3b594871dafbaf9f28444d267 dc9c4901ced1 8 weeks ago 10.7GB internal.registry.local/development/img 0.23.0-custom sha256:9c3c425cc0114e358c58800b544e104be5d5c8f3b594871dafbaf9f28444d267 dc9c4901ced1 8 weeks ago 10.7GB
3. 跨Registry打标签,Digest丢失
$ docker tag internal.registry.local/development/img@sha256:9c3c425cc0114e358c58800b544e104be5d5c8f3b594871dafbaf9f28444d267 external.example.org/production/img:0.23.0
查看结果:
$ docker image ls --digests internal.registry.local/development/img 0.23.0 sha256:9c3c425cc0114e358c58800b544e104be5d5c8f3b594871dafbaf9f28444d267 dc9c4901ced1 8 weeks ago 10.7GB internal.registry.local/development/img 0.23.0-custom sha256:9c3c425cc0114e358c58800b544e104be5d5c8f3b594871dafbaf9f28444d267 dc9c4901ced1 8 weeks ago 10.7GB external.example.org/production/img 0.23.0 <none> dc9c4901ced1 8 weeks ago 10.7GB
4. 通过外部Registry拉取Digest可关联(但非离线场景所需)
$ docker pull external.example.org/production/img@sha256:9c3c425cc0114e358c58800b544e104be5d5c8f3b594871dafbaf9f28444d267 external.example.org/production/img@sha256:9c3c425cc0114e358c58800b544e104be5d5c8f3b594871dafbaf9f28444d267: Pulling from production/img Digest: sha256:9c3c425cc0114e358c58800b544e104be5d5c8f3b594871dafbaf9f28444d267 Status: Downloaded newer image for external.example.org/production/img@sha256:9c3c425cc0114e358c58800b544e104be5d5c8f3b594871dafbaf9f28444d267 external.example.org/production/img@sha256:9c3c425cc0114e358c58800b544e104be5d5c8f3b594871dafbaf9f28444d267
查看结果:
$ docker image ls --digests internal.registry.local/development/img 0.23.0 sha256:9c3c425cc0114e358c58800b544e104be5d5c8f3b594871dafbaf9f28444d267 dc9c4901ced1 8 weeks ago 10.7GB internal.registry.local/development/img 0.23.0-custom sha256:9c3c425cc0114e358c58800b544e104be5d5c8f3b594871dafbaf9f28444d267 dc9c4901ced1 8 weeks ago 10.7GB external.example.org/production/img 0.23.0 sha256:9c3c425cc0114e358c58800b544e104be5d5c8f3b594871dafbaf9f28444d267 dc9c4901ced1 8 weeks ago 10.7GB
我们尝试过以下命令均无法直接实现跨Registry保留Digest:
docker tag A/img@sha B/img:tag docker tag A/img:tag B/img:tag docker tag A/img:tag@sha B/img:tag docker tag A/img@sha B/img@sha # 执行报错
可行解决方案
方案1:临时推送镜像到外部Registry(推荐)
由于两个Registry指向同一仓库,推送仅更新元数据,不会重复上传镜像层,速度极快:
# 标记外部Registry标签 docker tag internal.registry.local/development/img@sha256:9c3c425cc0114e358c58800b544e104be5d5c8f3b594871dafbaf9f28444d267 external.example.org/production/img:0.23.0 # 推送到外部Registry docker push external.example.org/production/img:0.23.0 # 推送完成后,本地镜像自动添加对应RepoDigests条目 docker image inspect external.example.org/production/img:0.23.0 | jq '.[] | .RepoDigests' # 导出带Digest关联的镜像 docker save external.example.org/production/img:0.23.0@sha256:9c3c425cc0114e358c58800b544e104be5d5c8f3b594871dafbaf9f28444d267 -o img-0.23.0.tar
方案2:为离线镜像附带Digest验证文档
若无法推送,可在离线包中附带文档说明镜像对应的Digest值,客户加载后手动验证:
# 客户加载镜像 docker load -i img-0.23.0.tar # 查看镜像ID docker image ls # 验证镜像ID的sha256是否与文档中的Digest匹配 docker image inspect [image-id] | jq '.[] | .Id' # 手动标记外部Registry标签 docker tag [image-id] external.example.org/production/img:0.23.0
后续客户使用Digest拉取时,Docker会自动匹配本地镜像,无需重新下载。
方案3:手动修改本地镜像元数据(不推荐)
直接修改Docker存储的镜像配置文件添加RepoDigests条目,但此操作不被官方支持,易导致镜像损坏:
- 找到镜像配置文件:
/var/lib/docker/images/[image-id]/config.json - 在
RepoDigests数组中添加条目:"external.example.org/production/img@sha256:9c3c425cc0114e358c58800b544e104be5d5c8f3b594871dafbaf9f28444d267" - 重启Docker服务生效
内容的提问来源于stack exchange,提问作者Philipp Stephan
相关产品推荐
相关产品推荐

