Overview
In this tutorial, you will be guided through the process of running WordPress on Kubernetes.
You will learn how to deploy a WordPress Docker container as a Kubernetes Pod, attach persistent storage for storing themes, plugins, and uploaded content, and connecting it to MySQL database.
This lab will walk you through the process on Google’s GKE.
Secrets
Secrets are what we label any sensitive information that shouldn’t be available in clear text. This includes credentials to backend services, such as databases.
Since WordPress must connect to a database, MySQL in our case, we must create a Kubernetes Secret to store our connection password.
Kubernetes stores secrets as Base64 encodes, so the first thing you need to do is encode your MySQL user password to Base64
echo “my-super-secret-password | base64
c3VwZXItc2VjcmV0LXBhc3N3b3JkCg==
The output of the command will look something similar to the example above. Keep note of this output, as we will need to add it to a secrets YAML file.
Now create a new file named secrets.yml.
touch secrets.yml
Add the following contents to secrets.yml, replacing the value for wordpress_db_password with your base64 encoded string.
---
apiVersion: v1
kind: Secret
metadata:
name: myblog-secrets
type: Opaque
data:
wordpress_db_password: c3VwZXItc2VjcmV0LXBhc3N3b3JkCg==
Using the
Kubectl apply -f secrets.yml
Creating a Pod Deployment
A pod is the smallest atomic part of Kuberbetes, and each pod has at least one container inside of it. Pods have their own isolated namespace, filesystem, and network stack shared by all containers encapsulated inside of it.
A deployment is a declares how a pod should be deployed, including the number of replicas that should be created. While a pod resource can be deployed on its own, deployments are used to increase availability.
Create a new YAML file for your WordPress site.
touch myblog-deployment.yml
Add the following to the file.
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: site1-deployment
labels:
app: site1
spec:
replicas: 1
selector:
matchLabels:
app: site1
template:
metadata:
labels:
app: site1
spec:
containers:
- name: app1
image: wordpress:5.2
ports:
- containerPort: 80
env:
- name: WORDPRESS_DB_HOST
value: 10.0.0.25:3306
- name: WORDPRESS_DB_USER
value: root
- name: WORDPRESS_DB_PASSWORD
valueFrom:
secretKeyRef:
name: myblog-secrets
key: wordpress_db_password
Run the
kubectl apply -f myblog-deployment.yml
The
kubectl get deployments
You will also want to check the status of the pods, as a pod’s health is not tied to the health of a deployment. To check your pod’s status, run the
kubectl get pods
Creating a Service Resource
Pods are ephemeral and that means the so is the IP addresses assigned to them. A pod’s IP address is also not routable outside of a Kubernetes cluster, which is my service resources are created.
The service resource is static and is loosely coupled to the pods it services via labels. Service resources are exposed outside of the cluster through a variety of types, with each having it’s own characteristics.
The following service types are avaialable:
- ClusterIP
- NodePort
- LoadBalancer
A ClusterIP is only routable within the Kubernetes cluster and is ideal for services that should remain internal, such as backend services for applications used by web applications.
The NodePort type ties a service to a specific port shared by all nodes in the cluster.
Finally, there is the LoadBalancer types, which will assign your service its own publicly routable IP address. The LoadBalancer type is a cloud feature, and its availability is dependent on cloud networking, with the exception of MetalLB.
When you run a hosted Kubernetes cluster, such as GKE, AKS, or DigitalOceans Kubernetes, the LoadBalancer type will trigger the provisioning of a compute load balancer that will be tied to your service.
We are going to create a LoadBalancer type service, as this is the most common for exposing services to the public Internet.
Create a new file to configure your WordPress site’s service resource.
touch myblog-service.yml
Add the following contents to it.
---
apiVersion: v1
kind: Service
metadata:
name: site1-service
spec:
type: LoadBalancer
selector:
app: site1
ports:
- protocol: TCP
port: 80
targetPort: 80
Create the service for the
kubectl apply -f myblog-service.yml
You can monitor the service’s status by using the kubectl get svc command. When the LoadBalancer type is used a public IP address is assigned to it, and this process can take a minute or two to complete.
kubectl get svc
Attaching Persistence Storage
Containers are ephemeral by default, meaning any plugins, themes, or uploads add to your blog will disappear when a Pod stops. In order to persist data between pod life cycles, you will need to attach storage volumes to it.
Attaching storage is a two-step process in Kubernetes. You must first create a storage claim, where you define the storage itself, and then configure your Pod to mount the storage claim as a volume.
Creating a Persistent Storage Claim
When operating in cloud environment you can create a storage claim alone. The claim will typically create a compute disk volume matching the state declared in the Kubernetes storage claim resource.
We are going to create a persistent volume for all of our blog content, including themes, plugins, and uploads. This is required to ensure these items persist when our pods are recreated.
Create a new file named myblog-wpcontent-storage.yml.
touch mybog-wpcontent-storage.yml
And add the following contents to it to create a 1 GiB storage volume.
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: site1-disk
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
Mounting a Storage Claim in Your Pod
To mount the storage volume generated by the claim you will need to add to parts to the deployment YAML file. The first instructs the container where to mount a volume, and the second ties the storage claim to the container.
Add the following lines under the container section of the deployment template section.
volumeMounts: - mountPath: "/var/www/wp-content" name: wpcontent
Now, under the spec key, add the following to assign the storage claim to the deployment.
volumes: - name: wpcontent persistentVolumeClaim: claimName: site1-disk
Your updated
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: site1-deployment
labels:
app: site1
spec:
replicas: 1
selector:
matchLabels:
app: site1
template:
metadata:
labels:
app: site1
spec:
containers:
- name: app1
image: wordpress:5.2
ports:
- containerPort: 80
volumeMounts:
- mountPath: "/var/www/wp-content"
name: wpcontent
env:
- name: WORDPRESS_DB_HOST
value: 10.0.0.25:3306
- name: WORDPRESS_DB_USER
value: root
- name: WORDPRESS_DB_PASSWORD
valueFrom:
secretKeyRef:
name: myblog-secrets
key: wordpress_db_password
volumes:
- name: wpcontent
persistentVolumeClaim:
claimName: site1-disk
Apply your changes to the deployment by using the
kubectl apply -f myblog-deployment.yml
Kubernetes will automatically detect the changes and update the deployment’s declared state.