dockerdocker-registrymultiarch

docker manifest create annotate and push in a script


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?


Solution

  • 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.