How to push a multi-architecture Docker image to Docker Hub - 2
This post is part of the Multi-Architecture Docker image series.
Jan 16, 2018
3 minute read

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 :

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 in revision 1cd5da3683ea14e63a37eab9cf9d653dd4159b5a.

Update local copy

if [ "$(git status --untracked-files=no --porcelain)" ]; then
  echo "Uncommitted changes. Exiting..."
  exit 1

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

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"

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

I’ve created a basic manifest with placeholders that I replace with sed. Then I just push the manifest and that’s done.


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.


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.

comments powered by Disqus