In this article, we will look how we can set up a three node Kubernetes v1.28 cluster using kubeadm
Introduction
kubeadm is a tool used to create Kubernetes clusters
It automates the creation of Kubernetes clusters by bootstrapping the control plane, joining the nodes etc
Follows Kubernetes release cycle
Open-source tool maintained by the Kubernetes community
Prerequisites
Create three Ubuntu 20.04 LTS instances for the control plane, node-1 and node-2
Each instance has a minimum specification of 2 CPU and 2 GB RAM
Networking must be enabled between instances
Required ports must be allowed between instances
Swap must be disabled on instances
Initial Configuration
Set up unique hostnames on the control-plane, node-1 and node-2
Once the hostnames are set, log out from the current session and log back in to reflect the changes
# control-plane
sudo hostnamectl set-hostname control-plane
# node-1
sudo hostnamectl set-hostname node-1
# node-2
sudo hostnamectl set-hostname node-2
Update the hosts file on the control-plane, node-1 and node-2 to enable communication via hostnames
# control-plane, node-1 and node-2
sudo vi /etc/hosts
172.31.91.254 control-plane
172.31.94.177 node-1
172.31.87.11 node-2
Disable swap on control-plane, node-1 and node-2 and if a swap entry is present in the fstab file then comment out the line
# control-plane, node-1 and node-2
sudo swapoff -a
sudo vi /etc/fstab
# comment out swap entry
To set containerd as our container runtime on control-plane, node-1 and node-2, first, we need to load some Kernel modules and modify system settings
# control-plane, node-1 and node-2
cat << EOF | sudo tee /etc/modules-load.d/containerd.conf
overlay
br_netfilter
EOF
sudo modprobe overlay
sudo modprobe br_netfilter
# control-plane, node-1 and node-2
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
Installation
Once the Kernel modules are loaded and the system settings are modified, now we can install containerd runtime on control-plane, node-1 and node-2
# control-plane, node-1 and node-2
sudo apt update
sudo apt install -y containerd
Once the packages are installed, generate a default configuration file for containerd on control-plane, node-1 and node-2 and restart the containerd service
# control-plane, node-1 and node-2
sudo mkdir -p /etc/containerd
sudo containerd config default | sudo tee /etc/containerd/config.toml
sudo systemctl restart containerd
We need to install some prerequisite packages on control-plane, node-1 and node-2 for configuring the Kubernetes package repository
# control-plane, node-1 and node-2
sudo apt update
sudo apt install -y apt-transport-https ca-certificates curl
Download the Google Cloud public signing key and configure Kubernetes apt repository on control-plane, node-1 and node-2
# control-plane, node-1 and node-2
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.28/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.28/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
Install kubeadm, kubelet and kubectl tools and hold their package version on control-plane, node-1 and node-2
# control-plane, node-1 and node-2
sudo apt update
sudo apt install -y kubeadm kubelet kubectl
sudo apt-mark hold kubeadm kubelet kubectl
Initialize the cluster by executing the below command on control-plane
# control-plane
sudo kubeadm init --pod-network-cidr 192.168.0.0/16 --kubernetes-version 1.28.0
Once the installation is completed, set up our access to the cluster on control-plane
# control-plane
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
Verify our cluster status by listing the nodes
But our nodes are in a NotReady state because we havenβt set up networking
# control-plane
kubectl get nodes
NAME STATUS ROLES AGE VERSION
control-plane NotReady control-plane 40s v1.28.0
Install the Calico network addon to the cluster and verify the status of the nodes
# control-plane
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/calico.yaml
# control-plane
kubectl get nodes
NAME STATUS ROLES AGE VERSION
control-plane Ready control-plane 101s v1.28.0
Once the networking is enabled, join our workload nodes to the cluster
Get the join command from the control-plane
# control-plane
kubeadm token create --print-join-command
Once the join command is retrieved from the control-plane, execute them in node-1 and node-2
# node-1 and node-2
sudo kubeadm join 172.31.91.254:6443 --token o3in76.aeqii9shr86cem2w --discovery-token-ca-cert-hash sha256:e301651b8930363842b054bafec26aba718dbc724d903c4c73228703622dc5f1
Verify our cluster and all the nodes will be in a Ready state
# control-plane
kubectl get nodes
NAME STATUS ROLES AGE VERSION
control-plane Ready control-plane 2m55s v1.28.0
node-1 Ready <none> 28s v1.28.0
node-2 Ready <none> 19s v1.28.0
Application Deployment
Deploy an Nginx pod, expose it as ClusterIP and verify its status
# control-plane
kubectl run nginx --image=nginx --port=80 --expose
service/nginx created
pod/nginx created
kubectl get pod nginx -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 1/1 Running 0 17s 192.168.247.1 node-2 <none> <none>
kubectl get svc nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx ClusterIP 10.97.157.101 <none> 80/TCP 38s
That's all for now
Reference
https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/
Top comments (1)
Thanks for the write up! I felt it had a good overview of how the kubernetes installation process works. One thing that caught my eye was swap being disabled. This lead me to find an interesting discussion on the project's GitHub issues. Apparently they're working on support for Linux swap in kubernetes, where it graduate to beta in 1.28. If anyone's interested you can check the current progress in this issue.
Thanks for the solid article!