This is the second post in a series on Modernizing my Personal Web Projects. In this post, I attempt to create a budget Kubernetes hosting setup on DigitalOcean. The goal is to provide everything I need to host my blogs and side-projects for under $50 USD. Let’s go!

First Things First: Creating the Kubernetes Cluster

The core part of this setup will be a managed Kubernetes cluster. I decided to use Kubernetes for its scalability and ease of deployment. By packaging my WordPress blogs and everything I want to run as containers, I can deploy them on Kubernetes in the same consistent way and let the cluster decide how to run them. If I want to run the same containers locally, or in a testing environment, it’ll be easily portable without having to manually install them on different servers. And more importantly, Kubernetes will ensure my apps are always running, even if the underlying server nodes have problems. That’s a load off my mind that I’ll never have to worry about.

While it’s possible to create the Kubernetes cluster myself, I decided a managed solution is the superior choice. This way, all updates and patches are handled automatically so I won’t have to maintain Kubernetes or the underlying servers. Furthermore, on DigitalOcean, the best part is there’s no extra cost for this service – you only pay for the resources you use! That’s in line with my goal for a budget Kubernetes hosting setup.

I used the DigitalOcean portal (with my existing account) to create a managed Kubernetes cluster with the following details:

  • Kubernetes version: (default)
  • Region: Singapore
  • Node plan: $20/month (2.5GB usable RAM, 2 vCPUs)
  • Number of nodes: 2
  • Total cost: $40/month

Cost of the Cluster

The minimum node plan recommended for production use costs $20/month. The cheapest node is $10, but actually offers worse value since it only has 1GB usable RAM. With two smaller nodes I’d only get 2GB usable, 500MB lower than the $20 nodes. 2 nodes offers enough capacity within my budget. If I need more in future, I can easily add more nodes to the cluster. I chose to set autoscaling from the control panel, but note that you will be charged for the additional nodes if the cluster scales up.

The initial cluster comes in at $40/month

Configuring the new Kubernetes Cluster

I configured a few extra settings from the ‘Settings’ tab after creating the cluster:

  • Automatically upgrade minor version patches: Enable
  • Upgrade window: Set to any day after 3am (SGT)
  • Surge Upgrades: Enabled

Next, I took advantage of the 1-click apps available and installed the Kubernetes Monitoring Stack from the DigitalOcean marketplace. This includes standard tools used for monitoring apps such as Prometheus, Grafana and metrics-server. I also considered using Pixie from NewRelic, however this was a bit resource-hungry for my liking. I’ll discuss how to set up Grafana in a later post. I wouldn’t recommend trying to save resources by avoiding monitoring completely; monitoring was one of my original requirements and this will allow me to monitor everything in one place.

Now the cluster should be ready to use!

Connecting to the Kubernetes Cluster

To connect to the new cluster I followed the official guide. The steps are:

  1. (Prerequisites) Install doctl and kubectl.
  2. Set credentials for doctl using doctl auth init.
  3. Run to generate the cluster configuration:
    doctl kubernetes cluster kubeconfig save use_your_cluster_name
  4. Test the configuration with:
    kubectl get nodes
  5. At this point I recommend aliasing kubectl to the single-letter ‘k’ to save typing for future commands.

Creating Other Essential Resources

There are two other services that I would consider essential, even for a budget Kubernetes hosting setup. They are:

  • A Docker registry
  • Object storage

For these I’ll be using the DigitalOcean Container Registry and Spaces respectively. Let me justify this decision:

A container registry is a must-have to deploy images onto Kubernetes. It’s possible to host our own, but this is problematic for two reasons. Firstly, the software is quite tricky to set up. Secondly, we’d need to host it somewhere. Hosting on the Kubernetes cluster might seem tempting but it would create a circular dependency – if there was an issue with the registry we wouldn’t be able to deploy anything! DigitalOcean’s Container Registry has the advantage of automatic integration with our Kubernetes cluster and the doctl command, which saves a lot of effort. It’s just 1 click to enable access from Kubernetes via the control panel.

DigitalOcean Spaces is object storage, similar to Amazon’s AWS S3. S3 is the quintessential cloud service that started the cloud revolution. Spaces is API-compatible with S3 for this reason. It’s equally great for serving content as storing backups, and I use it a lot. There is a specific reason it’s essential for Kubernetes though. Kubernetes pods use ephemeral storage, meaning it’s deleted when the pod is deleted. This is why it’s a best practice for apps designed for the cloud to be stateless. Therefore offloading as much storage as possible to the cloud is a good idea, to keep the individual pods stateless and allow them to horizontally scale while sharing the same storage.

Wrapping Up

I decided to go for the ‘Basic’ plan for the Container Registry, which gives 5 repositories and a maximum of 5GiB storage. There is a free plan if you only need a single repository, but I’m definitely going to use more than that.

For Spaces, the base subscription includes 250 GiB storage, which is enough to meet my needs for quite some time. It’s unfortunate that this space can’t be combined with the Container Registry to save cost, but never mind.

With these two extra services, this is the final cloud bill per month:

  • Kubernetes: $20/node * 2 = $40
  • Container Registry: $5 for the Basic plan
  • Spaces: $5 base subscription
  • Total: $50/month

Just right! All the essentials are covered with the exact budget of $50/month. I believe this offers the best value for a budget Kubernetes hosting setup. To save cost, I don’t plan on using any load balancers, and I’ll explain how to do this in the following posts. I’d also consider adding Managed Databases, depending on the apps being hosted.