19

There's a well-known approach to have docker images copied from one container registry to another. In case the original registry is dockerhub, the typical workflow would be something like this:

docker pull <image:tag>
docker tag <image:tag> <new-reg-url/uid/image:tag>
docker push <new-reg-url/uid/image:tag>

Now, how do you the above when dealing with images with multi-architecture layers?

As per the information in this link, you can rely on buildx to construct multi-arch images, and while doing that, you can also upload those to whichever repo you wish, but how do i do this without having to first build the images?

Looks like buildx cli has unnecessarily (?) coupled the uploading process with the building one. Any suggestions?

Thanks!

Rodny Molina
  • 193
  • 1
  • 6

2 Answers2

24

While the docker pull ...; docker tag ...; docker push ... syntax is the easy way to move images between registries, it has a couple drawbacks. First, as you've seen, is that it dereferences a multi-platform image to a single platform. And the second is that it pulls all layers to the docker engine even if the remote registry already has those layers, making it a bad method for ephemeral CI workers that would always need to pull every layer.

To do this, I prefer talking directly to the registry servers rather than the docker engine itself. You don't need the functionality from the engine to run the images, all you need is the registry API. Docker has documented the original registry API and OCI recently went 1.0 on the distribution-spec which should get us some standardization.

There's a variety of tooling based on those specs, from the docker engine itself and containerd, to skopeo, google's crane, and I've also been working on regclient. Doing this with regclient's regctl command looks like:

regctl image copy <source_image:tag> <target_image:tag>

And the result is the various layers, image config, manifests, and multi-platform manifest list will be copied between registries, but only for the layers that don't already exist on the target registry.

BMitch
  • 231,797
  • 42
  • 475
  • 450
  • 5
    `regctl` works like a charm, it does exactly what i needed, and even more (as you indicated), as it's smart enough to detect pre-existing layers and prevent unnecessary i/o. I hope some day these new features are incorporated into the high-level container runtimes (e.g. docker, podman, etc) to save us needing to learn yet-another tool. Thanks a lot @BMitch! – Rodny Molina Jul 30 '21 at 01:04
  • What if you cannot communicate directly with the target registry? I have to go through a bastion host . so I backup to a tar file, upload the tart file to a host the remote registry has access to, from the registry server I can download the tar file, load the image, and then push it to the target registry. It's convoluted thanks to security requirements. – majorgear Jun 05 '23 at 22:12
  • @majorgear specifically with regctl it can output to an OCI Layout which is a filesystem equivalent of a repository. Either with `regctl image copy` where the source or target is `ocidir://$dir` or `regctl image export` and `regctl image import` to use a tgz file instead. – BMitch Jun 05 '23 at 23:07
  • My security team denied my request to install regctl , so what I did was build each image with architecture-specific tags in order to manage each image individually. I learned that the local registry does't support multi arch images, which was the root of my problem. – majorgear Jun 09 '23 at 13:54
10

2022 (docker builtin) solution

It's posible to perform the copy using the not-well-documented built in command docker buildx imagetools create using --tag

# i.e.
OLD_TAG=registry.example.com/namespaced/repository/example-image:old-tag
NEW_TAG=registry.example.com/namespaced/repository/example-image:new-tag
# we can
docker buildx imagetools create --tag "$NEW_TAG" "$OLD_TAG"

Reference documentation

IMPORTANT NOTE: There is no support at the moment to perform this operation against different repositories. Given tags like

OLD_TAG=registry.example.com/namespaced/repository/example-image:latest
NEW_TAG=registry.example.com/other-repository/example-image:latest

You end with an error like

error: multiple repositories currently not supported

For this situation I'm going to test the actual accepted answer

laconbass
  • 17,080
  • 8
  • 46
  • 54