Building a Kubernetes v1.28 Cluster using kubeadm
Tags: kubernetes, cloudnative, opensource, beginners
Published: 2023-08-23 13:49:51

> 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

```bash
# control-plane

sudo hostnamectl set-hostname control-plane
```

```bash
# node-1

sudo hostnamectl set-hostname node-1
```

```bash
# 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

```bash
# 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

```bash
# 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

```bash
# 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
```

```bash
# 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

```bash
# 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

```bash
# 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

```bash
# 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

```bash
# 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

```bash
# 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

```bash
# 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

```bash
# 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

```bash
# 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

```bash
# control-plane

kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/calico.yaml
```

```bash
# 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

```bash
# 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

```bash
# 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

```bash
# 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

```bash
# 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/](https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/)