Bikin Kubernetes Cluster di KVM - From Zero to Hero! π
Kubernetes Lab on KVM WSL Journey
Part 2 of 5
Tutorial step-by-step deploy Kubernetes cluster production-ready di homelab KVM. Dari setup VM sampai deploy aplikasi pertama!
Prerequisites: Pastikan sudah setup KVM di WSL2 dari tutorial sebelumnya. Kita bakal build on top of that setup!
Setelah punya homelab KVM yang solid, saatnya naik level ke container orchestration! Di tutorial ini, kita bakal setup production-ready Kubernetes cluster dengan:
- 1 Master Node (Control Plane)
- 2 Worker Nodes
- Calico CNI untuk networking
- Containerd sebagai container runtime
Letβs dive in! πͺ
π― Architecture Overview
βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ
β k8s-master β β k8s-worker-1 β β k8s-worker-2 β
β 192.168.122.11 β β 192.168.122.21 β β 192.168.122.22 β
β β β β β β
β β’ API Server β β β’ Kubelet β β β’ Kubelet β
β β’ etcd β β β’ Kube-proxy β β β’ Kube-proxy β
β β’ Scheduler β β β’ Containerd β β β’ Containerd β
β β’ Controller β β β β β
βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββSpecs per VM:
- Master: 1 vCPU, 2GB RAM, 20GB Storage
- Workers: 1 vCPU, 2GB RAM, 20GB Storage
ποΈ Step 1: Create VMs dengan Terraform
Mari kita automate VM creation pakai Terraform! Create file k8s-cluster.tf:
terraform {
required_providers {
libvirt = {
source = "dmacvicar/libvirt"
}
}
}
provider "libvirt" {
uri = "qemu:///system"
}
# Ubuntu 22.04 Base Image
resource "libvirt_volume" "ubuntu_base" {
name = "ubuntu-22.04-server-cloudimg-amd64.img"
pool = "isos"
source = "https://cloud-images.ubuntu.com/releases/22.04/release/ubuntu-22.04-server-cloudimg-amd64.img"
format = "qcow2"
}
# Master Node
resource "libvirt_volume" "k8s_master" {
name = "k8s-master.qcow2"
pool = "vms"
base_volume_id = libvirt_volume.ubuntu_base.id
size = 21474836480 # 20GB
}
resource "libvirt_domain" "k8s_master" {
name = "k8s-master"
memory = "2048"
vcpu = 1
network_interface {
network_name = "net-lab"
addresses = ["192.168.100.11"]
hostname = "k8s-master"
}
disk {
volume_id = libvirt_volume.k8s_master.id
}
console {
type = "pty"
target_port = "0"
target_type = "serial"
}
graphics {
type = "spice"
listen_type = "address"
autoport = true
}
}
# Worker Nodes
resource "libvirt_volume" "k8s_worker" {
count = 2
name = "k8s-worker-${count.index + 1}.qcow2"
pool = "vms"
base_volume_id = libvirt_volume.ubuntu_base.id
size = 21474836480 # 20GB
}
resource "libvirt_domain" "k8s_worker" {
count = 2
name = "k8s-worker-${count.index + 1}"
memory = "2048"
vcpu = 1
network_interface {
network_name = "net-lab"
addresses = ["192.168.100.${21 + count.index}"]
hostname = "k8s-worker-${count.index + 1}"
}
disk {
volume_id = libvirt_volume.k8s_worker[count.index].id
}
console {
type = "pty"
target_port = "0"
target_type = "serial"
}
graphics {
type = "spice"
listen_type = "address"
autoport = true
}
}Deploy VMs:
terraform init
terraform plan
terraform apply -auto-approveπ§ Step 2: Initial VM Setup (Semua Node)
Login ke setiap VM dan jalankan commands berikut. Bisa pakai script atau manual satu-satu:
Update System & Install Prerequisites
# Update system
sudo apt-get update -y && sudo apt upgrade -y --with-new-pkgs
# Install required packages
sudo apt-get install -y \
apt-transport-https \
ca-certificates \
curl \
gpg \
software-properties-common \
nano \
htop \
net-toolsConfigure Hosts File
# Edit hosts file untuk semua nodes
sudo nano /etc/hosts
# Tambahkan entries berikut:
192.168.100.11 k8s-master
192.168.100.21 k8s-worker-1
192.168.100.22 k8s-worker-2Set Timezone
sudo timedatectl set-timezone Asia/JakartaDisable Swap (Critical!)
# Disable swap immediately
sudo swapoff -a
# Disable swap permanently
sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
# Verify swap is disabled
free -hπ Step 3: Configure Kernel Modules & Networking
Load Required Kernel Modules
# Load modules immediately
sudo modprobe overlay
sudo modprobe br_netfilter
# Make modules persistent across reboots
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOFConfigure Kernel Parameters
# Setup networking parameters for Kubernetes
cat <<EOF | sudo tee /etc/sysctl.d/99-k8s-sysctl.conf
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-arptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.conf.all.rp_filter = 1
EOF
# Apply settings
sudo sysctl --system
# Verify settings
sudo sysctl net.bridge.bridge-nf-call-iptablesπ¦ Step 4: Install Container Runtime (Containerd)
Add Docker Repository
# Create keyrings directory (for Ubuntu < 22.04)
sudo install -m 0755 -d /etc/apt/keyrings
# Add Docker GPG key
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
# Add Docker repository
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/nullInstall & Configure Containerd
# Update package list and install containerd
sudo apt-get update
sudo apt-get install -y containerd.io
# Generate default configuration
sudo containerd config default | sudo tee /etc/containerd/config.toml
# Configure systemd cgroup driver (IMPORTANT!)
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
# Restart and enable containerd
sudo systemctl restart containerd
sudo systemctl enable containerd
# Verify containerd is running
sudo systemctl status containerdPro tip: Kalau mau manual edit config, cari section [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options] dan set SystemdCgroup = true.
βΈοΈ Step 5: Install Kubernetes Components
Add Kubernetes Repository
# Create keyrings directory (if not exists)
sudo mkdir -p -m 755 /etc/apt/keyrings
# Add Kubernetes GPG key
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.32/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
# Add Kubernetes repository
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.32/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.listInstall Kubernetes Tools
# Update package list
sudo apt-get update
# Install kubelet, kubeadm, kubectl
sudo apt-get install -y kubelet kubeadm kubectl
# Hold packages to prevent automatic updates
sudo apt-mark hold kubelet kubeadm kubectl
# Enable kubelet service
sudo systemctl enable kubelet
# Verify installation
kubeadm version
kubectl version --clientποΈ Step 6: Initialize Master Node
β οΈ HANYA di Master Node (k8s-master):
Initialize Cluster
# Initialize Kubernetes cluster
sudo kubeadm init \
--apiserver-advertise-address=192.168.100.11 \
--pod-network-cidr=192.168.0.0/16 \
--node-name=k8s-master
# Setup kubectl for regular user
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
# Verify cluster status
kubectl cluster-info
kubectl get nodesImportant: Save the kubeadm join command yang muncul setelah init! Format:
kubeadm join 192.168.100.11:6443 --token <token> --discovery-token-ca-cert-hash sha256:<hash>πΈοΈ Step 7: Install CNI Plugin (Calico)
Masih di Master Node:
Install Calico
# Download and apply Calico manifest
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.29.2/manifests/tigera-operator.yaml
# Download custom resources
curl -L https://raw.githubusercontent.com/projectcalico/calico/v3.29.2/manifests/custom-resources.yaml -o calico-custom-resources.yaml
# Apply custom resources
kubectl create -f calico-custom-resources.yaml
# Verify Calico installation
kubectl get pods -n calico-systemInstall Calicoctl (Optional tapi Recommended)
# Download calicoctl binary
curl -L https://github.com/projectcalico/calico/releases/download/v3.29.2/calicoctl-linux-amd64 -o calicoctl
# Make executable and move to PATH
chmod +x calicoctl
sudo mv calicoctl /usr/local/bin/
# Verify installation
calicoctl versionπ· Step 8: Join Worker Nodes
Di setiap Worker Node (k8s-worker-1 dan k8s-worker-2):
Join Cluster
Jalankan command join yang didapat dari master node initialization:
# Example command (ganti dengan token actual)
sudo kubeadm join 192.168.100.11:6443 \
--token <your-token> \
--discovery-token-ca-cert-hash sha256:<your-hash>Verify di Master Node
# Cek semua nodes sudah Ready
kubectl get nodes
# Expected output:
# NAME STATUS ROLES AGE VERSION
# k8s-master Ready control-plane 10m v1.32.0
# k8s-worker-1 Ready <none> 5m v1.32.0
# k8s-worker-2 Ready <none> 5m v1.32.0
# Cek pod system berjalan normal
kubectl get pods --all-namespacesπ― Step 9: Test Deployment
Mari test cluster dengan deploy aplikasi sederhana:
Deploy Nginx
# Create deployment
kubectl create deployment nginx-test --image=nginx:latest --replicas=3
# Expose deployment
kubectl expose deployment nginx-test --port=80 --type=NodePort
# Check deployment status
kubectl get deployments
kubectl get pods -o wide
kubectl get servicesTest Connectivity
# Get NodePort
kubectl get svc nginx-test
# Test dari dalam cluster
kubectl run test-pod --image=busybox --rm -it --restart=Never -- wget -qO- nginx-test:80
# Test dari luar cluster (ganti dengan NodePort actual)
curl http://192.168.100.21:<NodePort>π§ Advanced Configuration
Install Metrics Server
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
# Verify
kubectl top nodes
kubectl top podsSetup Ingress Controller (Nginx)
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.10.0/deploy/static/provider/baremetal/deploy.yaml
# Wait for ingress controller to be ready
kubectl wait --namespace ingress-nginx \
--for=condition=ready pod \
--selector=app.kubernetes.io/component=controller \
--timeout=120sπ¨ Troubleshooting Common Issues
Node Not Ready
# Check kubelet status
sudo systemctl status kubelet
# Check kubelet logs
sudo journalctl -u kubelet -f
# Common fixes:
sudo systemctl restart kubelet
sudo systemctl restart containerdPod Stuck in Pending
# Check node resources
kubectl describe nodes
# Check pod events
kubectl describe pod <pod-name>
# Common causes: insufficient resources, node not readyCNI Issues
# Restart Calico pods
kubectl rollout restart daemonset/calico-node -n calico-system
# Check Calico status
kubectl get pods -n calico-system
calicoctl node statusJoin Token Expired
# Generate new token (di master node)
kubeadm token create --print-join-commandπ Monitoring & Maintenance
Useful Commands
# Check cluster health
kubectl cluster-info dump
# Check resource usage
kubectl top nodes
kubectl top pods --all-namespaces
# View cluster events
kubectl get events --sort-by=.metadata.creationTimestamp
# Check service accounts
kubectl get serviceaccounts --all-namespacesRegular Maintenance
# Update Kubernetes components
sudo apt update
sudo apt upgrade kubeadm kubelet kubectl
# Backup etcd (important!)
sudo ETCDCTL_API=3 etcdctl snapshot save backup.db \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.keyπ― Whatβs Next?
Congrats! Sekarang sudah punya production-ready Kubernetes cluster yang berjalan di homelab. Selanjutnya bisa explore:
π Deploy complex applications dengan Helm charts
π Setup persistent storage dengan Longhorn atau Ceph
π Implement GitOps dengan ArgoCD atau Flux
π Add monitoring stack dengan Prometheus + Grafana
π Practice disaster recovery dengan backup/restore procedures
Recommended Next Steps:
- Install Helm - Package manager untuk Kubernetes
- Setup Persistent Volumes - Untuk stateful applications
- Deploy sample microservices - Practice real-world scenarios
- Learn YAML manifests - Deep dive into Kubernetes resources
- Explore security - RBAC, Network Policies, Pod Security
π Final Thoughts
Setting up Kubernetes dari scratch might seem overwhelming, tapi ini adalah fundamental skill yang invaluable buat modern infrastructure. Dengan homelab cluster ini, bisa:
- Understand Kubernetes internals secara mendalam
- Practice deployment strategies tanpa fear of breaking production
- Learn troubleshooting dalam controlled environment
- Build confidence dengan container orchestration
Remember: Kubernetes is a journey, not a destination. Keep experimenting, breaking things (safely), dan learning from mistakes. Thatβs how expertise develops! π
Questions atau stuck di step manapun? Reach out ke phamminhphueur@gmail.com mari troubleshoot together! Building strong Kubernetes community starts with helping each other πͺ
Coming up next: βDeploy Production-Ready Applications di Kubernetes Homelabβ - Stay tuned! π