Running Stateless WordPress in Containers

As much as WordPress is lately plagued by bad governance and a "Jack of all trades, master of none" direction, a lot of sites are still running on WordPress, and there are legitimate use-cases where the aging CMS still is the optimal choice. But that legacy aspect brings with it a few challenges that contrast with today's containerised world. That brings the question, can WordPress be adapted to run in stateless environments such as Kubernetes?

Pretty much all of my projects are running in a Kubernetes cluster where the stateless applications can easily be versioned and deployed with a near infinite capacity for scaling up and down. But what do we do with the applications that require folder access such as WordPress?

WordPress as we know has its wp-content folder with sub-folders such as theme, plugins and uploads. This could in theory be adapted for Kubernetes by using volume mounts connected to block storage, but that's a solution which doesn't take advantage of container images' versioned nature, in addition to adding complexity to the setup. Containers offer an immense potential for platform flexibility, the ability to move a deployment from the Kubernetes cluster to for example Serverless Containers was in my eyes something worth supporting.

The solution to this? Github Actions and preparing the image with everything it needs, and offloading uploads to S3 Object Storage.

Here's a brief explanation of what happens during build:

  • A base Stateless-WordPress image is used that contains an optimised wp-config.php, Redis, and a few base plugins.
  • The theme folder in the site repository is merged with the base image.
  • A script connects to the live site and downloads a zip-file with all of the installed plugins and does final preparations.

Each site therefore has its own image and label versioned for the WordPress-version and its plugins.

Broke something in the code or a plugin update and forgot what the previous setup was? No problem, a simple change of the image tag to the previous version gives an exact working copy of how things were.

Since images and other uploaded media use the WP Offload Media plugin, we don't have to do include the uploads folder at all during build, and can ensure that the media library always is up to date and consistent when switching between image tags. This also simplifies backups, requiring only the bucket to be downloaded and also keeping database dumps.

A key consideration is location of all of the involved components. I did test having the database located in a region far from the container (database in France, container in Norway), and performance really did start to struggle. Even with Redis object caching and page caching, hitting uncached pages or navigating in wp-admin was painfully slow. Whilst availability zones these days have such good connections that using seperate zones isn't an issue, seperate regions definitely can be so. I've settled on running the MySQL database in the Kubernetes cluster, but using a managed database in the same region worked absolutely fine as well.

Project repository with documentation: https://github.com/victorberland/wordpress-stateless