RUN WORDPRESS + MYSQL ON KUBERNETES

Seandon Mooy
Mar 27, 2019

TL;DR: Press "apply" on each of the configs below and you'll be running a new WordPress blog.

WordPress is a nice example app for learning Kubernetes basics, because it involves a handful of moving pieces which most WordPress administrators are familiar with:

  1. You need to deploy the WordPress code
  2. You'll need a database system to store your blog's data
  3. You'll need some persistent storage for the database's data
  4. Finally, you need to expose the service to the internet

Kubernetes exposes a few high level resources which will help us get this job done:

  • A PersistentVolumeClaimA PersistentVolumeClaim is a request for storage - it asks the Kubernetes Cluster for a particular type of storage which it can use as a Volume.Read More..., which asks the system for a bit of disk storage
  • A SecretA secret is a file, set of keys and values, or blob of data which can be provided to particular podsRead More..., which will store our database password
  • A MySQL DeploymentIn Kubernetes, a Deployment is an object which describes how an application is deployed. A Deployment defines the images to launch, how to configure them, and how they should be deployedRead More..., which controls the DB containers and their configuration
  • Another DeploymentIn Kubernetes, a Deployment is an object which describes how an application is deployed. A Deployment defines the images to launch, how to configure them, and how they should be deployedRead More... for WordPress, similiarly controlling the containers running PHP + WordPress
  • A ServiceA Service describes how to access your applications over the networkRead More... which allows WordPress to talk to our DB
  • Finally, another ServiceA Service describes how to access your applications over the networkRead More..., which exposes WordPress to the internet!

These are some of the high level resources that make up Kubernetes, and are the building blocks of your infrastructure. KubeSail provides an easy way to both learn and iterate on k8s resources. Click the "Apply" button to instantly deploy to your own KubeSail.com namespace, or hover over any section to learn more!

For this tutorial we're going to stick fairly close to this article, and the YAML below will work on any Kubernetes cluster, from AWS or Google, to KubeSail Hobby Tier! There are no KubeSail-specific details, no OS-specific details, and no Cloud-specific details! We will discuss the one point where you may want to make a different decision, which is usually when it comes to how you expose your application to the internet.

Configuring MySQL

Let's start with the PersistentVolumeClaimA PersistentVolumeClaim is a request for storage - it asks the Kubernetes Cluster for a particular type of storage which it can use as a Volume.Read More..., which asks Kubernetes for some disk space:

Apply
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-pv-claim
labels:
app: wordpress
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 50Mi
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Not so bad! We've asked for a very small slice of storage (50mb) which we'll use for our Database. Before creating our Database, let's first create a secret password, which we'll tell our Database and WordPress to use. K8s has a resource for encrypted things, called (naturally) SecretsA secret is a file, set of keys and values, or blob of data which can be provided to particular podsRead More.... We can create one very simply like so:

NOTE: You should change the password below before clicking "apply"

Apply
---
apiVersion: v1
kind: Secret
metadata:
name: mysql-pass
type: Opaque
stringData:
password: SECRET_PASSWORD_GOES_HERE
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Next step, let's spin up a MySQL database by way of a Kubernetes DeploymentIn Kubernetes, a Deployment is an object which describes how an application is deployed. A Deployment defines the images to launch, how to configure them, and how they should be deployedRead More.... These resources control how k8s deploys our applications, and allow us to specify things like what container image to use, how many instances to spin up, what disks should be attached, etc. Almost every application deployment option you can imagine is supported out of the box. See the documentation for more.

In this deployment, we're setting the environment variable MYSQL_ROOT_PASSWORD from the secret you created earlier.

