I pull images from public registries such as DockerHub, and push them to a singular private registry. This is a simple process for images in the format of image:tag
but not so for those of image@digest
.
I want to re-publish, or push in Docker’s terminology, images from a public registry to my private registry whilst maintaining the integrity of the exact immutable image. I want to preserve the digest so there’s no abstraction between the digest referenced from my private registry to the image’s source in a public registry.
I attempted to perform the same docker push
command that works for image:tag
on image@digest
, but to no avail.
image:tag push
docker login -u usr -p psw registry.io
docker image pull docker.io/alpine:3.17.0
docker image push registry.io/alpine:3.17.0
...
ok
image@digest: push
docker login -u usr -p psw registry.io
docker image pull docker.io/alpine@sha256:c0d488a800e4127c334ad20d61d7bc21b4097540327217dfab52262adc02380c
docker image push registry.io/alpine@sha256:c0d488a800e4127c334ad20d61d7bc21b4097540327217dfab52262adc02380c
...
cannot push a digest reference
I want to re-publish the image from source to target as-is. I could perform a re-tag, or a push with a different ID, but both result in altering the reference-able digest and a level of abstraction that seems unnecessary.
3
Answers
I wasn't able to solve this using Docker. Instead, I investigated Skopeo. v1.6.0 introduced the
--preserve-digests
flag that sounded laughably perfect. It was.I implemented it as follows:
After I'd completed the digest-preserving copy, I had some additional bits that I wanted to add but found the documentation a bit hard to navigate. I eventually found all of the answers and supplemental flags that I was looking for, so thought I should post here in case they help someone else. I had to read through the available transports (repository types) for use in Skopeo's copy command, which is where I discovered
--dest-creds
and--preserve-digests
, and I wasn't able to discover--override-arch
as a global flag immediately!What you want to do is rename the image and then push it. When you push an image to a repository you are pushing it to the repository specified by the image name. So first rename (changing the
tag
really) to include the registry you want to push to, then do the push.There are a variety of tools for managing images on registries. And most support copying the image, including the multi-platform manifest, without modifying the digest. A few examples include:
crane copy
)skopeo copy
)regctl image copy
)Using the docker CLI won’t work for this because pulling an image to docker dereferences the multi-platform manifest to your platform’s image. And when docker pushes an image, it may regenerate the image manifest json, possibly losing data like annotations, or changing spacing, and any single character change in the marshaled json will change the digest.