Dbercules
Dbercules

Reputation: 719

Republish Docker Image with Preserved Digest to Different Registry

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.

Upvotes: 2

Views: 3342

Answers (3)

BMitch
BMitch

Reputation: 264761

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:

  • google/go-containerregistry's crane (crane copy)
  • RedHat's skopeo (skopeo copy)
  • My own regclient's regctl (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.

Upvotes: 2

Dbercules
Dbercules

Reputation: 719

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:

skopeo copy \
    --dest-creds='usr:psw' \
    --preserve-digests \
    --override-arch amd64 \
    docker://docker.io/alpine@sha256:c0d488a800e4127c334ad20d61d7bc21b4097540327217dfab52262adc02380c \
    docker://registry.io/alpine@sha256:c0d488a800e4127c334ad20d61d7bc21b4097540327217dfab52262adc02380c 

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!

Upvotes: 6

JohnXF
JohnXF

Reputation: 1097

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.

docker image pull centos:centos7
docker tag centos:centos7 my-registry.io/centos7:centos7
docker push my-registry.io/centos/centos7

Upvotes: 0

Related Questions