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