>_

Setting Up a Production-Ready Kubernetes Cluster

A comprehensive guide to bootstrapping a Kubernetes cluster from scratch — covering kubeadm, networking with Cilium, and essential post-install steps.

#kubernetes #devops #containers #infrastructure

Kubernetes has become the de-facto standard for container orchestration. In this guide, we’ll walk through setting up a production-ready cluster from scratch using kubeadm — no managed services, no shortcuts.

Prerequisites

Before you begin, make sure each node has:

Run a quick sanity check on each node:

sudo swapoff -a
free -h  # verify swap is 0
uname -r # should be 5.15+

Installing Container Runtime

We’ll use containerd as the CRI-compatible runtime:

# Install containerd
sudo apt-get update
sudo apt-get install -y containerd

# Generate default config
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml

# Enable SystemdCgroup
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
sudo systemctl restart containerd
sudo systemctl enable containerd

Bootstrapping with kubeadm

On the control plane node:

sudo kubeadm init \
  --pod-network-cidr=10.244.0.0/16 \
  --apiserver-advertise-address=<CONTROL_PLANE_IP>

After initialization, set up kubectl:

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

Verify your cluster is running:

kubectl get nodes
# NAME          STATUS   ROLES           AGE   VERSION
# control-01   Ready    control-plane   2m    v1.29.0

Installing Cilium for Networking

Cilium provides eBPF-based networking, observability, and security:

# Install Cilium CLI
CILIUM_CLI_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/cilium-cli/main/stable.txt)
curl -L --fail --remote-name-all \
  https://github.com/cilium/cilium-cli/releases/download/${CILIUM_CLI_VERSION}/cilium-linux-amd64.tar.gz
sudo tar xzvf cilium-linux-amd64.tar.gz -C /usr/local/bin
rm cilium-linux-amd64.tar.gz

# Install Cilium into the cluster
cilium install --version 1.15.0
cilium status --wait

Joining Worker Nodes

On each worker node, run the join command from the kubeadm init output:

sudo kubeadm join <CONTROL_PLANE_IP>:6443 \
  --token <TOKEN> \
  --discovery-token-ca-cert-hash sha256:<HASH>

Tip: If you lost the join token, regenerate it with:

kubeadm token create --print-join-command

Essential Post-Install Steps

1. Install Metrics Server

# metrics-server.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: metrics-server
  namespace: kube-system
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: metrics-server
  namespace: kube-system
spec:
  replicas: 1
  selector:
    matchLabels:
      app: metrics-server
  template:
    metadata:
      labels:
        app: metrics-server
    spec:
      serviceAccountName: metrics-server
      containers:
        - name: metrics-server
          image: registry.k8s.io/metrics-server/metrics-server:v0.7.0
          args:
            - --kubelet-insecure-tls

Apply it:

kubectl apply -f metrics-server.yaml
kubectl top nodes   # should work after ~60s

2. Storage with Longhorn

For persistent volume management, install Longhorn:

kubectl apply -f https://raw.githubusercontent.com/longhorn/longhorn/v1.6.0/deploy/longhorn.yaml
kubectl -n longhorn-system get pods  # wait for all pods to be Running

Wrapping Up

You now have a production-ready Kubernetes cluster with:

In the next post, we’ll cover setting up ArgoCD for GitOps deployments and Prometheus + Grafana for monitoring. Stay tuned!

Back to all posts