WordPress in Kubernetes: The Perfect Setup

By Jorge Salamero Sanz - MAY 16, 2017

SHARE:

Wordpress Kubernetes Perfect Setup

This tutorial shows how to prepare and deploy WordPress with all required dependencies (MySQL, etc) in Kubernetes.

Why WordPress? WordPress is usually chosen as the de facto application when explaining how to handle a process with a server software stack.

One of the challenges Kubernetes users face is deploying and re-deploying the same components required by their applications: databases like MySQL or MariaDB, MongoDB, Redis, Memcached, Elasticsearch; frontend servers like Nginx; or just a load balancer with HAproxy, to name a few examples.

If you have a CI/CD workflow in place, you probably have Jenkins or any other similar software deploying to Kubernetes via kubectl: Services, Deployments, ConfigMaps, Ingress controller and maybe even persistent storage. But if you are looking for something easier and more simple, there is a Kubernetes package manager that can help you: Helm.

Helm package manager and Kubernetes Charts

Helm is a Kubernetes package manager that allows you to package an application and handle all the required dependencies, including other services, and the configuration. The packages are called Charts. The idea is that instead of running kubectl to create the different deployments, services, etc. all the resources are defined in manifest templates that Helm installs as an atomic operation. Think of dpkg or yum, cpan or pip, but for Kubernetes apps.

Kubernetes Charts is the official repository that offers a central reference location for already packaged applications; at this time 60 apps are available in the stable branch.

Installing Helm in OSX or Linux

As a prerequisite, you will need kubectl authenticated and working against your Kubernetes instance in your cloud provider or you can use Minikube for testing in your local laptop.

On OSX, we recommend using Homebrew to install Helm:

% brew install kubernetes-helm

On Linux, you can download the latest release and unpack it:

% wget https://kubernetes-helm.storage.googleapis.com/helm-v2.2.0-linux-amd64.tar.gz
% tar xvzf helm-v2.2.0-linux-amd64.tar.gz
% sudo mv linux-amd64/helm /usr/local/bin/helm
Code language: JavaScript (javascript)

Init Helm in your Kubernetes cluster

Before moving along, Helm needs to be installed in your Kubernetes cluster as well. This is a very straightforward process and you just need to init Helm:

% helm init
$HELM_HOME has been configured at /home/bencer/.helm.


Tiller (the helm server side component) has been installed into your Kubernetes Cluster.
Happy Helming!
Code language: PHP (php)

This will create a containerized service in Kubernetes known as Tiller. From this point on, the Helm package manager installed in your laptop will communicate with Tiller running in Kubernetes via gRPC, and Tiller will be in charge of deploying, upgrading and deleting the apps in your cluster:

% kubectl get pods --all-namespaces
NAMESPACE     NAME                             READY     STATUS    RESTARTS   AGE
kube-system   kube-addon-manager-minikube      1/1       Running   0          3m
kube-system   kube-dns-v20-qzkhp               3/3       Running   0          2m
kube-system   kubernetes-dashboard-mtrl3       1/1       Running   0          2m
kube-system   tiller-deploy-2923173008-n21pw   1/1       Running   0          18s
Code language: JavaScript (javascript)

If you want to update the Chats database, like apt update, simply:

% helm repo update

And if you want to upgrade Tiller:

% helm init --upgrade

WordPress Deployment in Kubernetes

With Helm configured and Tiller up and running you can start deploying your favorite apps. For instance, let’s search for WordPress Charts:

% helm search wordpress
NAME                VERSION DESCRIPTION                                       
stable/wordpress    0.4.2   Web publishing platform for building blogs and ...

And you can get more information about this Chart in a similar fashion to apt-cache:

% helm inspect stable/wordpress
description: Web publishing platform for building blogs and websites.
engine: gotpl
home: http://www.wordpress.com/
icon: https://bitnami.com/assets/stacks/wordpress/img/wordpress-stack-220x234.png
keywords:
- wordpress
- cms
- blog
- http
- web
- application
- php
maintainers:
- email: [email protected]
  name: Bitnami
name: wordpress
sources:
- https://github.com/bitnami/bitnami-docker-wordpress
version: 0.4.2

---
## Bitnami WordPress image version
## ref: https://hub.docker.com/r/bitnami/wordpress/tags/
##
image: bitnami/wordpress:4.7-r0
[...]
Code language: PHP (php)

Since we want our WordPress running in its own namespace, let’s create one as we install the application:

% helm install --namespace wordpress --name wordpress stable/wordpress                                   

NAME:   wordpress
LAST DEPLOYED: Mon Mar  6 17:38:30 2017
NAMESPACE: wordpress
STATUS: DEPLOYED

RESOURCES:
==> v1/Service
NAME                 CLUSTER-IP      EXTERNAL-IP  PORT(S)                     AGE
wordpress-wordpress  10.109.108.55   <pending>    80:32435/TCP,443:30044/TCP  2s
wordpress-mariadb    10.102.199.160  <none>       3306/TCP                    1s

