How to push a multi-architecture Docker image to Docker Hub - Arm32v7 & Arm64v8
In the last post I took care of the x86_64 image generated by Docker Hub for us. The other images (Arm32v7 and Arm64v8) will have to be built at home with my own devices.
Get the manifest tool
I just downloaded a binary from the main Github repository. I chose version 0.7.0 for armv7 and arm64 architectures.
I just renamed to downloaded file and moved it to /usr/local/bin
:
wget https://github.com/estesp/manifest-tool/releases/download/v0.7.0/manifest-tool-linux-arm64
mv manifest-tool-linux-arm64 manifest-tool
chmod +x manifest-tool
./manifest-tool --help # Just to check that it's working
mv manifest-tool /usr/local/bin/
It will be integrated into Docker but for now we don’t have any estimates on when.
Let’s do it
I built a small shell script to build and push all images (thanks to this French web site).
Let’s break it into smaller pieces to explain.
In case this script is modified in the future, everything below relates to updateHub.sh
in revision 1cd5da3683ea14e63a37eab9cf9d653dd4159b5a.
Update local copy
if [ "$(git status --untracked-files=no --porcelain)" ]; then
echo "Uncommitted changes. Exiting..."
exit 1
fi
git pull --rebase
To avoid any errors the script fail if there is uncommitted / modified files. New files are allowed. If that’s OK let’s pull new commits.
Set some variables
TAG=$(git describe --tags $(git rev-list --tags --max-count=1))
MAJMIN=`echo $TAG | cut -d . -f 1,2 `
ARCH=`dpkg --print-architecture`
TAG
to the latest tag in the repository, let’s say 3.6.6.MAJMIN
will only keep the major and minor number so 3.6.ARCH
will be set to the dpkg (Debian) architecture so armhf / arm64.
Update working copy to latest tag
git checkout $TAG
Loop over all images
for dir in alpine-python3 alpine-python2 alpine-mosquitto alpine-minidlna alpine-nginx alpine-python3-cron alpine-nginx-php
do
...
done
Here I loop over all the image I want to push on Docker Hub. The order is important if there are some dependency (alpine-python3 has to be before alpine-python3-cron)
Check if the image already exists
NBARCH=`manifest-tool inspect seblucas/$dir:$TAG | grep "Arch:" | wc -l`
if [[ $NBARCH -gt 1 ]]; then
echo "Image seblucas/$dir:$TAG already uptodate"
continue
fi
I’m not proud of this, I have to check if the image already exists on Docker Hub, I have not found a clever way so I’m using manifest-tool
to check the image manifest and count the number of arch which has to be greater than 1.
If you have a better idea, please post a comment or propose a PR ;).
Build and push the image
cd $dir
docker build . -t seblucas/$dir:$ARCH-$TAG -t seblucas/$dir:$MAJMIN
docker push seblucas/$dir:$ARCH-$TAG
Again to handle image dependency we generate an additional local tag.
Push the manifest
if [[ $ARCH == "armhf" ]]; then
echo "Manifest uploading ..."
sed -i "s|{image}|$dir|g" ../manifest.yaml
sed -i "s|{tag}|$TAG|g" ../manifest.yaml
sed -i "s|{majmin}|$MAJMIN|g" ../manifest.yaml
manifest-tool push from-spec ../manifest.yaml
git checkout $TAG -- ../manifest.yaml
fi
I’ve created a basic manifest with placeholders that I replace with sed
. Then I just push the manifest and that’s done.
Conclusion
That’s it, that wasn’t that hard to do. If you spot any errors / enhancements, please share them with me.
The big downside I see is that I have to follow an order : amd64 then arm64v8 and finally arm32v7. So for 2 hours the multi-architecture image is not really ready.
Todo
Maybe for a next episode in the serie :
- Actually test the script in cron (for now I start it manually).
- Explain how to use
mplatform/mquery
. - Delete the unneeded tags in Docker Hub (amd64-{TAG}, armhf-{TAG}, …), maybe by using Docker Hub Api.
- Add other architectures.