Single-node Kubernetes on Home Lab using MicroK8s, Metallb, and Traefik

MicroK8s: High availability, Low-ops, Minimal Kubernetes for All-Size Clusters

TL;DR

In this blog, I will try another tool called MicroK8s which is around for sometime and hopefully will be more stable than k0s to setup a single-node Kubernetes cluster on Ubuntu Linux 20.04 on my home lab box.

Prerequisites

  • A public IP address from your internet provider, either dynamic or static.
  • A domain name mapped to your static IP or a dynamic DNS domain name for dynamic IP which can be configured on your modem router to sync with the Dynamic DNS provider e.g. no-ip.
  • You have a fresh install of Ubuntu 20.04 on your home lab server — see this blog for how-to.
  • SSH has been configured for remote access on your home lab server— see my previous blogs on how to setup on home lab or Linode VM.
  • kubectl, git, and helm are installed on your local machine

Setup MicroK8s

In this section, we will install MicroK8s on our Ubuntu server.

Install MicroK8s

On your server, use snap to install the MicroK8s package.

sudo snap install microk8s --classic --channel=1.21
sudo usermod -a -G microk8s $USER
sudo chown -f -R $USER ~/.kube
su - $USER
microk8s status --wait-ready
microk8s kubectl get nodes
microk8s kubectl get services
microk8s enable dns storage

Remote Access

To enable remote access to the api-server using kubectl, edit the file /var/snap/microk8s/current/certs/csr.conf.template on your server and add domain name and/or IP address (if static) of your server under alt_names section that reachable from the internet.

[ alt_names ]
DNS.1 = kubernetes
DNS.2 = kubernetes.default
DNS.3 = kubernetes.default.svc
DNS.4 = kubernetes.default.svc.cluster
DNS.5 = kubernetes.default.svc.cluster.local
DNS.6 = your.dnsname.com
IP.1 = 127.0.0.1
IP.2 = 10.152.183.1
IP.3 = 192.168.1.xx
IP.4 = 123.456.789.0
microk8s config > admin.config
scp username@your.dnsname.com:~/admin.config .
export KUBECONFIG=admin.config
kubectl version
kubectl get nodes
kubectl commands — screen captured from Windows Terminal by the author

Deploy Application

In this section, we will deploy an application named whoami for testing purpose.

Install whoami

First, clone this repository and apply deployment and service on the cluster.

git clone https://github.com/pacroy/whoami.git
cd whoami
kubectl create ns whoami
kubectl apply -f whoami.yml -n whoami
kubectl port-forward service/whoami 8080:80 -n whoami
whoami via port-forward — screen captured from Microsoft Edge by the author

Expose Service

In this section, we will expose whoami service to the outside world using metallb load balancer and traefik ingress controller.

Enable meltallb

To expose a service with LoadBalancer, we need to enable metallb which a load balancer for bare metal.

microk8s enable metallb
Enabling MetalLB
Enter each IP address range delimited by comma (e.g. ‘10.64.140.43–10.64.140.49,192.168.0.105–192.168.0.111’): 192.168.1.85–192.168.1.89
apply -f service-lb.yml -n whoami
kubectl apply -f whoami.yml -n whoami

Install Traefik Ingress

On your server, enable traefik ingress controller for external access.

helm repo add traefik https://helm.traefik.io/traefik
helm repo update
kubectl create namespace traefik
helm install traefik traefik/traefik -n traefik
kubectl apply -f ingress.yml -n whoami
whoami via ingress — screen captured from Microsoft Edge by the author

traefik Dashboard

You can access traefik dashboard by forwarding port 9000 from a traefik pod.

kubectl port-forward $(kubectl get pods --selector "app.kubernetes.io/name=traefik" --output=name -n traefik) -n traefik 9000:9000
traefik dashboard — screen captured from Microsoft Edge by the author

Configure HTTPs

In this section, we will enable HTTPS by setup a mechanism to automatically generate SSL certificate for our application using ACME provider from Let’s Encrypt authority (It’s free!).

Introduction

Now, if you try to access https://your.dnsname.com/whoami then you will get this warning page.

Invalid certificate — screen captured from Microsoft Edge by the author
traefik self-signed certificate — screen captured by the author
kubectl delete ingress/whoami -n whoami

IngressRoute

Instead of using standard Ingress object with lots of annotations, traefik also provides their own CRD called IngressRoute that make the configuration more readable and structured.

kubectl apply -f ingressroute.yml -n whoami

Certificate Resolver

Next, we need to upgrade the traefik to include a certificate resolver. Edit the file values.yml and update youremail@domain.com with your email address. This will be used by Let’s Encrypt to send notification email when the certificate nearly expires.

helm upgrade traefik traefik/traefik -n traefik --values values.yml
helm get manifest traefik -n traefik
kubectl logs $(kubectl get pod -n traefik -o name) -n traefik -f

IngressRoute with TLS

Now, let’s apply a new IngressRoute that using the certificate resolver. Don’t forget to update the hostname to yours!

kubectl apply ingressroute-tls.yml -n whoami
kubectl exec -it $(kubectl get pod -n traefik -o name) -n traefik -- cat /data/letsencrypt.json
whoami with valid certificate — screen captured from Microsoft Edge by the author
valid certificate issued by Let’s Encrypt — screen captured by the author

Security

This section will show you how to enhance security for our application.

TLS version 1.2

HTTPS should no longer support SSL and TLS v1.1 and TLS v1.2 as they are weak in term of security. If we scan our endpoint with SSLLabs, you will get rating at B.

Rate B HTTPS — screen captured from SSLLabs by the author
kubectl apply -f tlsoption.yml
Rate A HTTPS — screen captured from SSLLabs by the author

Redirect to HTTPS

So far, our whoami application serves HTTP traffic at port 80 and HTTPS traffic at port 443. What if we want to redirect all HTTP traffics to HTTPS. We need to leverage RedirectScheme middleware.

kubectl apply -f middleware-https.yml
kubectl apply -f ingressroute-http.yml -n whoami
$ curl http://microk8s.ddns.net/whoami -D-
HTTP/1.1 301 Moved Permanently
Location: https://microk8s.ddns.net/whoami
Date: Mon, 12 Apr 2021 14:14:36 GMT
Content-Length: 17
Content-Type: text/plain; charset=utf-8
Moved Permanently