How To Set Up WordPress with MySQL on Kubernetes

Kubernetes Cluster Setup

Using Kubernetes architecture, we setup a master node which delegates tasks and manages resources to multiple ‘worker nodes’. Let’s label one of our master and another as worker nodes 1. Once we have our cluster up and running, it’s time to make it work for us. Every node will communicate with the master using Kubectl, a binary package that we installed earlier in the tutorial. WordPress requires a persistent volume (one that doesn’t get destroyed by reboots or application deletions) that is used by MySQL for maintaining various databases used by WordPress. You can open a file persistent-volume.yaml using any text editor on your terminal.
PersistentVolumes (PVs) are storage resources in a cluster that are manually created by an administrator, or dynamically created by Kubernetes. A PersistentVolumeClaim (PVC) is a request from an end-user for storage that can be handled by a PV. PersistentVolumeClaims and PersistentVolumes are independent of pod lifecycles and maintain data even when pods are restarted, rescheduled, or even deleted.

Objectives

  • Create PersistentVolumeClaims and PersistentVolumes
  • Create a kustomization.yaml with
    • a Secret generator
    • MySQL resource configs
    • WordPress resource configs
  • Apply the kustomization directory by kubectl apply -k ./
  • Clean up

Download the following configuration files:

mysql-deployment.yaml
wordpress-deployment.yaml
 

Create PersistentVolumeClaims and PersistentVolumes

For MySQL

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pv-claim
  labels:
    app: wordpress
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 20Gi

For WordPress

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: wp-pv-claim
  labels:
    app: wordpress
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 20Gi

Create a kustomization.yaml

Add a Secret generator
A Secret is an object that stores a piece of sensitive data like a password or key. Kubectl supports the management of Kubernetes objects using a kustomization file. You can create a Secret by generators in kustomization.yaml file.
Add a Secret generator in kustomization.yaml from the following command. You will need to replace YOUR_PASSWORD with the password you want to use.
 
cat <<EOF >./kustomization.yaml
secretGenerator:
- name: mysql-pass
  literals:
  - password=YOUR_PASSWORD
EOF
 

Add resource configs for MySQL and WordPress

The following manifest describes a single-instance MySQL Deployment. The MySQL container mounts the PersistentVolume at /var/lib/mysql. The MYSQL_ROOT_PASSWORD environment variable sets the database password from the Secret.
 
apiVersion: v1
kind: Service
metadata:
  name: wordpress-mysql
  labels:
    app: wordpress
spec:
  ports:
    - port: 3306
  selector:
    app: wordpress
    tier: mysql
  clusterIP: None
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pv-claim
  labels:
    app: wordpress
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 20Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: wordpress-mysql
  labels:
    app: wordpress
spec:
  selector:
    matchLabels:
      app: wordpress
      tier: mysql
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: wordpress
        tier: mysql
    spec:
      containers:
      - image: mysql:5.6
        name: mysql
        env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-pass
              key: password
        ports:
        - containerPort: 3306
          name: mysql
        volumeMounts:
        - name: mysql-persistent-storage
          mountPath: /var/lib/mysql
      volumes:
      - name: mysql-persistent-storage
        persistentVolumeClaim:
          claimName: mysql-pv-claim
The following manifest describes a single-instance WordPress Deployment. The WordPress container mounts the PersistentVolume at /var/www/html for website data files. The WORDPRESS_DB_HOST environment variable sets the name of the MySQL Service defined above, and WordPress will access the database by Service. The WORDPRESS_DB_PASSWORD environment variable sets the database password from the Secret kustomize generated.
apiVersion: v1
kind: Service
metadata:
  name: wordpress
  labels:
    app: wordpress
spec:
  ports:
    - port: 80
  selector:
    app: wordpress
    tier: frontend
  type: LoadBalancer
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: wp-pv-claim
  labels:
    app: wordpress
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 20Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: wordpress
  labels:
    app: wordpress
spec:
  selector:
    matchLabels:
      app: wordpress
      tier: frontend
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: wordpress
        tier: frontend
    spec:
      containers:
      - image: wordpress:4.8-apache
        name: wordpress
        env:
        - name: WORDPRESS_DB_HOST
          value: wordpress-mysql
        - name: WORDPRESS_DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-pass
              key: password
        ports:
        - containerPort: 80
          name: wordpress
        volumeMounts:
        - name: wordpress-persistent-storage
          mountPath: /var/www/html
      volumes:
      - name: wordpress-persistent-storage
        persistentVolumeClaim:
          claimName: wp-pv-claim
