Docker Phpstorm Xdebug



  • An IDE in your machine (I use PHPStorm) An issue you need to debug (d’oh!) SSH to the remote server and install Xdebug sudo apt-get install php5-xdebug (Debian based servers) Configure Xdebug. The Xdebug configuration goes in the php.ini file (or in a specific.conf file inside your conf.d folder, it depends on the server’s OS).
  • Add Xdebug to the Webserver Dockerfile Since this image is using alpine, it's a little different than a lot of the approaches you might find if you just google 'Install Xdebug PHP.' At the end of your app Dockerfile you need to manually install xdebug using pecl, so add this command at the bottom.
Phpstorm

Run/debug a php script on docker To verify that everything is working, open the file app/hello-world.php in PhpStorm, right click in the editor pane and choose 'Run'. PhpStorm will start the configured container and run the script. The output is then visible at the bottom of the IDE.

I've been using Docker for my local environments at Vanilla since 2017.It was a good way to ensure consistent & reproducible developer environmentsand was a marked improvement over what we were running before. We setup a single repositorywith our shared environment (vanilla-docker) andit spread across the company like wildfire.

The consistency was great, especially as we onboarded various junior developers over the years.Unfortunately in 2018, Apple released MacOS High Sierra, sporting a new filesystem, APFS.

This brought one single major regression to our developer environments.

Docker for Mac was Slow!

In the beginning, it was completely unusable.Massive CPU spikes would freeze up our machines, and response times were abysmal.

Things got a little better with introduction of a few options when mounting volumes: Delegated & Cached

These along with various improvements in docker for mac made things better,but we still struggled with performance for a long time.It wasn't completely unusable, but we were seeing 3-4 second response times in docker,where we would see 200-300ms response times in local development.

Various Attempts at Fixing it

I tried a few things to speed them up.

  • NFS Volumes - This offered a 30-40% speed improvement but proved to difficult to roll across all of our developers due to the additional configuration required.
  • docker-sync - This tool gave essentially native performance but brought some major drawbacks. I tried 2 times, once in 2019, and again in the beginning of 2020 but these still seemed to hold true.
    • It was very slow to startup. We have a lot of files and directories, and the initial sync would take 10+ minutes with no status indicator. Sometimes it would hang entirely and you'd have to reboot your machine, wipe the containers, and start again.
    • It would stop syncing at random times with no indication. You would notice when you changes suddenly stopped applying. Often the only fix was to wipe the volumes and redo the initial sync. This was particularly evident when checking out and older release and swithing back.
    • The configuration was complicated. Additional commands were required for startup, and the configuration file used a poorly documented syntax for marking excluded directories (a few node_modules directories in particular needed to be excluded in order for things to sync for even short periods of time).
    • Sometimes filesystem permissions wouldn't sync properly. This tended to happen with certain configuration files written by the app.

The Real Problem - XDebug

Many of our developers use XDebug extensively during development and testing.A 2-5x slowdown while running a debug session is not unexpected.

Little did I know that just having the extension installed brings along some significant slowdown.This is amplified in docker, where every System IO call brings with it a lot of overhead due to the virtualization in Docker for Mac.

Removing the XDebug extension had the local sites responding within expected times again.XDebug is really useful though. I didn't want to give it up. Enabling it also couldn't be an onerous activity; I could use XDebug 10-20 times throughout a workday, and having to restart the container would be a chore.

The Solution - 2 PHP-FPM Containers

The final solution ended up being running 2 PHP-FPM containers.

  1. With a 'production-ish' configuration. This one without XDebug and with a development configuration for OPCache.
  2. With a debugging configuration. This one with XDebug.

Nginx was already used to serve our PHP-FPM processes, so I just updated the configuration to route between them.

Xdebug

The Configs

Nginx Server Config

Phpstorm xdebug docker cli

This is the bulk of the required configuration. It does the following:

Docker Xdebug Phpstorm Linux

  • Define the 2 upstreams (php-fpm socket and php-fpm-xdebug socket).
  • Define a few mappings 2 allow switching between the 2 upstreams based on
    • An XDebug cookie.
    • A query parameter of ?XDEBUG_SESSION_START
    • Many possible cookie values used by various browser plugins and IDEs.

Debug PHP config

Phpstorm Docker Xdebug Path Mappings

'Production-ish' PHP config