How to Deploy WordPress on Vultr Kubernetes Engine

Updated on February 12, 2024
How to Deploy WordPress on Vultr Kubernetes Engine header image

Introduction

WordPress is a free, open-source content management system (CMS), built with PHP and MySQL. It offers ease of use and flexibility that allow users to create and manage websites and blogs. It is a popular choice among web developers and content creators.

Deploying WordPress on Kubernetes offers several benefits, such as scalability, high availability and deployment of multiple environments. You can scale your WordPress website on the Vultr Kubernetes Engine, ensuring that the website can handle increased traffic. Kubernetes deployment also ensures your website's high availability, making it more fault tolerant. It also allows deploying and managing multiple environments such as development, staging, production, and so on.

This article demonstrates the steps to deploy a WordPress website on the Vultr Kubernetes Engine using the official container image and Vultr Managed Database as the database backend.

Prerequisites

Before you begin, you should:

Ensure that you provision all the services in the same region for low latency between the services.

Install OpenEBS and Dynamic NFS Provisioner

OpenEBS is an open-source storage platform for Kubernetes. It provides a highly available storage solution for the containers. Dynamic NFS Provisioner is an add-on that automates the provisioning of Network File System (NFS) volumes in a Kubernetes cluster. It provides a new storage class that allows the creation of ReadWriteMany volumes so that multiple pods can share the storage and endure the stateful nature of WordPress.

Install the OpenEBS operator.

# kubectl apply -f https://openebs.github.io/charts/openebs-operator.yaml

The above command installs the OpenEBS operator on the cluster creating all the required resources, such as role bindings, custom resource definitions and more.

Install the Dynamic NFS Provisioner.

# kubectl apply -f https://openebs.github.io/charts/nfs-operator.yaml

The above command installs the NFS operator on the cluster creating a new storage class named openebs-rbx that allows creating abstract volumes using a backend storage class to create ReadWriteMany volumes. It uses the openebs-hostpath storage class as the default backend storage class. In the next step, you update this storage class to use the vultr-block-storage as the backend storage class.

Create a new file named sc-rbx.yaml.

# nano sc-rbx.yaml

Add the following contents to the file.

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: openebs-rwx
  annotations:
    openebs.io/cas-type: nfsrwx
    cas.openebs.io/config: |
      - name: NFSServerType
        value: "kernel"
      - name: BackendStorageClass
        value: "vultr-block-storage"
provisioner: openebs.io/nfsrwx
reclaimPolicy: Delete

The above manifest updates the openebs-rwx storage class to use the vultr-block-storage as the backend storage class.

Apply the manifest file.

# kubectl apply -f sc-rbx.yaml

Create the Persistent Volume

You installed the OpenEBS and the Dynamic NFS Provisioner in the previous section to create a new ReadWriteMany volume. This section demonstrates the steps to create a new Persistent Volume Claim (PVC) using the openebs-rwx storage class for the WordPress deployment.

Create a new file named wp-pvc.yaml.

# nano wp-pvc.yaml

Add the following contents to the file.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: wordpress-pvc
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: "openebs-rwx"
  resources:
    requests:
      storage: 20Gi

The above manifest creates a new PVC resource for the WordPress deployment with 20GB storage. You can change the spec.resources.requests.storage value to match your storage need.

Apply the manifest file.

# kubectl apply -f wp-pvc.yaml

Verify the deployment.

# kubectl get pvc wordpress-pvc

You can also confirm the deployment by going to the customer portal, opening the cluster page and navigating to the Linked Resources tab. You should see a new block storage resource linked to the cluster matching the storage size of the wordpress-pvc resource.

Prepare the Kubernetes Cluster

You must prepare the Kubernetes cluster for the WordPress deployment by installing the required plugins and creating a few resources. This section demonstrates the steps to install the ingress-nginx controller, install the cert-manager plugin, and create a ClusterIssuer resource for issuing Let's Encrypt certificates.

Install the ingress-nginx controller and the cert-manager plugin.

# kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.5.1/deploy/static/provider/cloud/deploy.yaml
# kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.10.0/cert-manager.yaml

The above commands install the ingress-nginx controller and the cert-manager plugin on the cluster using the official manifest files. The ingress-nginx controller provisions a load balancer add-on to handle incoming HTTP requests on the Ingress resources.

Fetch the load balancer IP address.

# kubectl get services/ingress-nginx-controller -n ingress-nginx

It may take up to 5 minutes before the load balancer is ready. You can confirm the deployment by going to the customer portal, opening the cluster page and navigating to the Linked Resources tab. You should see a new load balancer resource linked to the cluster. You must point the A record for wordpress.example.com to the IP address of the load balancer.

Create a new file named le_clusterissuer.yaml.

# nano le_clusterissuer.yaml

Add the following contents to the file.

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: "YOUR_EMAIL"
    privateKeySecretRef:
      name: letsencrypt-prod
    solvers:
      - http01:
          ingress:
            class: nginx

The above manifest creates a ClusterIssuer resource for issuing Let's Encrypt certificates. It uses the HTTP01 challenge solver to verify the ownership. You must change the spec.acme.email value to your email address.

Apply the manifest file.

# kubectl apply -f le_clusterissuer.yaml

Verify the deployment.

# kubectl get clusterissuer letsencrypt-prod

Create a new database for the WordPress deployment.

  • Log in to the customer portal.
  • Navigate to the Databases tab.
  • Open your MySQL cluster page.
  • Navigate to the Users & Databases tab.
  • Add a new database named wordpress by clicking the Add New Database button.
  • Navigate to the Overview tab.
  • Copy the credentials, including the hostname, port, user and password.

You can optionally create a new user as well.

Create a new secret resource named wordpress-db-pass.

# kubectl create secret generic wordpress-db-pass --from-literal=password="MYSQL_USER_PASSWORD"

The above command creates a new secret resource containing the MySQL user's password. You must change the --from-literal=password= to the MySQL user password.

Deploy the WordPress Website

You installed the required add-ons and created all the necessary resources in the previous sections, such as the PVC and secret resources. This section demonstrates the steps to create a new Deployment resource for the WordPress deployment and a new Service resource to expose the connections to the WordPress pods within the cluster.

Create a new file named wp-deployment.yaml.

# nano wp-deployment.yaml

Add the following contents to the file.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: wordpress
spec:
  replicas: 1
  selector:
    matchLabels:
      app: wordpress
  template:
    metadata:
      labels:
        app: wordpress
    spec:
      containers:
        - name: wordpress
          image: wordpress:6.1.1-php8.2-apache
          ports:
          - containerPort: 80
            name: wordpress
          volumeMounts:
            - name: wordpress-data
              mountPath: /var/www/html
          env:
            - name: WORDPRESS_DB_HOST
              value: HOST:PORT
            - name: WORDPRESS_DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: wordpress-db-pass
                  key: password
            - name: WORDPRESS_DB_USER
              value: USER
            - name: WORDPRESS_DB_NAME
              value: DATABASE
      volumes:
        - name: wordpress-data
          persistentVolumeClaim:
            claimName: wordpress-pvc

The above manifest creates a new deployment resource named wordpress on the cluster. It uses the wordpress-pvc resource as the volume and the wordpress-db-pass resource for fetching the MySQL user password. You must change the environment variable values in the container template specification to the credentials of your MySQL cluster, such as the hostname, port, user and database name. You can also change the spec.replicas value to change the number of initial replicas.

Apply the manifest file.

# kubectl apply -f wp-deployment.yaml

Verify the deployment.

# kubectl get deployment wordpress
# kubectl get pods

Create a new file named wp-svc.yaml.

# nano wp-svc.yaml

Add the following contents to the file.

apiVersion: v1
kind: Service
metadata:
  name: wordpress-svc
spec:
  ports:
    - name: http
      port: 80
      protocol: TCP
      targetPort: 80
  selector:
    app: wordpress