Download the MySQL deployment configuration file.
curl -LO https://k8s.io/examples/application/wordpress/mysql-deployment.yaml
Download the WordPress configuration file.
curl -LO https://k8s.io/examples/application/wordpress/wordpress-deployment.yaml
Add them to kustomization.yaml file.
cat <<EOF >>./kustomization.yaml
resources:
  - mysql-deployment.yaml
  - wordpress-deployment.yaml
EOF

Apply and Verify

The kustomization.yaml contains all the resources for deploying a WordPress site and a MySQL database. You can apply the directory by
kubectl apply -k ./
Now you can verify that all objects exist.
$ sudo kubectl apply -k ./

secret/mysql-pass-dd6525th4g created
service/wordpress created
service/wordpress-mysql created
persistentvolumeclaim/mysql-pv-claim created
persistentvolumeclaim/wp-pv-claim created
deployment.apps/wordpress created
deployment.apps/wordpress-mysql created
Verify that the Secret exists by running the following command:
$ sudo kubectl get secrets
NAME                    TYPE                                  DATA   AGE
mysql-pass-dd6525th4g   Opaque                                1      41s
Verify that a PersistentVolume got dynamically provisioned.
Note: It can take up to a few minutes for the PVs to be provisioned and bound.
$ sudo kubectl get pvc
NAME             STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mysql-pv-claim   Bound    pvc-d8f643f5-c5c1-40b9-8bcc-2a610be7bd9d   20Gi       RWO            standard       83s
wp-pv-claim      Bound    pvc-ce759d93-2976-4ae9-9059-9e21119c22dc   20Gi       RWO            standard       83s
Verify that the Pod is running by running the following command:
Note: It can take up to a few minutes for the Pod’s Status to be RUNNING.
​$ sudo kubectl get pods
NAME                              READY   STATUS    RESTARTS   AGE
wordpress-56c6675d48-kgq2t        1/1     Running   0          2m1s
wordpress-mysql-57f67668b-pzqmw   1/1     Running   0          2m1s
Verify that the Service is running by running the following command:
$ sudo kubectl get services wordpress
NAME        TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
wordpress   LoadBalancer   10.99.231.19   <pending>     80:32137/TCP   2m56s

Note: Minikube can only expose Services through NodePort. The EXTERNAL-IP is always pending.
Run the following command to get the IP Address for the WordPress Service:

$ sudo minikube service wordpress --url
http://172.31.22.143:32137
http://52.14.63.97:32137
If you are using AWS instance then we need to allow port 32137 into security group and use the public IP. Copy the IP address, and load the page in your browser to view your site.
You should see the WordPress set up page similar to the following screenshot.
 
 
Warning: Do not leave your WordPress installation on this page. If another user finds it, they can set up a website on your instance and use it to serve malicious content.
Either install WordPress by creating a username and password or delete your instance.

Cleaning up 

Run the following command to delete your Secret, Deployments, Services, and PersistentVolumeClaims:
kubectl delete -k ./

Conclusion

That’s all you need to know about how to set up WordPress with MySQL on Kubernetes. I hope the above article helps to set up WordPress and MySQL on Kubernetes. There are more tutorials that will go into a deeper explanation of using Kubernetes thoroughly, but this is a simple article to just get familiar with setting up WordPress with MySQL on Kubernetes.

References

https://kubernetes.io/docs/
https://kubernetes.io/docs/reference/kubectl/cheatsheet/
https://kubernetes.io/docs/tutorials/stateful-application/mysql-wordpress-persistent-volume/
 
Avatar photo

Asif Khan

Responsible and proactive professional with more than 13 years of experience in IT systems, open source software applications, DevOps, Linux systems, and cloud operations. My main goals are to automate things, keep them safe, and make sure they are strong. I am very good at planning and building the infrastructure for services that people really want. I was drawn to the fast-paced world of cloud computing because it has resources that can be scaled up or down as needed. One of my best skills is being able to use a lot of different DevOps tools to set up, release management, and microservices ecosystems, as well as for provisioning, orchestration, and configuration management.