Blogging on Kubernetes

It has been a while since I last posted, but between college, work, and kids, I’ve been pretty busy. That said, I recently attended KubeCon 2019 and saw a lot of interesting presentations. As a fan of Rancher, I gravitated toward a lot of their talks. One that really caught my attention was Darren Shepherd’s talk on k3s. I really liked what I saw; it made setting up Kubernetes really easy, lightened the dependency load for small clusters, but still is very much the right amount of “batteries included” like most things made by Rancher.

I decided to move my home server (which runs, among other things, this blog) to k3s. Here, I’ll walk through how I did it — at least specifically for running a WordPress blog — just to demonstrate how easy it is. Fair warning though, there is a lot of YAML ahead!

The Basics

First, I’ll lay out my scenario (your mileage may vary).

  • OS: Ubuntu Linux 18.04 (LTS)
  • Blog Docker Image: wordpress:php7.2-apache
  • DB: MariaDB 10 (Basically MySQL) running on a dedicated host (outside of Docker)
  • Storage: HostPath-based (not using actual volumes) living under /usr/local/volumes on my server

This is to say that this is not a guide to running WordPress in an enterprise. This is just how I have my home server, which has been upgraded and carried along through numerous iterations of hosting my blog.

Note that all commands are run as root (which you can get to via sudo su -).

Installing K3S

Taken straight from the k3s GitHub repo:

Wait a bit and you’ll have a k3s service (à la systemd) up and running.

Note that if you’re paranoid like me and have decent firewall rules on your Linux box (mine acts as my home router/Internet gateway as well), then you’ll need to setup firewall rules to allow the Kubernetes networks outbound. I use ufw to manage iptables, but the rules more-or-less translate to:

Make sure these are persisted as they are what allow Pods to talk to things outside the Kubernetes network (including the Internet). I can’t find good documentation on the k3s site to back this up other than looking at the default values for k3s server --cluster-cidr and k3s server --service-cidr here.


I use Let’s Encrypt for securing my blog, so it was important to me to maintain this as I move to Kubernetes. Luckily, cert-manager exists and works with Kubernetes and Let’s Encrypt pretty easily. To add it, we need to install the controller and related resources:

That installs cert-manager, but now we need a ClusterIssuer that can provision certificates via Let’s Encrypt. Most guides will talk about using the staging API (which I highly recommend if this is your first time using Let’s Encrypt), but since I know this works already, I’m going to skip ahead to Prod.

Create a YAML file (I called mine certs-clusterissuer.yaml) at put something like this in there:

Be sure to replace “my.email@example.com” with your real email address! Also note that this wires up a ClusterIssuer kubernetes resource with Let’s Encrypt’s production API, but it won’t yet actually request any certificates. That’ll happen when we put the appropriate annotations on an Ingress resource later.

The kind: ClusterIssuer bit allows a single issuer to work for the entire cluster, rather than requiring an issuer per namespace. Given my use-case, this makes sense, but in an enterprise, it might make sense to break this up more.

Apply the YAML:

Blog Components


I avoid the default namespace whenever I can (using Kubernetes at work has drilled this into me), so let’s make a dedicated namespace for the blog:


Now for some REAL fun with YAML… let’s create the Deployment resource, which describes how to actually run our WordPress container. We’ll call this file blog-dep.yaml and put this content in there:

Much of the above is pretty arbitrary and are just patterns I found helpful. That said, pay very close attention to these things:

The above describes where on my host (meaning outside of Kubernetes) the document root and all variable data will be stored. This directory should already exist (for me, it is where my content was already stored previously). It gets mounted within the Pod/container at /var/www/html.

Hopefully, the above values are intuitive, but they almost certainly need to be changed. The DB hostname should be resolvable (or be changed to an IP) and the credentials should have appropriate permissions on the DB, which should also exist. You’re also able to use a container for your DB as well, but setting that up is beyond the scope of this post. Let me know if you get stuck.

Also, make note of the resource lines for CPU and memory. If your site is running slow and you have excess capacity on your server, you can bump this up.

Now we need to apply our configuration:

You can check on the status of your deployment via:

You should see something like:

You can get the logs for this via:


Kubernetes has a lot of layers of abstraction that make it very powerful and flexible but it also makes for a lot of configuration. Here, we’ll create the Service resource that exposes the ports used by the Deployment to the rest of the Kubernetes cluster. You can think of this as giving the blog Deployment an internal DNS name within Kubernetes that allows only specific ports to be accessed via that name.

Create a file called blog-svc.yaml and put this content in there:

The type here is ClusterIP, which only exposes the service within the Kubernetes cluster. Also, notice the selector rules; they are how the service finds its Pod(s).

Apply this configuration:


Now for our final piece of YAML: our Ingress resource. Note: when we deploy this resource, the cert-manager will try to provision TLS certificates via Let’s Encrypt. So before running these steps, be sure that you know what your blog’s DNS name is supposed to be and that you’ve already pointed it at your server! For me, this was already set up since I was moving from a docker-compose approach to Kubernetes. In any case, be sure your exact hostname is set correctly and resolvable externally before continuing.

The Ingress resource is kind of like an application load-balancer; it intelligently routes HTTP requests to upstream Pods in your cluster based on the hostname and/or URI. It can also do a few other handy things like automatic HTTP->HTTPS upgrading. We’ll make use of this feature here.

Create a file called blog-ingress.yaml and put this content in there:

There’s a lot to pay attention to there. Both locations that say blog.gnagy.info should be replaced with your blog’s hostname. Also, make note of the annotations used. Nothing should require changing, but it is worth understanding how this works to wire together our ClusterIssuer and this Ingress resource.

Apply this configuration:

In just a few minutes, you should have a WordPress installation running on k3s!

One thought on “Blogging on Kubernetes”

Leave a Reply