Provisioning Single-node Kubernetes Cluster using kubeadm on Ubuntu 20.04

There are many tools out there to provision single-node Kubernetes clusters but kubeadm is the way to go for a production-like set-up. Although it is more difficult to create a cluster with kubeadm, with its configuration options you can tweak the cluster to your needs. By following this post you can easily create a Single-node Kubernetes Cluster using kubeadm on Ubuntu 20.04.

Command line output of kubectl showing the WordPress components on a Kubernetes cluster

This post is for Ubuntu 20.04. Please see the updated version for Ubuntu 22.04.

Install general dependencies

Some packages need to be installed on your system for the commands we will use later.

sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates \
  curl gnupg lsb-release

Install docker from official repository

Installing docker from the official docker repository as this is the recommended way.

# Remove all other versions of docker from your system
sudo apt-get remove -y docker docker-engine \ containerd runc

# Add docker GPG key
curl -fsSL \
  | sudo gpg --dearmor \
  -o /usr/share/keyrings/docker-archive-keyring.gpg

# Add docker apt repository
echo \
  "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] $(lsb_release -cs) stable" \
  | sudo tee /etc/apt/sources.list.d/docker.list

# Fetch the package lists from docker repository
sudo apt-get update

# Install docker and containerd
sudo apt-get install -y docker-ce docker-ce-cli

Configure docker for kubeadm

We have to do some configuration changes to docker to make it work with Kubernetes or the kubeadm pre-flight checks will fail.

# Configure docker to use overlay2 storage and systemd
sudo mkdir -p /etc/docker
cat <<EOF | sudo tee /etc/docker/daemon.json
    "exec-opts": ["native.cgroupdriver=systemd"],
    "log-driver": "json-file",
    "log-opts": {"max-size": "100m"},
    "storage-driver": "overlay2"

# Restart docker to load new configuration
sudo systemctl restart docker

# Add docker to start up programs
sudo systemctl enable docker

# Allow current user access to docker command line
sudo usermod -aG docker $USER1

# Download cri-dockerd
curl -sSLo cri-dockerd_0.2.3.3-0.ubuntu-focal_amd64.deb \

# Install cri-dockerd for Kubernetes 1.24 support
sudo dpkg -i cri-dockerd_0.2.3.3-0.ubuntu-focal_amd64.deb

Install kubeadm, kubelet & kubectl

You need to ensure the versions of kubeadm, kubelet and kubectl are compatible.

# Add Kubernetes GPG key
sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg \

# Add Kubernetes apt repository
echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] kubernetes-xenial main" \
  | sudo tee /etc/apt/sources.list.d/kubernetes.list

# Fetch package list
sudo apt-get update

sudo apt-get install -y kubelet kubeadm kubectl

# Prevent them from being updated automatically
sudo apt-mark hold kubelet kubeadm kubectl

Ensure swap is disabled

The swap feature has to be disabled because it is not supported by Kubernetes. See the GitHub issue regarding swap on Kubernetes for details.

# See if swap is enabled
swapon --show

# Turn off swap
sudo swapoff -a

# Disable swap completely
sudo sed -i -e '/swap/d' /etc/fstab

Create the cluster using kubeadm

It’s only a single command to initialise the cluster but it won’t be very functional in single-node environments until we make some changes. Note that we’re providing the “–pod-network-cidr” parameter as required by our CNI plugin (Flannel). We’re also providing the “–cri-socket” parameter too, so kubeadm can use the right container runtime.

sudo kubeadm init --pod-network-cidr= --cri-socket=/var/run/cri-dockerd.sock

Configure kubectl

To be able to access the cluster we have to configure kubectl.

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

Untaint node

We have to untaint the node to allow pods to be deployed to our single-node cluster otherwise your pods will be stuck in a pending state.

kubectl taint nodes --all
kubectl taint nodes --all

Install a CNI plugin

For networking to function, you must install a Container Network Interface (CNI) plugin. We’re installing flannel.

kubectl apply -f

Install helm

To install our packages, we’re installing helm v3.

curl | bash

Install a CSI driver

We need to install a Container Storage Interface (CSI) driver for the storage to work. We’ll install OpenEBS.

# Add openebs repo to helm
helm repo add openebs

kubectl create namespace openebs

helm --namespace=openebs install openebs openebs/openebs

Install a test application

To test the cluster, you can deploy WordPress. Note that we need to specify the storage class provided by our CSI.

# Add bitnami repo to helm
helm repo add bitnami

helm install wordpress bitnami/wordpress \

The end

You have successfully created a single-node Kubernetes Cluster using kubeadm on Ubuntu 20.04, and the cluster has everything you need to install your application.

If you’d like to watch this in a video, see below:


2 thoughts on “Provisioning Single-node Kubernetes Cluster using kubeadm on Ubuntu 20.04

Leave a Reply

Your email address will not be published. Required fields are marked *