Running WordPress on Kubernetes

WordPress on Kubernetes

Recently I posted about creating a highly available WordPress deployment using Amazon Web Services. The focus was using Terraform and Docker to automate the deployment. With the release of Pivotal Container Service I thought I would explore what it would take to get a similar setup running on GCP.  This post will focus more on using Kubernetes to deploy your containers.

Before you start make sure that you have a Kubernetes cluster setup in GCP.

Create the Kubernetes cluster

Update kubectl to point to the new cluster. The below command will load the required credentials for you to interact with the cluster.

Once the cluster is ready we can begin by setting up WordPress.

Create the Database

The first step is creating the database. The simplest thing to do in this case is to create one inside our Kubernetes cluster. There are some flaws with this approach which I will discuss later.

The above YAML configuration defines a Pod based on the Mysql docker image. The Pod is the lowest level object within Kubernetes. A pod can be responsible For running 1 or more containers. It may be tempting to run more than one Docker container within a pod but generally, this is considered an anti-pattern. If you have two containers within a pod you cannot scale them independently. We could have defined our WordPress instance here but that will reduce our flexibility if we decide we need to scale the front end PHP app.

In addition to defining the container image to be used we must specify some of the environment variables that are required to configure the instance.

Apply the configuration to create the database.

Now that we have a Mysql instance we need to expose it as a service that WordPress can consume. It is always best to communicate between pods using a service.  The service acts as a decoupling point between the pods. We can change the implementation of a backend service without informing the consumer.  In addition, we can scale the pod to multiple instances if more capacity is required.

The above YAML exposes the new service. Kubernetes uses labels to connect the service to the eligible pods that support it.  In this case, we are targeting our service at any pod with the labels . app=wordpress and tier=mysql If we scale the MySQL pod with additional instances the service will round-robin requests between them.

As we can see we now have the wordpress-mysql service listening on 10.15.248.13:3306

Starting WordPress

Now that we have Mysql up and running we can deploy WordPress itself.

The pod definition utilizes the WordPress Docker container. We have hardcoded the database address using the IP of the MySQL container. Later on, I will discuss how to expose this address using Kubernetes service discovery.

Lastly, we need to expose WordPress via a load balancer facing the internet.

Once the load balancer is created we can access the blog at http://35.226.13.13:8888/

While we now have things running there are several things we can improve on.

Exposing the database using service discovery.

When creating a service Kubernetes creates DNSns entry to help locate that service.  The format is my-svc.my-namespace.svc.cluster.localWith this in mind we can update the app’s database connection. If we move the database or change its implementation as long as the service name is the same our application will be able to connect.

While all of this works as desired it exposes a few anti patterns in Kubernetes.

Use a Deployment

As mentioned earlier pods are the lowest level of deployment within Kubernetes.  A Deployment is a higher level artifact in Kubernetes.  It’s a description of a desired state and is also the starting point of being able to upgrade your application in a controlled manner.

To illustrate this more simply I will use a Deployment containing an Nginx container.

The Yaml above will create or desired state of having 3 copies of the nginx Pod running.  It will create a ReplicaSet which is repsoible if ensuring we always have 3 nodes running.

Applying the deployment gives us three copies of the pod. If one pod is terminated it will be replaced automatically by the ReplicaSet.

Rollouts

If we wish to update nginx we can force a rolling deployment of the upgrade. After editing the Yaml with the new version we can force an update.  Deployments have options that can be configured to control what process is used for the rollout.  In most cases you will want a rolling update to prevent an outage.

Deployments also keep a history of the changes as it is possible to rollback a deployment to a previous Version.

Persistent Disk Storage

Back to WordPress: So far we have a created a Mysql database deployed to our cluster.  With this setup is that we have a our data stored inside the container.  If we need to recreate this container for any reason we will lose our date.  Therefore we want to store data outside of the container.  Kubernetes provides a volume service to do this.  Depending on the cloud provider used there may be a few options of what type of disk to use.  Since we are in GCP Kubernetes will use a GCEPersistentDiskby default.

In the above Yaml we assign /var/lib/mysql to a persistent volume.

This volume is created automatically for us when the Deployment is applied.

Putting it all together

Its possible to combine the entire configuration with a single yaml file.  Similar to what you would do with docker-compose.

Other areas to explore

There are a few other areas that I will be exploring futher

 

You may also like...