Improve your app performance with Docker for Mac

Albert Campderros
4 min readApr 24, 2021

From hell to heaven in some steps. A PHP development environment story.

I’m working as a DevOps Engineer on a company with a PHP monolithic application as a main one… running with Docker for all developers. That’s ok, all pieces work like a charm but… a wild Docker for Mac appears!

Suddenly, the application running in the same way as Linux does need an 80–100% execution extra time, some scripts give timeout… that’s frustrating for our Frontend dev’s (main consumers of Docker for Mac in my company).

How to deal with that? Docker for Mac is causing a lot of trouble to our Frontend developers, and obviously, their production decreases because of this.

Okay, time for investigation, I have to find a solution… move the devs to Linux isn’t a solution. Aaaaand nothing clear… some people talking about xdebug… others talking about the clock… trying to rsync the code with some tools like docker-sync but… didn’t work as we need.

My intention with this is to write the post that I would have liked to find before my months of testing, research, frustration, and some dedicated profanity against Docker for Mac :)

The problem

First of all, what’s the issue with Docker for Mac? why is so slow? the answer is… the shared volumes. Yes, if you share volumes with your host, your app will run slow, more volumes, slower… and more files shared, slower. Because the internal issue is the amount of data shared between the VM (Docker for Mac it’s a “mini VM” with Linux Kernel inside) and the host (macOS).

Normally, if you are working on a microservice or a relatively small service the slowness isn’t enough to worry about it because the number of files shared inside is small.

Our app’s a monolithic one with Symfony inside, with 2 vendors, cache, and a huge number of files.

Why not? the entire workdir is shared inside our PHP container :)

And that’s not all, we have more services on the stack. One of them is MySQL with… the data-dir shared with the host. More troubles for our macOS users!

What is causing that? why the shared volumes are slow as f? it’s because of the technology used by macOS to share a folder called osxfs. More information here!

The solution

Well, the solution is clear: REDUCE THE SHARED VOLUMES! yes.. easy to say, not easy to implement.

My strategy to accomplish the objective (the app must run very close as Linux does) is to reduce step by step the volumes.

Our development environment is controlled by Docker Compose, the key is to take advantage of some of their features.

I create a YAML file with the differences between the main Docker Compose YAML file dedicated to my macOS developers. My Makefile does the magic to add this extra YAML file if the OS is macOS.

docker-compose -f docker-compose.yml -f darwin.yml up -d

Use NFS

Share the entire code. It’s faster than osxfs and you will improve the performance only using a volume like this. Follow this guide for help in the configuration.

...
volumes:
nfs-volume:
driver: local
name: nfs-volume
driver_opts:
type: nfs
o: addr=host.docker.internal,rw,noatime,nolock,nodev,intr,rsize=32768,wsize=32768,nfsvers=3
device: ":$PWD"
...

The cache folders

Must be a tmpfs volume inside the container, why we have to share them? and enjoy the RAM “boost”!

...
tmpfs:
- /path/to/cache:uid=48,gid=48
- /path/to/symfony/var/cache:uid=48,gid=48
...

MySQL data directory

Why are sharing the MySQL data directory? the frontends don’t need that! create an internal volume and install the data there.

...
mysql:
volumes:
- mysql:/var/lib/mysql:delegated
...
volumes:
mysql:
driver: local
name: mysql
...

The vendor's folders

Do you need the vendor's files shared on the host and the container? why don’t create an internal volume dedicated to it and execute the composer through Makefile to be executed inside the container? it’s magic!

...
volumes:
- symfony-vendor:/path/to/symfony/vendor:delegated
- vendor:/path/app/vendor:delegated
...

The logs folders

You have any kind of folder with logs? are you sharing it between the container and the host? please, don’t do that, normally is write intensive and Docker for Mac is very bad at that… create an internal volume for it.

...
tmpfs:
- /path/to/symfony/var/log:uid=48,gid=48
...

Enjoy the performance!

Results after these changes? from 5 seconds to load a page to less than a second… the performance is very close to the Linux users!!

I hope this will help anyone to improve their application performance on Docker for Mac :)

Thanks for reading!

--

--