Following our guides on dockerizing and automating the delivery of WP projects, the last article in the series will show you how to configure and deploy WordPress on Kubernetes with Buddy CI/CD.

The guide is divided into two sections. The first one covers the basics of creating a volume on a K8s cluster and configuring your application. The second one shows how to streamline the whole process down to a single push to Git with Buddy CI/CD.

Part 1: How to run WordPress on Kubernetes

This part covers creating K8s volumes and configuring a WordPress instance with a MySQL database. If you’re interested in automating K8s deliveries, skip to part 2.

Configure a PersistentVolume in the K8s cluter

In this example, we’ll use a hostPath volume since we only have one node in the cluster. This type of volume mounts the path from the node’s filesystem into K8s.

WARNING: The hostPath volume is not recommended for multi-node production clusters. If you’re working on multiple nodes, follow the instructions here.

Create volumes.yml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: local-pv-1
  labels:
    type: local
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: /k8/volume/pv-1
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: local-pv-2
  labels:
    type: local
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: /k8/volume/pv-2

This config will create two R/W 10GB volumes in the node paths:

/k8/volume/pv-1
/k8/volume/pv-2
Create your K8s volumes

To create the volumes, run

kubectl apply -f volumes.yml

You can check if everything’s working correctly by running

kubectl get pv

NAME       CAPACITY ACCESSMODES RECLAIMPOLICY STATUS CLAIM STORAGECLASS REASON AGE
local-pv-1 10Gi     RWO         Retain        Available                        13s
local-pv-2 10Gi     RWO         Retain        Available                        13s

Configure a MySQL database

Start with creating a secret password for the MySQL root user:

kubectl create secret generic mysql-pass --from-literal=password=ROOT_PASSWORD

You can check if the password was properly configured by running

kubectl get secrets

NAME       TYPE   DATA AGE
mysql-pass Opaque 1    17h

TIP: Secrets in K8s are hidden and cannot be displayed. This means there’s no risk of exposing them in config files in public repositories.

Create mysql.yml

The file below will create a single MySQL instance with a proper volume and port mapping. It also uses the secret that we created earlier:

apiVersion: v1
kind: Service
metadata:
  name: wordpress-mysql
  labels:
    app: wordpress
spec:
  ports:
    - port: 3306
  selector:
    app: wordpress
    tier: mysql
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pv-claim
  labels:
    app: wordpress
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: wordpress-mysql
  labels:
    app: wordpress
spec:
  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
Details of mysql.yml

The file consists of 3 separate configs:

Service – maps MySQL’s port 3306 and makes it available for all containers with labels app:wordpress & tier:mysql

Persistent volume claim – declares claim on the volume that will be used in the MySQL container configuration

Deployment – declares the creation strategy and specs of our MySQL container:

  • it’s an image from the Docker Hub: mysql:5.6
  • it has app:wordpress & tier:frontend labels (used in Service)
  • it contains an environment variable called MYSQL_ROOT_PASSWORD which holds the value from our secret password
  • it has an open port 3306
  • it has a volume claim mounted in /var/lib/mysql
Create your MySQL instance on K8s

To create the database, run

kubectl apply -f mysql.yml

You can check the progress of deployment by running

kubectl get pods

Once you see status:Running, the MySQL service is ready for action.


Deploy WordPress to Kubernetes

Begin with downloading WordPress sources from https://wordpress.org/download/

Configure the Docker file

Now we need to dockerize the WordPress instance. The Docker file only requires WP sources:

FROM wordpress:php7.1-apache
COPY . /usr/src/wordpress/
Build & push the Docker image

The next step is building the Docker image and pushing it to your Docker registry:

docker login
docker build -t buddy/wordpress .
docker push buddy/wordpress
Create wordpress.yml

To deploy WordPress on a Kubernetes node you need to create a proper config file:

apiVersion: v1
kind: Service
metadata:
  name: wordpress
  labels:
    app: wordpress
spec:
  ports:
    - port: 80
      nodePort: 30000
  selector:
    app: wordpress
    tier: frontend
  type: NodePort
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: wp-pv-claim
  labels:
    app: wordpress
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: wordpress
  labels:
    app: wordpress
spec:
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: wordpress
        tier: frontend
    spec:
      containers:
      - image: buddy/wordpress:latest
        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
Details of wordpress.yml

The file consists of 3 separate configs:

