docker manifest create annotate and push in a script

6.6k views Asked by At

I have DockerHub build images for x86_64 for my projects. The images have this naming: myname/project:version_architecture; such as foo/bar:1.0.0_x86_64.

Then I build aarch64 images on a RPi4: foo/bar:1.0.0_aarch64, which I then push to DockerHub.

Now I want a manifest that contains both of them so that I can use foo/bar:1.0.0 anywhere and it will work.

AFAIK, The following commands should work (to be run on the RPi):

docker build -t foo/bar:1.0.0_aarch64 .
docker push foo/bar:1.0.0_aarch64

docker manifest create foo/bar:1.0.0 foo/bar:1.0.0_aarch64
docker manifest annotate foo/bar:1.0.0 foo/bar:1.0.0_x86_64
docker manifest push foo/bar:1.0.0

But for some reason, the annotate step sometimes fails:

manifest for image foo/bar:1.0.0_x86_64 does not exist in foo/bar:1.0.0

And the following workaround (usually) works instead:

docker build -t foo/bar:1.0.0_aarch64 .
docker push foo/bar:1.0.0_aarch64

docker manifest create foo/bar:1.0.0 foo/bar:1.0.0_aarch64
docker manifest annotate foo/bar:1.0.0 foo/bar:1.0.0_x86_64
docker manifest create foo/bar:1.0.0 foo/bar:1.0.0_x86_64 --amend
docker manifest annotate foo/bar:1.0.0 foo/bar:1.0.0_aarch64
docker manifest push foo/bar:1.0.0

Am I missing something?

1

There are 1 answers

3
Dmitry On BEST ANSWER

To create multiarch manifest you need to build 2 images with different arch

export ARCH=i386
docker build -t foo/bar:1.0.0-${ARCH}" --build-arg ARCH=${ARCH} --network=host .
docker tag "foo/bar:1.0.0-${ARCH}" "${REGISTRY}.dkr.ecr.${REGION}.amazonaws.com/foo/bar:1.0.0-${ARCH}"
docker push "${REGISTRY}.dkr.ecr.${REGION}.amazonaws.com/foo/bar:1.0.0-${ARCH}"

After that you add another image (built from another architecture):

export ARCH=arm64v8
docker build -t foo/bar:1.0.0-${ARCH}" --build-arg ARCH=${ARCH} --network=host .
docker tag "foo/bar:1.0.0-${ARCH}" "${REGISTRY}.dkr.ecr.${REGION}.amazonaws.com/foo/bar:1.0.0-${ARCH}"
docker push "${REGISTRY}.dkr.ecr.${REGION}.amazonaws.com/foo/bar:1.0.0-${ARCH}"

Then you can create a root manifest, add links to actual images and edit it if you need to:

export DOCKER_CLI_EXPERIMENTAL=enabled
docker manifest create "${REGISTRY}.dkr.ecr.${REGION}.amazonaws.com/foo/bar:1.0.0" \
    --amend  "${REGISTRY}.dkr.ecr.${REGION}.amazonaws.com/foo/bar:1.0.0-i386" \
    --amend "${REGISTRY}.dkr.ecr.${REGION}.amazonaws.com/foo/bar:1.0.0-arm64v8"
docker manifest annotate --arch amd64 "${REGISTRY}.dkr.ecr.${REGION}.amazonaws.com/foo/bar:1.0.0" "${REGISTRY}.dkr.ecr.${REGION}.amazonaws.com/foo/bar:1.0.0-i386"
docker manifest inspect "${REGISTRY}.dkr.ecr.${REGION}.amazonaws.com/foo/bar:1.0.0"
docker manifest push "${REGISTRY}.dkr.ecr.${REGION}.amazonaws.com/foo/bar:1.0.0"

This allows you to have root manifest with a links to arch-manifests. I used annotate to update image architecture to match exact node type.