Update: Read about how I modified this Docker image to enable MultiSite.
I recently decided to create my first public WordPress plugin which provides basic FitBit stats for your blog.
This was on a fresh laptop (the one handily provided by Automattic, my new employer), so I had the opportunity to try something new in terms of my development environment.
Side Note: Docker, for those who don’t know, is a “container” runtime – a way of running Linux applications (even on OS X) that offers process and storage isolation but is lighter-weight than a full VM, allowing you to effectively run many different environments on the same computer. This is great for software development! I can test against 5 different versions of MySQL without having to somehow make them coexist on the same machine.
Sharing code with the Docker VM
This is the complex part of any Docker setup. We want to edit our code on the desktop and have the changes seamlessly appear when we reload the page. This means dealing with Docker volumes.
This is a problem for WordPress development because ideally your WordPress process (for example, Apache) needs permission to write to your plugin and theme directories. If it can’t, you need to install plugins and themes from the command line, which is fiddly and error-prone.
So why not run Apache as root? Alas, running Apache as root is not possible without recompiling the binary with the
-DBIG_SECURITY_HOLE flag, and to be honest I’m too lazy to maintain a custom Apache binary. There must be a better way.
Some developers recommend the “data container” pattern, i.e. create a special container that persists data for sharing between your desktop filesystem and the Docker VMs, using something like samba. Frankly I couldn’t get it to work without crashing Finder, and it’s complex to understand and works poorly with Docker Compose, so it’s out as far as I’m concerned.
Eventually, after banging my head against this problem for a couple of days, the solution came to me just as I was falling asleep. It’s so obvious that I hated myself for not thinking of it earlier: Use PHP’s built-in web server to serve WordPress as the root user.
Booting the app
This is the easy part. Docker Compose gives us everything we need to initialize a new WordPress application. Create a new directory for this project (e.g.
~/workspace/wp) and create a file called
docker-compose.yml with the following contents:
wordpress: image: gravityrail/wordpress volumes: - src:/var/www/html links: - db:mysql ports: - 8080:80 db: image: mariadb command: mysqld_safe --skip-name-resolve environment: MYSQL_ROOT_PASSWORD: example
Important to note that we override the mariadb command to include “–skip-name-resolve”. By default MySQL/MariaDB will try to look up the host name for an incoming IP address. Since composer doesn’t provide a hostname for our “wordpress” host to our “db” host, this can result in significant latency while DNS lookups are performed for every. Single. Query.
Then in the console,
cd ~/workspace/wp and run the following command:
Wait a few minutes while the containers are downloaded (they’re cached locally, so this only happens once) and then two services will boot – the WordPress container and MariaDB container. The logs will be output to your console.
During the boot process the WordPress image automatically installs WordPress to
/var/www/html inside the container, so you should see the WordPress files magically appear in the
src folder on your desktop!
Once booted (it only takes a couple of seconds) the service will be available at your boot2docker IP, port 8080. You can find it out like this:
Paste the output of that command into your browser (e.g. for me it’s http://192.168.59.103:8080/) and you should see the WordPress install screen.
Now you can edit the code locally and see your changes reflected instantly in your Docker WordPress instance.
Bonus: The wp cli command
I’ve included the wp-cli tool as part of the install (it’s how I boot the server), which means that from your desktop you can easily install plugins, manage the blog and database, and more.
docker-compose run wordpress wp --allow-root plugin install hello-dolly
I’m still experimenting with this configuration, but so far this is a super smooth workflow which has reduced the dependencies on my workstation and given me more flexibility. I’ll post again as this workflow evolves.