Docker on Apple M1
In the article “Apple M1”, I shared my initial observations of the Apple transition from Intel to Apple Silicon, using the new MacBook Air (Fourth Generation).
In summary, I was incredibly impressed with the Apple M1 System on a Chip (SoC), which delivered excellent performance and power efficiency as well as a viable transition runway via Rosetta 2.
I concluded that this transition was not only the most ambitious change in the history of the Mac but could also have a profound impact on the personal computing industry.
With that said, due to the immaturity of the architecture, there were some limitations. A big one for me was the inability to run Docker, which I use frequently as part of my development workflow.
Earlier in the week, Docker released the first public preview of “Docker Desktop for M1”, enabling native compatibility. Although still in preview, this is a significant milestone, removing one of the primary blockers that would prevent me from using an Apple Silicon powered Mac as my daily driver.
I did not expect to see a public preview in 2020, therefore the Docker development team should be commended for their quick work. As highlighted in the blog post, the team needed to overcome the following engineering challenges:
-
Migrate from HyperKit to the Virtualization Framework introduced in macOS 11 Big Sur.
-
Recompile all binaries of Docker Desktop to run natively on Apple Silicon.
-
Update engineering tools (CI/CD and Testing) to support Apple Silicon.
This article will focus on my initial impressions of Docker on Apple M1, looking to assess reliability and performance across my common workloads. Recognising this is a preview, I do not expect perfection.
Reliability
Once downloaded, the installation was very simple, essentially identical to the regular Docker Desktop for Mac.
I decided to use this blog (LifeinTECH) as my reference point, as I am very familiar with its performance characteristics building via Docker across a wide range of hosts (Windows, Mac, Linux).
As a reminder, LifeinTECH follows the JAMstack web development architecture, using the Jekyll Static Site Generator. It includes a range of custom plugins to support search, tagging and to enable Progressive Web App (PWA) capabilities (offline access, etc.) The project size is approximately 400MB.
I use the official Jekyll Docker image as part of my build, which itself requires Ruby, Ruby Gems and Bundler.
Leveraging Docker Compose, I was able to use my YAML configuration file to install and configure the required runtime dependencies.
Once complete, the Jekyll build service was executed, which generates a static site for production use. As you can see from the image below, the build took approximately 614 seconds to complete (more on performance later).
Everything worked as designed, including the Docker Dashboard GUI.
The Docker Dashboard GUI includes some useful real-time statistics of any running container, highlighting CPU, Memory and Storage and Network utilisation.
Everything built as expected, however, I did receive several warnings related to file conflicts. I do not receive these warning when building for WSL 2 on Windows, therefore I suspect this is related to the filesystem differences of the mounted volumes (e.g. AFS, ext4, NTFS).
Thankfully, the generated static site appears to work as designed.
Performance
With reliability looking good, I switched my attention to performance. The table below outlines the build times leveraging the “default” Docker settings for each device.
I have also added the relative Geekbench CPU scores, highlighting the relative performance of the hardware.
As you can see, the MacBook Air running the Apple M1 is very slow, falling behind my 16-inch MacBook Pro and only narrowly beating my old 12-inch MacBook.
The 12-inch MacBook is running an Intel Core i7-7Y75, which is a 7th Generation dual-core processor, that is passively cooled (no fan). As highlighted by the Geekbench scores, the Apple M1 is (in theory) significantly more powerful than the Intel Core i7-7Y75, highlighting a potential software bottleneck.
If I had to guess, I would highlight the following limitations.
-
Docker on M1 is pre-release (public preview), therefore likely not optimised for the new architecture.
-
Although Docker supports multi-platform images, I suspect the majority are still built using the x86 architecture, therefore not native to the Apple Silicon. This is the case for the official Jekyll Docker image, which does not include an ARM64 version. In this scenario, I believe the QEMU emulator is utilised, which would have a significant impact on performance.
It is worth noting that Docker running via WSL 2 on Windows 10 is still the gold standard (outside of native Linux), delivering over seven times the performance of the MacBook Air. This is thanks to the fact that Microsoft includes a native Linux Kernel as part of WSL 2, delivering bare-metal performance (CPU and I/O).
Conclusion
In conclusion, I am pleased to have a compatible version of Docker running on the Apple M1. Following my initial testing, everything appears to be working as designed.
Performance is not great when using x86 Docker images, but this is not a limitation of the hardware, therefore I hope to see things improve over time as the software stack matures, optimising for Apple Silicon.
Over the coming weeks, I plan to test some ARM64 Docker images, which I expect to perform better. In parallel, I am interested in evaluating the capabilities of the Apple Virtualization Framework, specifically targetting client-side virtualisation.