This guide walks you through building a Kubernetes cluster from scratch using kubeadm. You can set up the master node on one cloud provider, such as AWS, and have worker nodes on Azure, GCP, DigitalOcean, or on-premises. This tutorial uses Ubuntu as the example Linux distribution, but the steps apply to other Debian-based systems.
Prerequisites ๐
Before starting, ensure each node meets the following minimum requirements:
- At least 2 GB RAM per machine
- At least 2 CPU cores per machine
- Network connectivity between all nodes (private or public)
- Sufficient storage for your workloads
Server Specifications Example:
- Master Node: 4 GB RAM, 2 CPUs, IP: 10.11.23.30, Hostname: master-node
- Worker Node One: 2 GB RAM, 2 CPUs, IP: 10.11.23.31, Hostname: worker-node-one
- Worker Node Two: 2 GB RAM, 2 CPUs, IP: 10.11.23.32, Hostname: worker-node-two
Installing Containerd ๐
Containerd is the default container runtime for Kubernetes starting from v1.20, replacing Docker. You can also use other supported runtimes like CRI-O, Docker Engine, or Mirantis Container Runtime.
On each node, configure the system modules and sysctl parameters:
cat <<EOF | sudo tee /etc/modules-load.d/containerd.conf
overlay
br_netfilter
EOF
sudo modprobe overlay
sudo modprobe br_netfilter
cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF
sudo sysctl --system
Install containerd and generate its default configuration:
sudo apt update
sudo apt install -y containerd
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml
sudo systemctl restart containerd
sudo systemctl enable containerd
Installing Kubelet, Kubeadm, and Kubectl ๐
Install Kubernetes tools on all nodes (master and workers):
sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl
sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg
echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
Initializing the Master Node ๐
On the master node, initialize the control plane:
sudo kubeadm init
After initialization completes, copy the kubeconfig to your user account (non-root) to interact with the cluster:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
Ensure firewall rules allow communication between the master and worker nodes on the necessary Kubernetes ports.
Installing Kubernetes Networking ๐
Kubernetes supports multiple networking solutions such as Calico, Cilium, Antrea, AWS VPC CNI, and Weave. This guide uses Weave:
kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')"
You can configure IP ranges and advanced settings as needed; refer to Weave documentation for details.
Joining Worker Nodes ๐
If you still have the kubeadm join command from initialization, use it on each worker node. If not, generate a new token on the master node:
kubeadm token create --print-join-command
Then run the join command on each worker node:
sudo kubeadm join <MASTER_IP>:6443 --token <TOKEN> --discovery-token-ca-cert-hash <HASH>
docker run -d --name model-runner-proxy -p 8080:80 \
alpine/socat tcp-listen:80,fork,reuseaddr tcp:model-runner.docker.internal:80
Verifying the Cluster ๐
On the master node or any node with configured kubeconfig, check that all nodes have joined:
kubectl get nodes
You should see all worker nodes in the READY state. Optionally, enable kubectl auto-completion for a smoother CLI experience.