Why Do This?
Web applications are messes of dependencies. WordPress is no exception. When you install such an application directly on a host system, it fills up the corners. You end up with applications and libraries installed that you’d never use for anything else, configuration files in various spots on the filesystem, and database contents and configuration to manage. Package management tools like apt and infrastructure management tools like cfengine help this to some degree, but what if we could keep the entire web application inside its own little container. What if, then, we could rebuild that container from scratch with one or two commands? What if running that container had extremely minimal dependencies? Well, then, we’d be running in Docker.
As I said in the previous section, running these Docker containers has minimal dependencies. We need to install two things:
- Docker: We can do this with a 3rd-party apt repository.
- docker-compose: Unfortunately this isn’t in the apt repository, but it’s simple to fetch a static binary and install it.
- I recommend adding the users who will be developing/running the containers to the docker system group in /etc/groups.
That’s it! No need to install PHP, MariaDB, apache, no apache modules needed, no PHP libraries, none of the stuff that litters a system in a typical web application deployment.
Docker expects each image to be self-contained, and each image really should run only one process. This presents a challenge for WordPress which is of course a PHP application, but it isn’t really installed until it writes to its database. We’ll need two persistent volumes anyway (one for WordPress’s uploads folder and one for our MariaDB database), but we need to get those to a proper initial state.
We’ll tackle this with three steps:
- Build the WordPress image. We’ll base this on the Docker Hub wordpress:4-apache image.
- Bring up the WordPress and MariaDB containers and connect them with docker-compose.
- Seed WordPress’s database configuration, plugin install, and theme install to occur on the first start.
Using a Makefile to tie things together, we can address each of those steps individually:
- Build the WordPress image: make build (Writes out Dockerfile builds the WordPress image from it).
- Bring up and connect containers, install and set up wordpress: make compose (default target: Writes out docker-compose.yml and runs docker-compose up).
Be sure to first edit wpdocker.conf to configure how you want WordPress to be built. It has everything we can configure from image names and passwords to WordPress theme and plugins to install and patches to apply.
Our Makefile has a few other targets that can come in handy during development or even deployment:
- make clean (Stops the docker-compose-built processes, removes the WordPress image and any other dangling images, erases Dockerfile and docker-compose.yml).
- make cleanvolume (Erases any dangling persistent volumes. Persistent volumes are danging when the process that uses them is stopped, so be careful with this one. You can erase important data.)
- make backup (Take a snapshot of the database in backup.sql.gz and of the uploads folder in uploads.tar.gz).
- make restorebackup (Restore backup.sql.gz and uploads.tar.gz in to the running containers).
- make save (Create a tarball of the image for deployment).
Bringing it Together
Now, on any host, once we install Docker, we can go from zero to a running WordPress with the latest backup restored, simply by:
- $ make
Wait for both Docker images to come up and then in another window:
- $ make setup restorebackup
For more details, including an nginx recipe for the host to handle multiple of these instances, see README.hostsetup.
Please see my follow-up article on using the Alpine-linux-based images and fpm to reduce container size, RAM usage, and add microcaching to handle heavy load spikes.
Many thanks to grey <email@example.com> for the idea and for his initial work that I shamelessly embraced and extended.