Apply
---
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: kubesail/mysql:5.6
imagePullPolicy: Always
name: mysql
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
# Import our mysql-pass.password
# as MYSQL_ROOT_PASSWORD
name: mysql-pass
key: password
ports:
- containerPort: 3306
name: mysql
volumeMounts:
# Mount our PersistentVolumeClaim
# to /var/lib/mysql
- name: mysql-persistent-storage
mountPath: /var/lib/mysql
resources:
requests:
cpu: 5m
memory: 64Mi
limits:
cpu: 500m
memory: 192Mi
volumes:
- name: mysql-persistent-storage
persistentVolumeClaim:
claimName: mysql-pv-claim
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Excellent! Now we have a fully fledged MySQL server up and running! Not so bad right? All of this can be added to version control, just remember to encrypt or ignore your SecretA secret is a file, set of keys and values, or blob of data which can be provided to particular podsRead More...s!

Note that we used the image kubesail/mysql which is tuned to use less memory. but if you are running this on your own cluster or on the KubeSail hobby tier, you may want to use the standard mysql image.

The next step is to define a way for us to reach our MySQL server. This is one of the most often confused parts when learning Kubernetes, so it's important to understand the terms clearly. We're going to be defining a ServiceA Service describes how to access your applications over the networkRead More... for our MySQL DeploymentIn Kubernetes, a Deployment is an object which describes how an application is deployed. A Deployment defines the images to launch, how to configure them, and how they should be deployedRead More....

  • DeploymentsIn Kubernetes, a Deployment is an object which describes how an application is deployed. A Deployment defines the images to launch, how to configure them, and how they should be deployedRead More... control how applications are started, stopped, and updated.
  • ServicesA Service describes how to access your applications over the networkRead More... control how clients access a given DeploymentIn Kubernetes, a Deployment is an object which describes how an application is deployed. A Deployment defines the images to launch, how to configure them, and how they should be deployedRead More....

So, we'll be creating a MySQL service which points at our MySQL deployment.

Services and Deployments

You can think of a ServiceA Service describes how to access your applications over the networkRead More... as a combination of a DNS record, a port-forwarding rule, and a load-balancer. Like Deployments, almost every concievable option relating to exposing an application to a network can be defined in a ServiceA Service describes how to access your applications over the networkRead More.... See the Services Documentation for more. Let's create one!

NOTE: For now, KubeSail manages ServiceA Service describes how to access your applications over the networkRead More... objects for you, and you'll currently have read only access to this resource. For the purpose of this demo, the "Apply" button below will create the following service in your namespace for you. Of course, this service config will also work on any other k8s cluster!

Apply
---
apiVersion: v1
kind: Service
metadata:
name: wordpress-mysql
labels:
app: wordpress
spec:
ports:
- port: 3306
selector:
# Note that these match the "labels" in MySQL
app: wordpress
tier: mysql
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Configuring WordPress

Next, we'll configure our WordPress DeploymentIn Kubernetes, a Deployment is an object which describes how an application is deployed. A Deployment defines the images to launch, how to configure them, and how they should be deployedRead More...:

The service above was created for us, and was given a name automatically. The value for WORDPRESS_DB_HOST comes from the name of the service that is generated by KubeSail, but if you are running this on your own cluster, you'll want to update this value to be the name of the service you created in the last step.

Apply
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
resources:
requests:
cpu: 15m
memory: 64Mi
limits:
cpu: 500m
memory: 192Mi
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

And finally, we need to expose our WordPress application to the world! There are many many many ways to do this, but KubeSail makes it very easy by allowing you to simply expose your app through our infrastructure (we'll handle HTTPS, load balancing, high availablility, etc.) - click "Apply" to expose your WordPress instance!

Apply
apiVersion: v1
kind: Service
metadata:
name: wordpress-http
annotations:
getambassador.io/config: |
---
apiVersion: ambassador/v1
kind: Mapping
name: wordpress-http.namespace
prefix: "/"
service: http://wordpress-http.namespace:80
host: wordpress--namespace.cluster.kubesail.io
timeout_ms: 30000
spec:
ports:
- port: 80
selector:
app: wordpress
tier: frontend
type: ClusterIP
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Stay in the loop!

Give us a shout on twitter or gitter, checkout some of our GitHub repos and be sure to join our mailing list!