Service – maps port 80 of the container to the node’s external IP:30000 for all containers with labels app:wordpress & tier:frontend

Persistent volume claim – declares claim on the volume that will be used in the WP container configuration

Deployment – declares the creation strategy and spec of our WordPress container:

  • it’s an image from the Docker Hub: buddy/wordpress:latest
  • it has app:wordpress & tier:frontend labels (used in Service)
  • it contains environment variables WORDPRESS_DB_HOST, which is the internal host name of the MySQL instance, and WORDPRESS_DB_PASSWORD, which holds the value from our secret password
  • it has an open port 80
  • it has a volume claim mounted in /var/www/html from which the WP sources are served
Create your WP instance on K8s

To deploy your WP instance, run

kubectl apply -f wordpress.yml

You can check the progress of deployment by running

kubectl get pods

Once you see status:Running, the WordPress service is ready for action.

TIP: Congratulations! You have successfully deployed your WordPress project to Kubernetes. You can visit the site by going to node IP:30000.

Advantages & Extenstions

Running WordPress and other web projects on Kubernetes gives you a series of benefits:

  • easy configuration in just a few files
  • you can recreate the whole configuration on any host with a couple of commands:

    kubectl apply -f volumes.yml
    kubectl apply secret generic mysql-pass --from-literal=password=ROOT_PASSWORD 
    kubectl apply -f mysql.yml
    kubectl apply -f wordpress.yml
    
  • you can extend the configuration by using volumes on AWS or other production ready volumes
  • you can change the external port mapping for proper load balancing
  • you can change the deployment strategy from Recreate to RollingUpdate to increase container counts and ensure no downtime during the deployment

Part 2: How to automate Kubernetes delivery with Buddy

In this part we’ll show you how to automatically apply configuration changes and update the image on your K8s cluster on every push to branch.

Set up a project with Buddy

INFO: For the purpose of this guide we’ll use a Git repository with a sample WordPress project and Kubernetes config files from Part 1 of this guide: https://github.com/buddy-works/wordpress-kubernetes.git

  1. Sign up to Buddy with your GitHub/Bitbucket account or email
  2. Create a new project, select your Git provider, and choose your WP project:

Delivery pipeline #1: Apply K8s deployment

The first pipeline will automatically apply configuration changes to your K8s volumes and WordPress instance on a push to branch:

  1. Click Add a new pipeline
  2. Set the trigger mode to ‘On every push’
  3. Select the branch that will trigger the execution
  4. Click Add a new pipeline when ready

Define the delivery actions

  1. Add Apply K8s deployment configuration action and configure the details:

    • enter the details to the server with your K8s cluster
    • select the volumes.yml config file from your repository
  2. Add two more actions for mysql.yml and wordpress.yml.

TIP: You can also add a notification that will let you know of finished deployments.

In the end, your pipeline should look like this:

Delivery pipeline #2: Build & Replace Docker image

The second pipeline will automatically update the image on your K8s cluster if you make any changes to your WordPress project:

  1. Click Add a new pipeline
  2. Set the trigger mode to ‘On every push’
  3. Select the branch that will trigger the execution
  4. Click Add a new pipeline when ready

Define the delivery actions

  1. Add Docker build action and configure the details:
    • select the Dockerfile from the repository
    • select the registry to which Buddy will push your image (eg. Docker Hub)
    • in the Tag field, use the parameter ${execution.to_revision.short_revision}

TIP: You can view the whole list of Buddy parameters here.

<figure><img src="https://buddy.works/guides/images/kubernetes-wordpress/kubernetes-wordpress-3.png" /><figcaption></figcaption></figure>
  1. Add Set image in K8s deployment action and configure the details:

    • enter the details to the server with your K8s cluster
    • select the container to update (wordpress)
    • in the Tag field, use the parameter ${execution.to_revision.short_revision}

TIP: You can add a build action that will eg. compile your assets before the deployment (Gulp/Grunt etc.).

This is what your pipeline should look like when you’re done (Gulp is optional):

Run the pipeline

With both pipelines in place, make a push to the assigned branch and watch Buddy perform all tasks for you:

Congratulations! Your WordPress project is now running on a Kubernetes cluster and your deployment is now fully automated. We salute you, developer!

WARNING: If you’d like to automate your deployment, let us know on the live-chat or drop a line support@buddy.works and we’ll create a delivery pipeline for your project for free!