In this article, I will explain what steps you need to take to bring native feeling with Docker on Ubuntu (or any other Linux machine) to OSX with (docker for mac).

Docker should act on each machine the same … but it does not, unfortunately. There are some areas that are restricted by each OS. I will focus on my switch from Linux to OSX and will try to help you get going with my experience about all those limitations and how to overcome them.

Php X-Debug connect back

I was using x-debug to debug my PHP applications, I was using the default listener from my PhpStorm application and my docker PHP container was publishing x-debug messages on port 9000.

The same configuration is not possible on OSX, because the bridge network is not reachable from the MacOS host.

So, I was using x-debug connect_back option, but it did not work due to this issue.

The goal is just listen to incoming debug connections. So, due to the network issue, there is no way to use connect_back from the container. But we can create a workaround for that.

1. Choose a free private IP address (choose wisely, you will use it for all your containers), which should be taken from the local address pool. I selected 10.254.254.254.

2. Now, add this IP address as an alias to your localhost network interface. This new IP will act as if it were localhost.

ifconfig lo0 alias 10.254.254.254

Important!

This setting will disappear after reboot, so you need to add it to your launch configuration(launchd). You can use this snippet or follow Ralph’s gist.

For more information visit: https://gist.github.com/ralphschindler/535dc5916ccbd06f53c1b0ee5a868c93

4. Now, you need to change your Xdebug settings from:

zend_extension=xdebug.so

xdebug.remote_back=1

xdebug.remote_enable=1

xdebug.remote_autostart=1

To:

zend_extension=xdebug.so

xdebug.remote_back=0

xdebug.remote_enable=1

xdebug.remote_autostart=1

xdebug.remote_host=10.254.254.254

Now, rebuild and recreate your application, and you enjoy your PhpStorm debug listener with the native feeling, the best thing is that get from that the possibility to debug application from web and cli.

Of course, this is not perfect solution. We are binding our Docker configuration to our environment and we need to prepare our OS. But I like this way much better than remote xdebuger.

Sources:

http://stackoverflow.com/questions/39143814/xdebug-not-working-in-docker-for-mac

https://forums.docker.com/t/explain-networking-known-limitations-explain-host/15205

https://gist.github.com/ralphschindler/535dc5916ccbd06f53c1b0ee5a868c93

https://docs.docker.com/docker-for-mac/networking/#/use-cases-and-workarounds

Slow file sharing

The next big thing that was noticeable after my switch to OSX is the performance of my PHP applications. I’m using Symfony for my daily work.

I was mounting my codebase to a Docker container via docker-compose.json file this way:

volumes:

- './:/var/www/html'

Simply add all my files into /var/www/html directory. But this is … EXTREMELY SLOW on OSX.

Native speed on linux host:

// linux machine

time docker-compose exec web app/console

real 0m0.425s

user 0m0.192s

sys 0m0.024s

Docker for mac:

// docker for mac 1.13.0

time docker-compose exec web app/console

real 0m5.209s

user 0m0.253s

sys 0m0.081s

And this is just for a plain app/console plain call.

Solution

The basic idea is to synchronize your codebase with codebase in your container. I will provide the easiest functional solution, which works awesome for me. I will let you start with this and if you miss something here, you can (and should) dig dipper through resources that I included below.

The basic idea is to synchronize your codebase with the codebase in your container. I will provide the easiest functional solution, which works awesome for me. I will let you start with this, and if you miss something here, you can (and should) dig deeper through resources that I included below.

Step 1. Install tools

What we need:

Homebrew unison or rsync fswatch Install docker-sync

Installation guide:

// 1. Install homerbew (don't use macports, I wasn't able to get it work) /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" // 2. Instal fswatch brew install fswatch // 3. Install unison brew install unison // 4. Install docker-sync gem install docker-sync

Project setup

Now, we need to setup our project. First, remove from composer.yml all your mounted volumes. And if you want you can add them on the build process in the Dockerfile. Of course, those files will not be updated, when you make changes on your host machine. For that purpose, we need those syncing methods.

// before docker-compose.json version: '2'

services:

web:

build: ./

image: codebase_and_apache/dev

volumes:

- './:/var/www/html' # remove line with code, we will sync it!

ports:

- 80:80

And we should change it as you can see underneath:

// new docker-compose.json version: '2'

services:

web:

build: ./

image: codebase_and_apache/dev

volumes:

// you can have here volumes that are not heavy

ports:

- 80:80

Now we need to create our development compose file, which will add some volumes` settings into our base application, in this case web, and add this volume itself.

// docker-compose-dev.json // do not change the filename (unless you know what you are doing ;) )

version: "2"

services:

web: # our application name from docker-compose.yml

volumes:

- web-sync:/var/www/html:rw # will be mounted on /var/www volumes:

web-sync: # this volume you can name whaterver you want but it must be unique on your docker host machine

external: true

And now the real stuff. We need to prepare the file that is responsible for configuring our synchronization process. It will look like this:

syncs:

eb-sync: #tip: add -sync and you keep consistent names as a convention

src: './'

dest: '/var/www/html'

sync_host_port: 10872

sync_strategy: 'unison'

sync_user: 'www-data'

sync_userid: '33'

# For Symfony 2.x projects

sync_excludes: ["app/cache", "app/logs"]

# For Symfony 3.x projects

# sync_excludes: ["var"]

Finally, we can test-run our Symfony application. First, we need to create our container and start syncing files. Do this with the docker-sync-stack command:

docker-sync-stack start

Containers will be created and the synchronization will start. This will take a while, because it must copy all your files from the host to the container. Then, we can check the performance again. And…

// Docker for mac with file synchronization

time docker-compose exec web app/console

real 0m0.806s

user 0m0.307s

sys 0m0.082s

Ta-dah! Great! We can continue working on our project!

Of course, we made here significant changes in docker-compose.json files that are environment dependant and Docker should (yes, should) be OS independent, but it is not. We need to polish some solutions from time to time. I just gave you the easiest basic approach. If you are interested in some special cases please look into resources, or feel free to ask me in comments below. If you have any other solution, I will be glad to here about it. I will try to respond to it or, if the explanation will be complex enough, I will write another deep-dive post into this topic.

Resources:

http://docker-sync.io/

https://github.com/timglabisch/symfony_docker_sync

https://github.com/brikis98/docker-osx-dev

http://stackoverflow.com/questions/30842005/upgrading-rsync-on-os-x-using-homebrew

https://github.com/EugenMayer/docker-sync-boilerplate

http://brew.sh/

https://github.com/EugenMayer/docker-sync

http://stackoverflow.com/questions/30090007/whats-the-right-way-to-setup-a-development-environment-on-os-x-with-docker

https://docs.docker.com/docker-for-mac/osxfs/