Docker for Mac Edge Brings Major Performance Improvements

Posted May 30th, 2020

Great news for developers who use Docker for Mac and encounter performance issues.

The newest version of Docker for Mac Edge (preview release) includes new file caching / bind mount options for directories on your machine to improve performance using Mutagen. The amazing Jeff Geerling offered some thoughts, initial metrics and a quick write up on how to get started with it.

I have been using Docker for almost 3 years now on various Drupal projects, Symfony projects, and other odds and ends (Go, Pattern Lab, static sites) for local development and even some Pi pet projects (hat tip here to Jeff again) on my home network. I had accepted the fact that local development in Docker would be slower than native or MAMP simply due to the efficiencies and ease of use that Docker brought in a team setting. 

How fast is it?

First, take the following anecdotes and metrics with a grain of salt. My performance gains may not mirror yours, I may be running different services or Docker images in my setup, and other factors can vary the numbers. Also note that it is not native speed, but a whole lot better and closer than it's ever been to date.

The containers:

  • PHP 7.3 (Drupal 8.8.6)
  • Apache 2.4
  • MariaDB 10
  • MariaDB 10 (test db instance)
  • Solr 7.7
  • Node 10
  • Redis
  • Traefik
  • Mailhog


Setting up the project was fairly straightforward. The first "test" would be fetching dependencies, Drupal core and contributed modules, and some private packages with Composer.

Typically for me, installing from scratch with Composer would take the better part of anywhere from 3-5 minutes, and sometimes see a delay before even seeing acknowledgement in the terminal that I issued a command. Composer now starts immediately with no hiccups and starts downloading packages. Nuking it and running it twice resulted in nearly the same length of time, about a minute and a half.

PHPUnit Tests

While in development as I am with the project I tested with, I am constantly running tests for functionality testing and confidence in requirements are being met. Depending on the tests you are running, this can be a fairly lengthy process. This is an area where I saw the most improvements, it was impossible to not notice the difference and what excited me the most.

I chose a specific kernel test I wrote that is run frequently to test gated content access to Drupal nodes. If you are not familiar with kernel tests, it does a minimal Drupal bootstrap + install with only the modules and services you request in the test. On average, this particular test would take 30-40 seconds on average to execute.

After enabling directory caching, this is now the new normal:

phpunit -- --testsuite kernel --filter AuthControllerTest
PHPUnit 7.5.20 by Sebastian Bergmann and contributors.

...                                                                 3 / 3 (100%)

Time: 4.48 seconds, Memory: 6.00 MB

OK (3 tests, 33 assertions)

4.5 seconds. Honestly, I went back and double-checked I had set everything up correctly in Docker and that this was correct. This can't be accurate, can it? I pinched myself, I was not dreaming. 

I can't describe enough what a gain that is. If you run your tests one time a day, you may not get what the big deal is. I run them many many times in a day, as do all developers in our project. We trade time for confidence and stable predictable deployments. A good percentage of this time can now be reclaimed.

Lets say the average time is 35 seconds. If I am writing code or refactoring, I may want to run this test after each change. Lets say I make 10 changes, I run it 10 times. That's 6 minutes total time spent waiting for the test to finish. With this change, that number is less than 50 seconds total. Add that up over dozens or hundreds of runs in a sprint, milestone or length of a project - this is a lot of idle time wasted. You can also look at it as faster feedback loops, which mean more rapid iterations in code changes and testing that code - for a more efficient developer.

Ok, what about all kernel tests? We have a handful that test mission critical services and functionality in this project. On average, performing them all would take about 3-4 minutes while making my Macbook Pro sound like it was ready to lift off. Except now:

phpunit -- --testsuite kernel                            
PHPUnit 7.5.20 by Sebastian Bergmann and contributors.

.........................                                         25 / 25 (100%)

Time: 26.35 seconds, Memory: 6.00 MB

OK (25 tests, 165 assertions)

Wow! A half minute is a pretty good improvement. To add on to the above benefits, I can run the whole testsuite or classes within a testsuite to ensure any changes I'm making do not cause regressions, without losing minutes per run.

Previously, running ~100 unit tests took an average of 15 seconds to run. Not great for unit tests. After the change:

phpunit -- --testsuite unit  
PHPUnit 7.5.20 by Sebastian Bergmann and contributors.

...............................................................  63 / 102 ( 61%)
.......................................                         102 / 102 (100%)

Time: 951 ms, Memory: 10.00 MB

OK (102 tests, 141 assertions)

A hell of a lot better!

Alright, what if we throw the whole suite at it and run them all? We have a ballpark of 140 tests, unit, kernel, functional and a few tests that we run with Cypress. The average here was anywhere from 6 minutes on a good day to 8 minutes on a bad one to run everything combined. Frankly I gave up running them all a long time ago and left that task to the CI service to report on a pull request (it runs in Linux, so it can do this faster). Now the execution time is way, way shorter on Mac:

phpunit -- --testsuite unit,kernel,functional
PHPUnit 7.5.20 by Sebastian Bergmann and contributors.

...............................................................  63 / 133 ( 47%)
............................................................... 126 / 133 ( 94%)
.......                                                         133 / 133 (100%)

Time: 1.63 minutes, Memory: 12.00 MB

OK (133 tests, 639 assertions)

I just upgraded on Friday, so I don't have too much else to report here other than this. Using xdebug feels a lot better and faster than it did before, and navigating Drupal locally has much snappier response times. I typically spend a majority of my time in the tooling, debugging, testing and coding, so this will make me even more efficient by an order of magnitude.

Get Docker for Mac Edge today and give it a try, you might be pleasantly surprised with the results. I am!