Let's do something real this time. I started the blog pretty quickly while I am learning about Kubernetes, Containers and its relevant technologies.
In this article, we will take a look at how it’s done, what is the architecture behind it and what are the benefits of using Kubernetes to manage all this. Before all this, let’s see what are the things that I want to do.
What do I need?
I want to start a blog, hence I need are you blogging software. I need this to be simple yet convenient, cheap to setup, and mobile responsive.
Also, I want my audiences to be able to make comments. On the other hand, I am aware of all the spamming that may happen in the comments section. So I have to find a commenting Software that can prevent it. Thus something that requires need authentication and can allow moderation will be good. I also want to be able to know who had comment on my article so that I can respond to it.
All these need to be stable enough so that I don’t need to worry about it.
What have I chosen?
After carefully searching couple a couple of days, I have decided to use the following:
- Ghost - A very common open-sourced blogging platform, which is very simple to setup, flexible in customisation, have tons of integration options (including Slack to notify you when a post is published), multiple author support. It also provides hosting service. Since I am learning, I have decided to host my own using Kubernetes cluster.
- Schnack - A commenting platform that is highly recommended in various places like here and here in year 2020. It supports and requires login from Twitter, Google, Mastodon, Facebook, Github and has notification plugins that support Slack. Obviously setting up OAUTH login is very painful and requires verification, but it is worthwhile because it can help reduce spam a lot!
Ghost provides an official docker image while I have built a docker image for Schnack. There is no need to download any of the images, when you setup the Kubernetes yaml, they will be pulled automatically.
What roles does Kubernetes play?
Orchestration - Making sure that Ghost, Schnack are:
- broughtly up properly,
- periodically checked and ensured that it is up-and-running properly,
- provided with proper Persistent Storage to store all its necessary contents, and
Secured in the application level so that the software stack are:
- Secured through SSL enabled ingress, and
- have certificates renewed regularly.
Prerequisites and assumptions
- A Kubernetes Cluster setup - you can refer to my articles (part 1, part 2, part 3) for a properly setup Kubernetes Cluster
- Kubernetes cert-manager, ingress-nginx also setup. I have written another guide for this.
- GlusterFS client setup on all nodes that you want Ghost and schnack to run on.
- Your own domain registered with 2 entries of DNS registered (either A or CNAME doesn't matter). In the following example, we will use example.com and comments.example.com to host Ghost and Schnack respectively.
With all preparations done, let's take a look at the architecture
This is a very simple and typical web site deployment in Kubernetes, which consist fo the following components:
- The MetalLB handles load-balancing to the ingress-nginx. In L2 mode
- ingress-nginx is the reverse proxy and SSL termination point.
- cert-manager periodically renews SSL certificates for ingress-nginx and use it to conduct LetsEncrypt domain validation.
- Ghost and schnack are ran as another 2 pods.
- Glusterfs service glues Ghost and schnack to the GlusterFS distributed storage, which runs on bare metal.
Since Ghost behaves like a static website, as long as you configure ingress-nginx properly it can load-balance and cache the contents in a very efficient manner.
We will discuss about how to expand this architecture to enterprise level system in another article (which will come).
Let's see how the setup is done one-by-one. All examples could be found in my Github repository.
Glusterfs service setup
In order to allow the external GlusterFS service to work properly in Kubernetes, you will need to setup an endpoint for GlusterFS, which is illustrated in the below manifest:
apiVersion: v1 kind: Endpoints metadata: name: glusterfs-cluster # IP address must the glusterfs cluster subsets: - addresses: - ip: 192.168.xxx.yyy ports: - port: 1 - addresses: - ip: 192.168.xxx.zzz ports: - port: 1 - addresses: - ip: 192.168.xxx.aaa ports: - port: 1 --- apiVersion: v1 kind: Service metadata: name: glusterfs-cluster # Must be the same as the name of the Endpoints spec: ports: - port: 1
Normally you will have multiple endpoints for a GlusterFS cluster, hence put those into the IP addresses in the above yaml and apply it.
Storage for Ghost
We will configure Ghost to use GlusterFS using the following Persistent Volume and Persistent Volume Claims in the same YAML file to simply things a bit:
# This defines the PV and PVC together, to make the example more simple apiVersion: v1 kind: PersistentVolume metadata: name: pv-gl-ghost spec: capacity: storage: 1G accessModes: - ReadWriteMany # The following example use GlusterFS, you can also use NFS with different # configurations glusterfs: endpoints: glusterfs-cluster path: "/ghost" readOnly: false persistentVolumeReclaimPolicy: Retain --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: pvc-gl-ghost spec: accessModes: - ReadWriteMany storageClassName: "" volumeName: pv-gl-ghost resources: requests: storage: 1G
Ghost Deployment and Ghost Service
The ghost deployment and service can be deployed with the following YAMLs:
In the above Ghost deployment, we point the data storage for Ghost into the Persistent Volume Claim of pvc-gl-ghost. Set it to listen to port 2368 and setup proper monitoring on the service availability. I am using the official Ghost image and will always pull the latest image whenever the deployment is restarted. By doing so, I can upgrade rather easily to the latest version of Ghost.
The volume that is going to be mounted to the Ghost image will need to be write-able by the user specified in the securityContext (Under spec sesction).
Ingress for Ghost
In this example, we will host the ghost in the URL of https://example.com. We can use the following Ingress manifest:
Once the above is applied, it will setup ingress-nginx with the right redirection, and cert-manager will initiate a certificate request to LetsEncrypt automatically. You can refer to my article to check whether your certificate is issued and renewed accordingly.
If you setup everything accordingly and correctly, visit the URL that you have defined and the Ghost template website will be setup accordingly. You can start to add authors and post articles.
Similar to Ghost, we will need to setup Schnack. The image that I will be using is built by myself as I noticed that there is no suitable pre-built image for the software. Luckily Schnack provided a handy Dockerfile that I could modify and build upon.
I have forked Schnack into my own Github repository so that my changes to the Dockerfile are incorporated. Also want to work with him (her) to incorporate my changes as well but seems like he / she had been very busy.
Anyway, the Docker image is in the Docker repository, so you can take a look at the documentation. yourself. I will focus on the Kubernetes deployment and ingress setup in this article.
Persistent Storage for Schnack
My docker image requires 2 persistent volumes. One for configuration and the other one for the comments database. The relevant manifest are shown below:
Again, I use GlusterFS to define these volumes.
In the config volume, you will need 2 configuration files:
- schnack.json - This file stores the main configuration of the software. You can visit my Github repository for a example.
- plugins - This file contains a list of npm install commands to allow you to install the plugins for authentification and notification. If you use the allplugins tag when you pull the docker image, it will contain all supported plugins and this file can be left blank.
Deployment, Services and Ingress for Schnack
The relevant YAML are copied here, and could be found in my Github repository. I have put in relevant comments to make things easier. You can download them and modify them accordingly vit git.
Verify the installation
Once you have modified and applied all the manifest files, cert-manager will initiate a certificate request. Again you can verify them if needed. You can also visit the comments website URL to see if it works like below:
Making Ghost and Schnack working together
Finally, you will have your blog setup with a supplementary commenting section ready. Now all you need to do is to make them work together.
In Ghost, it is done by modification of the theme templates. In my example, I want all blog posts to have a comment session beneath it. Hence I modified the post.hbs in the themes directory of the Ghost persistent storage by:
sudo mount -t glusterfs glusterNode0:/ghost /mnt
Then, the file will be in /mnt/themes/<themename>/post.hbs. The modifications are like below:
Once you're done with the modification, don't forget to unmount the folder (/mnt) and restart the Ghost deployment by:
kubectl rollout restart deployment ghost
Verifying the integration
You can simply access your website, create a post and publish it. After publishing you will see a section below all post that will require you to login before posting comments.
You can mingle with the CSS so that it fits with your theme.
Wrapping it up
That's all! Once you have everything setup you can start blogging right away. In my website, I have enabled Twitter and Github login for the commenting section. These are the 2 simpliest OAUTH setup that you can get within a short period of time, and the user coverage is already quite wide. Given enough time, you can also enable Google OAUTH to allow your comments to reach out to further audiences. Feel free to leave a comment for any questions!
- https://www.ghost.org - Ghost
- https://schnack.cool - Schnack
- https://github.com/jasworks/kyaml - All sample YAML configurations used above.
- https://hub.docker.com/jasworks/schnack - Schnack docker images, it can run on both ARM64 and AMD64 platforms.
- https://jasworks.org/tags/kubernetes - All the guides for setting up a Kubernetes cluster, beginner stage with Google and Docker repositories.