Dockerized the Apple Silicon

Before christmas 2020, a lot of people were working on porting their software to the new Mac Apple M1 Silicon family. More and more people are buying one:) It’s a great adventure, and the new ARM processor is an amazing piece of hardware. For me it’s the best Mac ever. The Rosetta 2 Intel CPU emulation made it possible to bootstrap the ARM based world or better a Multi Architecture world! The new Apple Virtualization Framework allows to create lighter Linux VMs. Docker delivered the first Docker for Desktop M1 Preview on December 10 and since December 17, 2020 Parallels® Desktop 16 for M1 Mac Technical Preview is available.

In my previous blog posts, I have containerized and kuberized the Silicon successfully with the vftool to create Ubuntu VMs. Its a bit hacky but useful! Now it is time to dockerize the Silicon with more comfort.

Install the Docker for Desktop

Setup the Docker for Desktop M1 Preview

Before you can start your Docker Container adventure, you must be an accepted part of the Docker Developer Preview programme :) A really nice and helpful community. Your are welcome.

Find the link in the Docker slack channel or download the Docker for Desktop M1 Preview 7 and let it run.

Docker for Desktop Preference

$ docker version
 Cloud integration: 1.0.2
 Version:           20.10.0
 API version:       1.41
 Go version:        devel +37a32a1833 Thu Dec 3 21:34:39 2020 +0000
 Git commit:        7287ab3890
 Built:             Wed Dec  9 06:23:12 2020
 OS/Arch:           darwin/arm64
 Context:           default
 Experimental:      true

Server: Docker Engine - Community
  Version:          20.10.0
  API version:      1.41 (minimum version 1.12)
  Go version:       go1.13.15
  Git commit:       eeddea2
  Built:            Tue Dec  8 19:01:40 2020
  OS/Arch:          linux/arm64
  Experimental:     true
  Version:          v1.4.3
  GitCommit:        269548fa27e0089a8b8278fc4fc781d7f65a939b
  Version:          1.0.0-rc92
  GitCommit:        ff819c7e9184c13b7c2607fe6c30ae19403a7aff
  Version:          0.19.0
  GitCommit:        de40ad0

Yes, Docker did it: Dockerized the Silicon successfully!

Features are:

  • ARM ready Docker Engine 20.10 and CLI Tools are available
  • Docker for Desktop 3 UI is available
  • Auto update isn’t working
  • There are some trouble with internal host DNS
    • Kubernetes needs this!
  • Filesystem performance can be better
  • QEMU is available
    • Some amd64 binaries do not work!
    • Porting to ARM or fixes are on the way.
  • The new hub-tool is available in Preview 7
  • Works with Big Sur 11.1

Many thanks to the Docker Team for working really well. Great job!

It’s time to move on multi architecture container images

