Git Enabled Wordpress

Making Wordpress play nice with Git
September 15, 2017
git wordpress docker gitlab

Wordpress. Sometimes it feels like someone sat down and asked themself, “What sort of software can I create that makes it totally impossible to use version control?” Wordpress is that creature.

Wordpress itself is under version control, nicely tagged and available for download. They even have a Docker container, nicely tagged and available for deployment. The problem is that once you deploy Wordpress from either of these locations, you give up on all of the benefits of both containers and source control.

What’s the problem?

If you deploy Wordpress from Git directly onto your host, the instant that you start using it, you pollute the repository with your own content. You can run git pull periodically, but this isn’t the way you want to use code under source control. Eventually you’ll have a conflict or other issue, and if you’re going for sites that are managed by external deployment solutions, logging into your host to run git pull is just…wrong.

If you deploy their container, you’ll have to mount some sort of persistent volume at /var/www/html, and on first run they will copy the latest installed copy from /usr/src/wordpress to /var/www/html. Their own init process for the container states the embarassing:

# TODO handle WordPress upgrades magically in the same way, but only if
wp-includes/version.php's $wp_version is less than /usr/src/wordpress/
wp-includes/version.php's $wp_version

Figuring out how to do that isn’t challenging. Figuring out how to do it when the person running the container wants to do it is the challenging part, and that’s probably why that line has been in docker-entrypoint.sh for so long.

Without some sort of upgrade functionality you can deploy 4.7.4 of Wordpress via their container, and if you later upgrade the image to 4.8.1, nothing happens. You will think that you’re running 4.8.1, but your container simply has that version in /usr/src/wordpress. Your actual document root still contains 4.7.4, and it will continue to do so until you manually upgrade the code in your document root. If that’s the process, why run Wordpress in a container at all?

What are the options?

I’ve dealt with this for years, and the easy solution is to put your entire site into version control.

Don’t do it.

Version control is for controlling things that are versioned. You don’t want to be making updates to your site, adding images, putting in plugins, upgrading the Wordpress core, and then having to SSH into your server to add all of that to Git and push it back to some repository somewhere.

Don’t get me wrong - doing this is better than doing nothing, but it’s still wrong. I know because I’ve done it, and while doing it, it didn’t feel like the right solution at all.

The next thing is to try and bundle your entire codebase into a container. I recently built a solution for a client that did this using Gitlab CI to run jobs for Composer, Gulp, and Wordpress. It runs jobs and caches the artifacts, and a later stage retrieves all of the artifacts and builds PHP-FPM and Apache containers.

Those containers are almost 1G each. Builds take 20 minutes, with much of that time spent pushing artifacts around.

Still better than nothing, but still not right.

The optimal solution looks like this:

  1. Wordpress core is separated from Wordpress content
  2. Wordpress is installed directly from their Git repository at build time
  3. All non-Wordpress content is contained in a single shared volume mounted at runtime
  4. An upgrade of the container image upgrades Wordpress core

If the shared content volume is mounted via NFS, you can instantly scale your Wordpress installation and gain all the benefits of being fault tolerant and highly available.

Can we do this?

My wife asked me for a Wordpress installation yesterday, and rather than go the route of installing the container and dealing with the shortcomings later, I sat down and architected a solution that does what we want.

  1. The Docker image is built via Gitlab CI using a Git submodule for Wordpress that checks out the desired version at build time.
  2. Because Wordpress is installed in a submodule, its core is separated from user content
  3. Wordpress core is stored in /var/www/html/release. Wordpress content is stored in /var/www/html/shared, which can be any persistent volume (but should really be NFS for the greatest benefit)
  4. wp-config.php, .htaccess and wp-content are symlinked to the shared directory.
  5. wp-config.php contains modifications that tell Wordpress how to function as a submodule (thanks to this site for pointing the way)

The result is what I want in a solution. All of the site’s content (images, plugins, themes, etc) are stored in the shared directory. I can update the container and it will update the core without changing shared content.

You can find the repository for it here. You an find the Docker repo for it here.

Please open issues in Github if you find it to be lacking in any way.