Despite a lot of articles written on how to run WordPress in Kubernetes, in a previous blog post, I identified two key challenges around horizontally scaling WordPress in Kubernetes. In this post, I will cover how to solve the first challenge when running WordPress in Kubernetes: how do you ensure each replica of a WordPress site is exposing the exact same content?
The easiest solution to ensuring each replica is exposing the same content is to host all the content in a Network File Share (NFS) and mounting the NFS at the location where your wp-content is expected. For default WordPress installations, this is <Wordpress directory>/wp-content (e.g. /var/www/html/wp-content).
Because I had created a Kubernetes cluster in Azure, the rest of this blog will talk about how to create and mount an Azure File share (which is a NFS offering in Azure). But if your Kubernetes cluster is running on other cloud provides like Amazon Web Services, Google Cloud Platform, Oracle Cloud Infrastructure, etc., then you need to identify the equivalent service that offer NFS like capability and then perform the following steps.
Azure File Share
While you can create and maintain your own Samba file share on a regular Linux VM that is exposed via Public IP, Azure offers a fully managed NFS service via Azure File share. You can find instructions on how to create and mount a static Azure File share to your Kubernetes cluster over here. I will specify each of the Kubernetes resources you need to create in the next section, so all you need to do at the moment is the following:
- Create a new Azure Storage account. You can also use an existing one if you would like.
- Create a new Azure File share.
- Upload all of your WordPress File share content to a directory. If you are creating a new WordPress site, and have nothing to upload, just create a new directory where you want all the content for this site to be hosted at.
- Have your Azure Storage account name and key ready for the next section.
Once you have created a new Azure File share and uploaded all your WordPress content to it, you will have to do the following tasks:
- Create a Secret storing credentials to your Azure storage account
- Create a PersistentVolume that points to your Azure File share
- Create a PersistentVolumeClaim that points to your PersistentVolume
- Create a Deployment that consumes PersistentVolumeClaim
- Create a Service to expose WordPress to public internet
Create Kubernetes Secret
# TODO: replace <Azure Storage account name> with name of your account # TODO: replace <Azure Storage account key> with your storage account key kubectl create secret generic azure-secret --from-literal=azurestorageaccountname=<Azure Storage account name> --from-literal=azurestorageaccountkey=<Azure Storage account key>
Create Kubernetes PersistentVolume
Copy the following content into a file called pv.yml and then run: “kubectl create -f pv.yml” command on terminal.
apiVersion: v1 kind: PersistentVolume metadata: name: azurefile spec: capacity: storage: 10Gi accessModes: - ReadWriteMany storageClassName: azurefile azureFile: secretName: azure-secret shareName: "<your Azure File share name>" # TODO: fill in this value readOnly: false mountOptions: - dir_mode=0777 - file_mode=0777 - uid=1000 - gid=1000 - mfsymlinks - nobrl
Create Kubernetes PersistentVolumeClaim
Copy the following content into a file called pvc.yml and then run: “kubectl create -f pvc.yml” command on terminal.
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: azurefile spec: accessModes: - ReadWriteMany storageClassName: azurefile resources: requests: storage: 10Gi
Create Kubernetes Deployment for WordPress
Copy the following content into a file called deploy.yml and then run: “kubectl create -f deploy.yml” command on terminal.
apiVersion: apps/v1 kind: Deployment metadata: name: wordpress labels: app: wordpress spec: selector: matchLabels: app: wordpress strategy: rollingUpdate: maxSurge: 1 maxUnavailable: 1 replicas: 3 template: metadata: labels: app: wordpress spec: containers: - name: wordpress image: wordpress:5.5.1-php7.4-apache env: - name: WORDPRESS_DB_HOST value: "<your host>" # TODO: fill in this value - name: WORDPRESS_DB_NAME value: "<your DB>" # TODO: fill in this value - name: WORDPRESS_DB_USER value: "<your user>" # TODO: fill in this value - name: WORDPRESS_DB_PASSWORD valueFrom: secretKeyRef: name: "<your DB password secret>" # TODO: fill in this value key: "<your DB password key>" # TODO: fill in this value ports: - containerPort: 80 volumeMounts: - name: azurefile subPath: "<Azure File share path containing wp_content>" # TODO: fill in this value mountPath: /var/www/html/wp-content volumes: - name: azurefile persistentVolumeClaim: claimName: azurefile
Create Kubernetes Service
Copy the following content into a file called service.yml and then run: “kubectl create -f service.yml” command on terminal.
apiVersion: v1 kind: Service metadata: name: wordpress spec: selector: app: wordpress ports: - name: wordpress protocol: TCP port: 80 targetPort: 80 type: LoadBalancer