Today the Docker Community is well prepared for this challenge with multiple architectures. Don`t forget that the Hypriot Pirates made this possible. Their HypriotOS on Raspberry PIs at the beginning of 2015 was a big first step to move us in this ARM direction. Many thanks Dieter, Stefan, Govinda, Mathias and Andreas for their passion and Lukas for making Kubernetes available on Raspberry PIs.

Today, most ARM based Linux distributions support Docker and Kubernetes. It’s easy to make containers available on tiny embedded machines, hybrid clustering is container business as usual. See the new simple faasd raspberry PI edition that is based on containerd, runc and CNI. All container images supported by Docker are multi architectures that are available on the Docker Hub. The modern registries support the Image Distribution Specification. However, many open source projects and products lag behind these possibilities. Please accept that AMD64 is not enough anymore. Much more computing on the planet is based on ARM. Microsoft also announced on December 18, 2020 that they are working on a new Surface Chip based on ARM.

I hope this tiny example below motivates you to better create your software with multi arch support. Trust me, getting software up and running on lighter machines is amazing. Smarter solutions with fewer power consumption is the new sustainable challenge for the next generation of IT on planet earth.

Docker Developer Experience at the Silicon

It only takes a few steps to create Multi Arch Images or binaries with golang:

  1. Create a tiny Hello World Golang example
$ cat >hello-world.go <<EOF
package main

import (

func main() {
	fmt.Println("Hello, world!")
bee silicon \__/\__/\__/\__/\__/ on", runtime.GOOS , "-", runtime.GOARCH )
  1. Create a Multi Stage and Multi Arch Dockerfile to create the image:

The Docker OS supports QEMU and golang can cross compile. Use the Image Builder Pattern to split creation from runtime images.

$ cat >Dockerfile <<EOF
# compile it
FROM golang:1.15 as builder
WORKDIR /go/src/
COPY hello-world.go .
RUN GOOS=$TARGETOS GOARCH=$TARGETARCH go build -o hello-world .

# assemble the resulting image
FROM alpine:3.12 as prod
LABEL org.opencontainers.image.authors="Peter Rossbach"
LABEL org.opencontainers.image.source=
LABEL org.opencontainers.image.licenses=Apache-2.0
# copy the binary from the `build-stage`
COPY --from=builder /go/src/ /bin
CMD /bin/hello-world
LABEL org.opencontainers.image.created="${BUILD_DATE}"
LABEL org.opencontainers.image.revision="${BUILD_REVISION}"
  1. Setup a Multi Arch builder
$ docker buildx create --name builder
$ docker buildx inspect builder --bootstrap
$ docker buildx use builder
  1. Create the Multi Arch images and push it to the Docker Hub.

Only a single command is required to create the four images, create the references multi arch image manifest and push all five artifacts to the Docker Hub.

$ docker login --username <xxx> --password <yyy>
$ docker --context default buildx build \
	--platform linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6 \
	--push --tag rossbachp/multiarch-example:edge .
  1. Let it run locally
$ docker run --rm -ti \
Hello, world!

bee silicon \__/\__/\__/\__/\__/ on linux - arm64
$ docker inspect --format “{{.Architecture}}” “rossbachp/multiarch-examples:edge”

You also give the other platform images a chance to run it:

$ docker run --rm -ti --pull always --platform linux/amd64 \
Hello, world!

bee silicon \__/\__/\__/\__/\__/ on linux - amd64
$ docker inspect --format “{{.Architecture}}” “rossbachp/multiarch-examples:edge”

It’s that simple, give it a try or send me a nicer asciiart version…

\__/\__/  \__/\__/ bee42 solutions ...

You can find my project on github:

Automated the buildx workflow with Github Actions

An important next step is to build these images fully automatically. It takes time and uses local resources. Sometimes the QEMU emulation does not work well or it requires testing on real hardware. These setups must be well prepared. Use it in a cloud service and connect your special hardware to external runners. Create your Apple Silicon at Macstadium to test it or better buy one :innocent:

Most people today used Github to manage their source code and make the results available. With Github Actions you can automate easily the image building, testing and deployment.

Create a workflow file .github/workflows/release.yml to release your image. Check out my tiny Hello World project for more workflows to trigger after commit and nightly builds.

  • Only start publishing in Docker Hub workflow after tagging
  • Prepare the repository
    • Get the Docker Hub Access Token
    • Add the Docker Hub credentials to your github projects secrets settings.
    • Choose the right repository name
    • Login to the Docker Hub
  • Activate buildx and QEMU
  • Prepare for image caching
  • Build the multi arch and push it to the Docker Hub
name: Publish Releases to Hub

# When it's time to do a release do a full cross platform build for all supported
# architectures and push all of them to Docker Hub.
# Only trigger on semver shaped tags.
      - "v*.*.*"

    runs-on: ubuntu-20.04
        name: Checkout
        uses: actions/checkout@v2
        uses: FranzDiebold/github-env-vars-action@v2
        name: Prepare
        id: prep
        run: |
          DOCKER_IMAGE=rossbachp/${{ }}
          if [[ $GITHUB_REF == refs/tags/* ]]; then
          if [ "${{ github.event_name }}" = "schedule" ]; then
          if [[ $VERSION =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
            TAGS="$TAGS,${DOCKER_IMAGE}:latest,${DOCKER_IMAGE}:${{ env.CI_SHA_SHORT }}"
          echo ::set-output name=tags::${TAGS}
        name: Set up QEMU
        uses: docker/setup-qemu-action@v1
          platforms: all
        name: Set up Docker Buildx
        id: buildx
        uses: docker/setup-buildx-action@v1
          install: true
        name: Cache Docker layers
        uses: actions/cache@v2
          path: /tmp/.buildx-cache
          key: ${{ runner.os }}-buildx-${{ github.sha }}
          restore-keys: |
            ${{ runner.os }}-buildx-
        name: Builder instance name
        run: echo ${{ }}
        name: Available platforms
        run: echo ${{ steps.buildx.outputs.platforms }}
        name: Login to Docker Hub
        if: github.event_name != 'pull_request'
        uses: docker/login-action@v1
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}  
        name: Build and push
        id: docker_build
        uses: docker/build-push-action@v2
          builder: ${{ }}
          context: .
          file: ./Dockerfile
          platforms: linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6
          build-args: |
            BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')
          push: ${{ github.event_name != 'pull_request' }}
          tags: ${{ steps.prep.outputs.tags }}
          cache-from: type=local,src=/tmp/.buildx-cache
          cache-to: type=local,dest=/tmp/.buildx-cache
        name: Image digest
        run: echo ${{ steps.docker_build.outputs.digest }}

Trigger a new release with following commands:

$ git tag -a v1.0.2
$ git push origin v1.0.2

This example is inspired by this project:

More information on GitHub Actions see the links below:

Time for one more thing!

The Docker Hub CLI: hub-tool

I like the Docker Hub image support, but now a long missing piece is available. The hub-tool is a CLI for the Docker Hub and is available in the Docker-for-Desktop 3 release.

The Docker Desktop M1 Silicon Preview 7 edition includes the hub-tool. You also can grab it from your Mac amd64 installation.

The hub-tool manages your account, organization and all artifact repositories.

# Preview 5 need a intel binary
# DOCKER_HOME=/Applications/
# scp <big sur intel docker for desktop 3.0 host>:$DOCKER_HOME/hub-tool $DOCKER_HOME
# sudo ln -s $DOCKER_HOME/hub-tool /usr/local/bin/hub-tool
$ hub-tool --help
A tool to manage your Docker Hub images

  hub-tool [command]

Available Commands:
  account     Manage your account
  help        Help about any command
  login       Login to the Hub
  logout      Logout of the Hub
  org         Manage organizations
  repo        Manage repositories
  tag         Manage tags
  token       Manage Personal Access Tokens
  version     Version information about this tool

  -h, --help      help for hub-tool
      --verbose   Print logs
      --version   Display the version of this tool

Use "hub-tool [command] --help" for more information about a command.
  1. Login to your account and browse to your repositories.
$ hub-tool login
$ hub-tool token ls
DESCRIPTION       UUID                                    LAST USED       CREATED     ACTIVE
Github Actions    7b725f9d-5b23-4910-9950-655af709d7fd    12 hours ago    13 hours    true
$ ibrew install jq
$ hub-tool repo ls --format json | jq -r ".[].Name"
  1. You can review your multi architecture images setup:
$ hub-tool tag inspect rossbachp/multiarch-example:1.0.2
MediaType: application/vnd.docker.distribution.manifest.list.v2+json
Digest:    sha256:19559956d9b1db18289238bf9e1fda46474342fe18aaa291c3a55ee0eb6c93a3
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/amd64
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/arm64
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/arm/v7
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/arm/v6
  1. Or list all tags for a repository:
$ hub-tool tag ls rossbachp/multiarch-example --format json | jq -r ".[].Name"
  1. Control your rate limits

Docker Hub Rate Limits were enforced on November 2nd. A lot of options exist to deal with the rate limit:

  • No problem, works for my tiny projects.
  • Paid for the Docker Hub support.
  • Use a image mirror or proxy.
  • Monitor the usage and wait a little bit.
  • Migrate to another registry.

With the hub-tool it#s easier to be informed:

$ hub-tool account rate-limiting


My experience as a developer with multi architectures began in June 1993 with NextSTEP. The simple compilation and execution challenge made me happy. With the new Apple M1 Silicon there is now the same experience for Mac and container developers.

On December 25, 1990 Sir Tim Berners-Lee published the first Nexus World Wide Web browser. Now we live most of the time Always ON and drive communication into a new dimension. I hope we all use this massive information overflow to create a more sustainable world.

Nexus the first WorldWideWeb Browser

It’s time to change a lot. Lower power consumption is possible, also on a Mac. Please, #dezombify your computing. Less is more!

Listen to Holly Cummins' amazing KubeCon keynote:

I hope you had the time to celebrate the 30th birthday of the WWW on December 25, 2020! Hope my old NeXTCube and NeXTStation start again. Belief me or not, this is more of a challenge. Cross your fingers that the new SDCard SCSI disk emulation works well!

I wish you all a Merry Christmas.

Regards and stay tuned,

Peter (pathfinder)


If you want to be notified of updates to container images, use Docker Image Update Notifier:

DIUN logo

Thank you @solidnerd for sending me the link.


"Um unsere Webseite für Sie optimal zu gestalten und fortlaufend verbessern zu können, verwenden wir Cookies. Durch die weitere Nutzung der Webseite stimmen Sie der Verwendung von Cookies zu. Weitere Informationen zu Cookies erhalten Sie in unserer Datenschutzerklärung."