The above manifest creates a new service resource named wordpress-svc with the app: wordpress selector to expose the connections to the WordPress pods within the cluster. This resource allows exposing the connections to the internet using an Ingress resource you create in the next section.

Apply the manifest file.

# kubectl apply -f wp-svc.yaml

Verify the deployment.

# kubectl get svc wordpress-svc

Set Up External Access

This section demonstrates the steps to create an Ingress resource to set up external access to your WordPress website. It also gives an overview of the session affinity configuration with the ingress-nginx controller. You must verify that the letsencrypt-prod cluster issuer resource is ready before you proceed with these steps.

Create a new file named wp-ingress.yaml.

# nano wp-ingress.yaml

Add the following contents to the file.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: wordpress-ingress
  annotations:
    kubernetes.io/ingress.class: nginx
    cert-manager.io/cluster-issuer: letsencrypt-prod
    nginx.ingress.kubernetes.io/affinity: "cookie"
    nginx.ingress.kubernetes.io/session-cookie-name: "wordpress-cluster"
    nginx.ingress.kubernetes.io/session-cookie-expires: "14400"
    nginx.ingress.kubernetes.io/session-cookie-max-age: "14400"
spec:
  tls:
    - secretName: wordpress-tls
      hosts:
        - wordpress.example.com
  rules:
    - host: wordpress.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: wordpress-svc
                port:
                  number: 80

The above manifest creates a new ingress resource named wordpress-ingress that enables external access to the wordpress-svc resource. It uses the letsencrypt-prod cluster issuer resource to issue a new SSL certificate for wordpress.example.com and store it as the wordpress-tls secret resource.

The above manifest also configures session affinity in the annotations using cookie affinity. This means a cookie directs future incoming requests to a specific pod, to prevent getting logged out of the WordPress dashboard due to load balancing between available pods. Refer to the Session Affinity section for more information.

Apply the manifest file.

# kubectl apply -f wp-ingress.yaml

Verify the deployment.

# kubectl get ingress wordpress-ingress

You can now access the WordPress website and complete the installation by opening https://wordpress.example.com in your web browser. The Let's Encrypt Certificate stored in the wordpress-tls secret resource secures the website. The ingress-nginx controller handles the automatic renewals of the certificate when it comes close to the expiry date.

After the installation is complete, you can migrate your existing WordPress website using plugins such as Duplicator, BackupBuddy, UpdraftPlus, Jetpack and more.

Scale the WordPress Deployment

The WordPress deployment demonstrated in the previous sections uses a ReadWriteMany volume that allows the WordPress pods to share the same volume. This section demonstrates the steps to increase or decrease the number of WordPress pods.

Increase the number of replicas.

# kubectl scale deployment/wordpress --replicas=6

The above command increases the number of deployment/wordpress replicas to 6.

Verify the change.

# kubectl get deployment wordpress
# kubectl get pods 

Decrease the number of replicas.

# kubectl scale deployment/wordpress --replicas=2

The above command decreases the number of deployment/wordpress replicas to 2.

Verify the change.

# kubectl get deployment wordpress
# kubectl get pods 

You can also test the fault tolerance of your WordPress deployment by deleting any running pod using the kubectl delete pod command. Kubernetes detects the state change and instantly creates a new pod to keep the deployment in a healthy state. New pods get detected by the ingress resource that starts serving the incoming requests in no time.

Conclusion

This article demonstrated the steps to deploy a WordPress website on the Vultr Kubernetes Engine using the official container image and Vultr Managed Database as the database backend. It also walked you through installing the OpenEBS storage platform and the Dynamic NFS Provisioner add-on for creating the ReadWriteMany volume based on the Vultr Block Storage volume.

You can further enhance the performance of your WordPress website by setting up a Vultr Managed Redis cluster as the object caching backend. This reduces the amount of SQL queries going to the MySQL cluster, reducing the request turn-around time. Refer to the Boost WordPress Performance with Vultr Managed Databases for Redis article for more information.

More Information