WordPress on Kubernetes

The Definitive Guide for WordPress on k8s

ReadWriteOnce vs ReadWriteMany

Kubernetes defines four persistent storage access modes: ReadWriteOnce, ReadWriteMany, ReadOnlyMany and ReadWriteOncePod. These modes define the rules by which pods and nodes can access persistent volumes, and have an affect on placement and scaling strategies.

In this section we’ll look at the purpose and key differences between the two main modes – ReadWriteOnce and ReadWriteMany and briefly mention the others. This will help understand how pods and placement are affected by storage, and facilitate good decisions about scaling WordPress applications in our Kubernetes cluster.

ReadWriteOnce

This access mode is by far the most widely used, and not just in Kubernetes. Most storage devices today can only be attached to a single computer at any given time, like a locally attached hard-drive for a USB flash drive. Most network attached block storage systems are also limited to a single attachment.

A ReadWriteOnce volume in Kubernetes can only be mounted into a single node in a cluster, providing exclusive read-write access to that particular node. The volume itself can be mounted into multiple pods running on that one node.

We’ve seen the ReadWriteOnce access mode in action in previous sections. We provisioned and mounted an OpenEBS Mayastor block storage volume for our MariaDB StatefulSet. Even though the Mayastor disk pools were replicated across multiple nodes in the Kubernetes cluster, only one node could mount the volume at any given time. When we moved our MariaDB pod to a different node, the volume attachment was also moved to the new node.

Our early Nginx + WordPress pods deployment also mounted a local volume using the ReadWriteOnce mode. This is an example where multiple pods (and multiple containers within those pods) could access the same persistent volume, but only when it’s on the same node in the cluster. This is the reason why our three Nginx replicas all ended up on the same node where the persistent volume was available, rather than being spread out.

ReadWriteOnce is the access mode you’ll deal with most of the time when working with Kubernetes clusters. Any locally attached storage (local persistent volumes) will use this access mode. Most block storage solutions, both on-premises (OpenEBS, Ceph block devices) and in cloud environments (Amazon Elastic Block Storage, Google Cloud persistent disks, etc.)

A ReadWriteOncePod mode is also available in recent versions of Kubernetes. This is similar to the ReadWriteOnce mode, but the attachment limitation is per-pod rather than per-node.

ReadWriteMany

As you might have guessed from the name, this access mode allows multiple nodes (and thus pods) to read and write to a volume simultaneously. While this does sound like it could address a lot of the scaling challenges we described earlier, there are some performance considerations to keep in mind.

Most storage implementations of a ReadWriteMany access mode are based on the concept of a shared filesystem (as opposed to block devices). CephFS, Amazon Elastic File System, S3FS, GlusterFS and of course NFS are all examples of ReadWriteMany storage.

By design, these are significantly slower than block storage devices (even network attached ones), since you can no longer benefit from caching blocks in memory (you can still cache files), and cache invalidation becomes significantly more expensive, given that it has to be coordinated between multiple readers and writers.

Having said that, some clustered file systems are able to provide ReadWriteMany access at the block level too (AWS EBS has a Multi-Attach feature for example) but it’s still a significant tradeoff in performance (and complexity) compared to ReadWriteOnce attachments.

ReadOnlyMany

This is a less common access mode, and most of the implementations rely on the same backend as a ReadWriteMany volumes while providing read-only access to the client.

However, there are some block-level implementations that support the ReadOnlyMany access mode, like the native iSCSI, which supports ReadWriteOnce and ReadOnlyMany (but not ReadWriteMany).

This access mode is quite useful if you want to share a single block device with multiple nodes (and pods) and can make sure they’ll be okay with read-only access. There are still some performance implications compared to single-attachment block devices, but it is a good middleground between a multi-client network filesystem and a single-client block device.

In a typical web application, a ReadOnlyMany volume can guarantee the statelessness of an application, while sharing the codebase among multiple pods across multiple nodes for example, which is great for scaling out. However, in practice it is more common to simply duplicate the read-only codebase on directly attached storage instead, so each pod can have its own copy, providing significantly better performance and (arguably) some less complexity.

Access Modes for WordPress

There is no single correct answer here as there are multiple ways to run WordPress applications in a Kubernetes cluster.

If you opt-in for the simplest single-pod deployment, a locally attached ReadWriteOnce volume will probably give you the best performance and simplicity. For some redundancy you may look at a replicated block device, still exposed to a single node via ReadWriteOnce.

In multi-pod and multi-node configurations you’ll likely have a combination of these. For example, all nodes in your MariaDB cluster may have ReadWriteOnce local persistent volumes, and your WordPress pods may have the application codebase in ReadWriteOnce volumes, with the media being shared through a ReadWriteMany filesystem.

We’ll explore some of these topologies in more depth in future sections. For now, make sure you have a good understanding between the different modes, and the tradeoffs required for each.

In the next section we’ll be looking at vertical and horizontal scaling, and how they relate to a typical WordPress application in a Kubernetes cluster.