==> extensions/v1beta1/Deployment
NAME                 DESIRED  CURRENT  UP-TO-DATE  AVAILABLE  AGE
wordpress-mariadb    1        1        1           0          1s
wordpress-wordpress  1        1        1           0          1s

==> v1/Secret
NAME                 TYPE    DATA  AGE
wordpress-wordpress  Opaque  2     2s
wordpress-mariadb    Opaque  2     2s

==> v1/ConfigMap
NAME               DATA  AGE
wordpress-mariadb  1     2s

==> v1/PersistentVolumeClaim
NAME                           STATUS  VOLUME                                    CAPACITY  ACCESSMODES  AGE
wordpress-wordpress-apache     Bound   pvc-551b2739-028b-11e7-ad79-12182a6edca4  1Gi       RWO          2s
wordpress-wordpress-wordpress  Bound   pvc-551b9867-028b-11e7-ad79-12182a6edca4  8Gi       RWO          2s
wordpress-mariadb              Bound   pvc-551c0c25-028b-11e7-ad79-12182a6edca4  8Gi       RWO          2s


NOTES:
1. Get the WordPress URL:

  NOTE: It may take a few minutes for the LoadBalancer IP to be available.
        Watch the status with: 'kubectl get svc --namespace wordpress -w wordpress-wordpress'

  export SERVICE_IP=$(kubectl get svc --namespace wordpress     wordpress-wordpress -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
  echo http://$SERVICE_IP/admin

2. Login with the following credentials to see your blog

  echo Username: user
  echo Password: $(kubectl get secret --namespace wordpress wordpress-wordpress -o jsonpath="{.data.wordpress-password}" | base64 --decode)
</none></pending>
Code language: HTML, XML (xml)

You can find all the available configuration options here, and you can set these either using the command line --set or in a YAML file. Also, all Charts output some instructions on how to proceed after the package is installed. In this case, you should see how to get the WordPress Ingress controller URL with:

% kubectl get svc --namespace wordpress wordpress-wordpress -o jsonpath='{.status.loadBalancer.ingress[0].hostname}'

Note: using .status.loadBalancer.ingress[0].ip didn’t work for me as expected an IP address and I had a hostname instead, but you can always inspect the wordpress service with kubectl to get full details:

% kubectl describe svc wordpress-wordpress --namespace wordpress        
Name:           wordpress-wordpress
Namespace:      wordpress
Labels:             app=wordpress-wordpress
            chart=wordpress-0.4.2
            heritage=Tiller
            release=wordpress
Selector:       app=wordpress-wordpress
Type:           LoadBalancer
IP:         10.109.108.55
LoadBalancer Ingress:   a55201964028b11e7ad7912182a6edca-1068550576.us-east-1.elb.amazonaws.com
Port:           http    80/TCP
NodePort:       http    32435/TCP
Endpoints:      192.168.224.67:80
Port:           https   443/TCP
NodePort:       https   30044/TCP
Endpoints:      192.168.224.67:443
Session Affinity:   None
Events:
  FirstSeen LastSeen    Count   From            SubObjectPath   Type        Reason          Message
  --------- --------    -----   ----            -------------   --------    ------          -------
  9m        9m      1   {service-controller }           Normal      CreatingLoadBalancer    Creating load balancer
  9m        9m      1   {service-controller }           Normal      CreatedLoadBalancer Created load balancer

So just head to: https://a55201964028b11e7ad7912182a6edca-1068550576.us-east-1.elb.amazonaws.com and you will be able to access your new WordPress blog.

You can also check the administrator user credentials that are stored in a Kubernetes secret:

% kubectl get secret --namespace wordpress wordpress-wordpress -o jsonpath="{.data.wordpress-password}" | base64 --decode

And if you want to see this information at any point, you can use helm status wordpress to show it again.

Helm can install and handle multiple apps, and can list the different apps installed:

% helm ls
NAME        REVISION    UPDATED                     STATUS      CHART           NAMESPACE  
sysdig      1           Mon Mar  6 12:40:22 2017    DEPLOYED    sysdig-0.2.0    default    
wordpress   1           Mon Mar  6 12:48:11 2017    DEPLOYED    wordpress-0.4.2 wordpress
Code language: CSS (css)

And you can also delete them once you have finished with helm delete.

Monitoring WordPress in Kubernetes

Along with your app stack, monitoring with telemetry and performance metrics for troubleshooting, dashboards and alerts is a must. Sysdig Monitor is probably your best bet for doing all this with one tool in Kubernetes and in less than 5 minutes!

Sysdig Monitor agent has always been very easy to install, either running the plain Docker command or deploying it using a DaemonSet, but now Sysdig can also be deployed with Helm since it’s available in the official Kubernetes Charts repository.

You just need to run the following command, including the AccessKey, which you will find in your Sysdig Monitor user account settings.

% helm install --namespace sysdig --set sysdig.AccessKey="YOUR-ACCESS-KEY",sysdig.AgentTags="cluster:kubernetes-dev" stable/sysdig
NAME:   needled-quoll
LAST DEPLOYED: Mon Mar  6 16:02:49 2017
NAMESPACE: sysdig
STATUS: DEPLOYED

RESOURCES:
==> v1/Secret
NAME                  TYPE    DATA  AGE
needled-quoll-sysdig  Opaque  2     1s

==> extensions/v1beta1/DaemonSet
NAME                  DESIRED  CURRENT  READY  NODE-SELECTOR  AGE
needled-quoll-sysdig  3        3        0      <none>         1s

NOTES:
Sysdig Monitor agents are spinning up on each node in your cluster. After a few seconds, you should see your hosts appearing in the Explore tab:

    https://app.sysdigcloud.com/#/explore/overview/l:10

No further action should be required.
</none>
Code language: HTML, XML (xml)

That’s it.

Now you can list both Charts running:

% helm list                              
NAME            REVISION    UPDATED                     STATUS      CHART           NAMESPACE  
needled-quoll   1           Mon Mar  6 16:02:49 2017    DEPLOYED    sysdig-0.2.0    sysdig     
wordpress       1           Mon Mar  6 15:28:10 2017    DEPLOYED    wordpress-0.4.2 mywordpress
Code language: CSS (css)

To start monitoring your Kubernetes deployment, go to Sysdig Monitor and from there you can visualize your deployment topology, configure dashboards and set up alerts. Through the Explore tab you can browse your infrastructure. Not only can you see hosts and containers running on them, you can also group containers using Kubernetes logic: cluster > namespaces > deployments or services > pods and containers.

Wordpress Kubernetes Monitor Dashboard

Thanks to Sysdig’s ability to autodiscover the services running in your containers you will automatically get views of your WordPress containers, including application-layer metrics such as: HTTP requests and HTTP error count per second, average and max response time for each microservice, and also which are the top requested URLs or which are the slowest ones!

Wordpress Kubernetes Response Time

Recommended alerts for WordPress in Kubernetes

Monitoring any service running in Kubernetes is a little more tricky that monitoring the same service in a bare metal static infrastructure. Now you have to monitor not only the host and the services but also the containers and the orchestration platform. There is no rule that fits all scenarios, but we are going to throw out a few suggestions here of what should probably be in your alerts list.

Host-level alerts

Is any of your hosts down? If its a minion it’s probably not too bad because Kubernetes will reschedule the containers somewhere else. If it’s your master and you only have one you will probably want to know ASAP.

You might want to add some other host-level resource consumption alerts like disk usage over 80%, if you have been swapping for a few minutes and the load is way above normal. But remember, it’s not worth waking you up if there isn’t anything broken.

Kubernetes alerts

This is the new layer and basically you want to make sure the resources defined by Kubernetes are running. For our WordPress example, I’m pretty sure that everyone would like to know if there are no containers running for a given service, which should never happen!

kubernetes.replicaSet.replicas.running < 1
</code>
Wordpress Kubernetes Alert

But also, you will want to know if the number of container running is lower that the number of replicas you wanted. This can be triggered with the following condition:

kubernetes.replicaSet.replicas.running < kubernetes.replicaSet.replicas.desired
</code>

This should be applied to both the wordpress and mysql service.

Just making sure the containers are alive is not enough; you need to make sure they are not being continuously restarted because the process running inside is crashing. This is known as CrashLoopBackOff, and you can receive an alert when this happens using the restart count metric or an alert on the event:

Wordpress Kubernetes Alert Event

We will apply this alert across everything in your cluster, making it trigger for each pod that matches this condition: kubernetes.pod.restart.count > 4 over the last 2 minutes.

Service level alerts

You still need to make sure that your services are running: that the WordPress webserver is responding to HTTP requests properly and queries are going through the MySQL database. Defining alerts at this level depends heavily on your traffic patterns. If you have a regular, sustained number of visits it is easy to set a minimum threshold of HTTP requests or MySQL queries, but if your traffic is random these kind of alerts will trigger many false positives.

In general, alerting should be configured using your working metrics (those that are a clear indicator that your app is working), triggering notifications to show that something has stopped working. Still, in most cases, you should set up a few alerts based on infrastructure availability or resources that always need to be there. If you want to learn more about Kubernetes alerting, don’t miss our Monitoring Kubernetes (part 2): Best practices for alerting on Kubernetes.

Next steps

We think Helm is great for quickly and easily deploying the services you need for running your app in Kubernetes. Now you can also deploy the Sysdig Monitor agent with Helm too. If you want to close the circle you can create your own Chart package for your app and host it in your private repository, with everything still handled by Helm.

If you are looking at an even more user-friendly way to expose Helm to your Kubernetes users, check out Monocular, a Helm UI that you can also self-host in your Kubernetes.

Subscribe and get the latest updates