Update - On 14-MAR-2022, Docker released Docker Desktop for Mac v4.6.0, which included a new experimental file sharing implementation called virtiofs. Please refer to my follow-up article “Docker and Apple Silicon” for the latest results.

With the arrivial of the 2021 MacBook Pro, I have been testing my common workloads.

I have been using Docker since 2014, primarily to support web development. Last year, I tested Docker for Mac on the MacBook Air running Apple Silicon, which I documented across three articles.

The performance of Docker running on the MacBook Air was good, relative to Intel equivalent Mac. It was clear that the Apple M1 System on a Chip (SoC) had tremendous potential, but was held back by the software. For example, in my testing, Docker Desktop for Mac was consistently outperformed by its x86 Linux and Windows (WSL2) counterparts.

In this article, I plan to take a second look at Docker Desktop for Mac. I hope that a year of additional development and the more powerful Apple M1 Max SoC will deliver tangible improvements.

Test Setup

As part of my testing, I will be using the 16-inch MacBook Pro (OCT-2021), 16-inch MacBook Pro (NOV-2019), Dell XPS 17 (9710) and a custom-built desktop PC. A summary of the specification for each system can be found below.

16-inch MacBook Pro (OCT-2021)

  • Apple M1 Max (10-core - 8 Performance / 2 Efficiency)
  • 32-core GPU (10.4 Teraflops)
  • 32GB Unified Memory (400GB/s Memory Bandwidth)
  • 1TB SSD (7.4GB/s Read)
  • macOS 12.0.1

16-inch MacBook Pro (NOV-2019)

  • Intel Core i9-9980HK 2.4GHz Base / 5.0GHz Boost (8C/16T)
  • AMD Radeon Pro 5500M 8GB GDDR6
  • 32GB 2666MHz DDR4 RAM
  • 1TB PCI-e SSD
  • macOS 11.6

Dell XPS 17 (9710)

  • Intel Core i9-11900HK 2.6GHz Base / 5.0GHz Boost (8C/16T)
  • NVIDIA GeForce RTX 3060 Ti 6GB GDDR6 (70W)
  • 64GB DDR4 3200MHz RAM
  • 1TB M.2 PCI-e NVM-e SSD
  • Pop!_OS 21.04 (Linux 5.13)

Custom-Built Desktop

  • AMD Ryzen 9 3950X 3.5GHz Base / 4.7GHz Boost (16C/32T)
  • NVIDIA GeForce RTX 3090 FE 24GB GDDR6X
  • 64GB Corsair Vengeance LPX DDR4 PC4-28800C18 3600MHz RAM
  • 1TB Samsung 980 Pro M.2 PCI-e 4.0 NVM-e SSD
  • Windows 11 (WSL2)

I plan to use LifeinTECH (this blog) as my test build, which follows the JAMstack web development architecture, using the Jekyll Static Site Generator.

The project includes a range of external dependencies and custom plugins. It is fairly large, including over 4000 individual files and 800MB of data. This is relevant as it applies file sharing I/O pressure.

On the MacBook Pro, I plan to test two scenarios, specifically Docker Desktop for Mac and Docker running on a Linux virtual machine using UTM.

Docker Desktop for Mac

Docker Desktop for Mac includes multiple configuration options that can directly impact performance.

Under “Docker Desktop > Preferences > Resources > Advanced”, I configured the following settings.

  • CPUs: By default, Docker Desktop is set to use half the number of CPUs available on the host machine. However, Docker Desktop does not detect the M1 Max correctly, therefore I manually configured 8 CPUs. At this time, there is a software bug that prevents configuring all 10 CPUs.

  • Memory: By default, Docker Desktop is set to use 2GB runtime memory, allocated from the total available memory on the Mac. This is adequate for my test build but can be adjusted as required. It should be noted that this memory is allocated to Docker Desktop regardless of a running container.

  • Swap: I retained the default swap of 1GB.

Under “Docker Desktop > Preferences > Resources > File Sharing”, I configured the following settings.

  • File Sharing: One of the biggest bottlenecks associated with Docker Desktop for Mac is file sharing I/O performance. Therefore, it is important to only share the directories required by the container. For example, the specific “development” folder.

Finally, under “Docker Desktop > Preferences > Experimental Features”, I checked the setting “Use the New Virtualisation Framework”, which enables the new Apple Hypervisor framework that should deliver better performance.

Ubuntu Server on UTM

I installed Ubuntu Server (ARM64) on UTM, provisioned with 4 Cores, 8GB Memory and NVMe Storage.

Docker Performance on M1

The Ubuntu Desktop Environment was installed, with the Docker Desktop and Docker Compose packages. The full setup can be found in the article “Virtualisation on M1”.

Results

The table below outlines the results of my testing.

Docker Performance on M1

Performance across Linux (Dell XPS 17) and Windows (Custom-Built PC) provides a good baseline as they both build against a native Linux kernel.

The results from the 16-inch MacBook Pro (OCT-2021) are inconsistent depending on the specific configuration. For example, when using Docker Desktop for Mac, it is critical that an ARM64 image is selected and the Apple Hypervisor is enabled to achieve acceptable performance.

In this scenario, the Apple M1 Max performs as well as the 16-inch MacBook Pro (NOV-2019), with an Intel Core i9-9980HK processor. Interestingly, the 16-inch MacBook Pro (NOV-2019) performance degraded with the Apple Hypervisor enabled.

The most exciting result was the Ubuntu Server (ARM64) running on UTM, which achieved a blistering 9 second build time. This result is the fastest I have seen on any system, demonstrating the raw power of the Apple M1 Max when software limitations are removed.

For example, the testing indicates that file system I/O is the limiting factor when using Docker Desktop for Mac, especially with large, multi-file projects. This is not an issue in scenarios where the native Linux kernel filesystem can be accessed directly.

Conclusion

I remain conflicted regarding the performance of Docker for Mac, specifically with the 16-inch MacBook Pro (OCT-2021) running the Apple M1 Max SoC.

If it is not possible to run a Linux host directly, I prefer the implementation of Docker for Windows, which takes advantage of WSL2. In my opinion, this is a great compromise, allowing the developer to use Windows software, with Linux performance.

Regarding macOS, Docker Desktop feels constrained, forced to use middleware that is not always performant (e.g. File Sharing). As a result, I will likely retain a “right-sized” Ubuntu Server running as a virtual machine on UTM.

This approach unlocks the raw performance of the Apple M1 Max SoC by removing the filesystem I/O bottleneck, delivering an unbelievable 24x performance increase over Docker Desktop for Mac.

Finally, it is worth noting that these results are workload-specific, therefore the highlighted filesystem I/O bottleneck may not always be an issue.