Create an Kubernetes Multi-Node Cluster of AWS Free Tier with CRI-O as Container Engine

Sonam Kumari Singh
4 min readDec 27, 2023

Finally I am able to complete the article on creating multi-node cluster on AWS Free tier. i.e. using a t2.micro. Hope this article is useful. You can connect me on LinkedIn if any help needed.

Launched VMs from the aws cloud

  • ubuntu 22.04 instance with t2.micro

The article will compose of following sections
1. Master Node Configuration
2. Worker Node configuration

1. Master Node Configuration

Let’s Setup cri-o engine first

Update the packages and install the following dependencies:

$ sudo apt update
$ sudo apt install apt-transport-https ca-certificates curl gnupg2 software-properties-common -y

Now let’s configure the CRI-O repository:

## Define the variables below 
$ export OS=xUbuntu_22.04
$ export CRIO_VERSION=1.24

# Configure the repositories
$ echo "deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/ /"| sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
$ echo "deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable:/cri-o:/$CRIO_VERSION/$OS/ /"|sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:stable:cri-o:$CRIO_VERSION.list

# configure the GPG keys
$ curl -L https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable:cri-o:$CRIO_VERSION/$OS/Release.key | sudo apt-key add -
$ curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/Release.key | sudo apt-key add -
$ sudo apt update

#Finally install the cri-o docker engine
$ sudo apt install cri-o cri-o-runc -y
$ sudo systemctl start crio
$ sudo systemctl enable crio
$ sudo systemctl status crio

Now let’s setup the CNI Plugings for the CRI-O

$ sudo apt install containernetworking-plugins -y
$ vi /etc/crio/crio.conf
$ sudo systemctl restart crio

# Optional (If you require crictl command)
sudo apt install -y cri-tools

Networking Configuration:

As a root user run the following commands

$ cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF

$ modprobe overlay
$ modprobe br_netfilter

$ cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF

# Apply sysctl params without reboot
sudo sysctl --system

Finally, Configuring the Kubernetes Repository

$ sudo apt-get install -y apt-transport-https ca-certificates curl gpg
$ curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.29/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.29/deb/ /' | 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
$ systemctl start kubelet
$ systemctl enable --now kubelet

Initiate the cluster:

$ kubeadm init — pod-network-cidr=10.244.0.0/16 — ignore-preflight-errors=NumCPU — ignore-preflight-errors=Mem — cri-socket=unix:///var/run/crio/crio.sock

it would take some time, then configure the kubectl command:

and note the kubeadm join command that you will get at the end

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

Verify the kubectl command is working

root@ip-172-31-39-227:~# kubectl get nodes 
NAME STATUS ROLES AGE VERSION
ip-172-31-39-227 Ready control-plane 64s v1.29.0

root@ip-172-31-39-227:~# kubectl get pods -A
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-76f75df574-lsvkc 1/1 Running 0 55s
kube-system coredns-76f75df574-rxw6f 1/1 Running 0 55s
kube-system etcd-ip-172-31-39-227 1/1 Running 0 71s
kube-system kube-apiserver-ip-172-31-39-227 1/1 Running 0 68s
kube-system kube-controller-manager-ip-172-31-39-227 1/1 Running 0 69s
kube-system kube-proxy-hf659 1/1 Running 0 55s
kube-system kube-scheduler-ip-172-31-39-227 1/1 Running 0 68s

2. Configuring the worker node

Configure the cri-o engine

$ sudo apt update
$ sudo apt install apt-transport-https ca-certificates curl gnupg2 software-properties-common -y

## Define the variables below
$ export OS=xUbuntu_22.04
$ export CRIO_VERSION=1.24

# Configure the repositories
$ echo "deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/ /"| sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
$ echo "deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable:/cri-o:/$CRIO_VERSION/$OS/ /"|sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:stable:cri-o:$CRIO_VERSION.list

# configure the GPG keys
$ curl -L https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable:cri-o:$CRIO_VERSION/$OS/Release.key | sudo apt-key add -
$ curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/Release.key | sudo apt-key add -
$ sudo apt update

#Finally install the cri-o docker engine
$ sudo apt install cri-o cri-o-runc -y
$ sudo systemctl start crio
$ sudo systemctl enable crio
$ sudo systemctl status crio

Configure networking, Run the below commands:

$ cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF

$ modprobe overlay
$ modprobe br_netfilter

$ cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF

# Apply sysctl params without reboot
sudo sysctl --system

Configure kubelet and kubeadm (generally we don’t require kubectl on the worker nodes)

$ sudo apt-get install -y apt-transport-https ca-certificates curl gpg
$ curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.29/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.29/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
$ sudo apt-get update
$ sudo apt-get install -y kubelet kubeadm
$ sudo apt-mark hold kubelet kubeadm
$ systemctl start kubelet
$ systemctl enable --now kubelet

We are now ready to join the cluster, hope you remember the join command

$ kubeadm join 172.31.39.227:6443 — token h6gja6.712g23rje3wdm7he — discovery-token-ca-cert-hash sha256:63466b11aeec4028e76efd3542de5fad2274bb5da033ae8f55940fad166bdfda — ignore-preflight-errors=NumCPU — ignore-preflight-errors=Mem — cri-socket=unix:///var/run/crio/crio.sock

Now we can see that there are two nodes on our cluster.

root@ip-172-31-39-227:~# kubectl get nodes
NAME STATUS ROLES AGE VERSION
ip-172-31-38-126 Ready <none> 32s v1.29.0
ip-172-31-39-227 Ready control-plane 10m v1.29.0

Finally we are done with configuring the multi-node k8s. More nodes can be added by joining the new nodes !!

Follow for more and feel free to reach out to me on linkedin if need to have any discussion

--

--

Sonam Kumari Singh

SONAM here! Grateful for your connection! Tech enthusiast exploring new languages, deep into DevOps, with a spotlight on Linux. 😊🚀