April 5, 2026
Building a Kubernetes Home Lab with GitOps
From bare metal to production-grade self-hosted infrastructure
Why Kubernetes at Home?
I wanted to run real workloads at home - not just Docker Compose. Prometheus, Grafana, Pi-hole, home automation - these need orchestration, not just containers running ad-hoc.
So I built a 5-node kubeadm cluster on AlmaLinux with full GitOps. Everything deploys from Git. When I push to main, ArgoCD makes it happen. No manually running kubectl apply.
The Hardware
Current Cluster:
- 1 Master Node - 4 cores, 8GB RAM, 120GB SSD
- 4 Worker Nodes - Mix of 2-4 cores, 4-8GB RAM each
- Total - ~32GB RAM, 20+ vCPU across the cluster
- Network - 10.0.0.0/24 flat network
Architecture Overview
The cluster follows the GitOps pattern using ArgoCD and Helm.
- ArgoCD watches this Git repo and deploys automatically
- Helm charts define all applications
- cert-manager handles TLS with Cloudflare DNS-01
- MetalLB provides load balancing
- NGINX Ingress routes external traffic
- Prometheus + Grafana monitor everything
When I add a new app, I push a Helm chart and enable it in config. ArgoCD syncs automatically.
Step 1: Initialize the Master
Start with one node that will become the master. All nodes run AlmaLinux 10.0.
# Disable swap (REQUIRED for k8s) swapoff -a sed -i '/ swap / s/^/#/' /etc/fstab # Load kernel modules modprobe overlay modprobe br_netfilter # Configure sysctl cat <<EOF > /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-iptables = 1 net.bridge.bridge-nf-call-ip6tables = 1 net.ipv4.ip_forward = 1 EOF sysctl --system # Install containerd dnf install -y containerd.io mkdir -p /etc/containerd containerd config default > /etc/containerd/config.toml sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml systemctl enable --now containerd # Install k8s repo and components cat <<EOF > /etc/yum.repos.d/kubernetes.repo [kubernetes] name=Kubernetes baseurl=https://pkgs.k8s.io/core:/stable:/v1.33/rpm/ enabled=1 gpgcheck=1 gpgkey=https://pkgs.k8s.io/core:/stable:/v1.33/rpm/repodata/repomd.xml.key exclude=kubelet kubeadm kubectl cri-tools kubernetes-cni EOF dnf install -y kubelet kubeadm kubectl --disableexcludes=kubernetes systemctl enable --now kubelet
Step 2: Initialize Kubernetes
Initialize the cluster with kubeadm. This creates the control plane.
# Initialize (use your node IP) kubeadm init --pod-network-cidr=10.244.0.0/16 --service-cidr=10.96.0.0/12 # Set up kubeconfig for your user mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config # Install flannel (or calico, or weave) kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml
Wait for everything to be Ready. Run kubectl get nodes to verify.
Step 3: Join Worker Nodes
Generate a join token on the master. Run this on each worker:
# On master, generate token (valid 24h) kubeadm token create --print-join-command # On worker, run the output (looks like): kubeadm join 10.0.0.219:6443 --token xxxxxx --discovery-token-ca-cert-hash sha256:xxxxxx
After joining, approve the CSRs on master:
# Check and approve kubectl get csr kubectl approve <node-name>
Step 4: Install Infrastructure
Once nodes are ready, install the basics. I use a bootstrap script but here's the manual way:
- ArgoCD - The GitOps controller
- MetalLB - Load balancer for bare metal
- NGINX Ingress - HTTP routing
- cert-manager - TLS certificates
- local-path-provisioner - Storage (PVCs)
My cluster uses kubeadm on AlmaLinux 10.0 with Kubernetes v1.33.
Step 5: Set Up GitOps
Install ArgoCD and point it at your Git repo. The repo contains all Helm charts and configs.
# Install ArgoCD
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/v3.3.3/manifests/install.yaml
# Get the admin password
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
# Add your repo (in ArgoCD UI or CLI)
argocd repo add https://github.com/your-org/k8s-playground-cluster --username your-userThen create an Application in ArgoCD that watches your repo. When you push, ArgoCD syncs automatically.
Applications Running
- Prometheus + Grafana - Metrics and dashboards
- Loki - Log aggregation
- Pi-hole - Network-wide ad blocking
- Istio - Service mesh
- Gatekeeper - Policy enforcement
- Sealed Secrets - Encrypted secrets in Git
- SNMP Exporter - For router monitoring
How to Deploy a New App
With GitOps, adding a new app takes 3 steps:
- Create a Helm chart in
charts/ - Enable it in
cluster/dev/config.yaml - Push to main - ArgoCD deploys automatically
No kubectl apply needed. No manual steps. The repo is the source of truth.
Questions? Reach out!