← Back to Journey
Completed6/6 milestones

Building a single node cluster

Turning theory into practice by running a real Kubernetes cluster on a Raspberry Pi. This is where the abstractions became concrete: I installed k3s on bare hardware, containerised and shipped my own backend image, wired up a persistent database, deployed a full monitoring stack via Helm and exposed services to the outside world safely. Every milestone involved a real decision with a real consequence.

Duration: 1 month

"Breaking things on hardware you own is the fastest way to build real intuition."

Milestones

Progress100%
  • Installed k3s on an Ubuntu server running on a Raspberry Pi
  • Built and pushed a personal backend Docker image to Docker Hub
  • Ran the personal image in k3s alongside a persistent database
  • Deployed a monitoring stack via Helm and built Prometheus + Grafana dashboards
  • Exposed backend endpoints to accept traffic from outside the cluster
  • Exposed Grafana externally to view and configure dashboards remotely

Skills & Tools

k3skubectlDockerDocker HubHelmPrometheusGrafanaPersistent Volumes / PVCsKubernetes Networking / IngressUbuntu ServerRaspberry Pi
tool6
concept2
platform3

Challenges & Solutions

!

Deciding what to expose to the outside world without leaving the cluster wide open.

Applied the principle of least exposure: only the backend API and Grafana got external-facing ingress rules, everything else stayed cluster-internal. Used NodePort for now to keep it simple, but for the multi-node cluster I'll do it the right way. Meaning, more production-like with a proper Ingress controller and TLS termination, but this was good enough for the single-node homelab and let me get something working without getting bogged down in configuration details.

!

Getting the database to initialise with the right seed script and keep its data across crashes and pod restarts.

Mounted a PersistentVolumeClaim for the database data directory so the volume survives pod restarts and used a ConfigMap to inject the seed SQL as an init script. Verified by deliberately killing the pod and confirming the data and schema came back intact on restart.

!

Understanding why deploying Prometheus and Grafana felt completely different from running my own image and what was actually happening under the hood.

Working through this made the Helm abstraction click. A Helm chart doesn't just create pods; it provisions a whole namespace, CRDs, RBAC rules, ServiceMonitors and configuration in one go.

Resources