This blog presents how to deploy a self-hosted Kubernetes cluster using kubeadm.

Note that usually we use kubeadm to bootstrap a K8s cluster that has several nodes. It is also easy to scale up the created cluster using kubeadm later. However, if you only need to have a learning environment of K8s, it might be easier to use some tools like kind, and minikube:

Links to The Relevant Documentations

I have also made a demonstration video according to the steps in these documents:

Before Installing Kubeadm

Let us start this journey by creating OpenStack instances: you could follow the video to create an internal network first, then to create several instances that will host the K8s cluster later. One node is used for hosting the control-plane node. The other nodes are used for the workers.

Configure The Created Instances

Ssh to the created nodes first. Run the following commands on each node.

Letting iptables see bridged traffic

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

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

Installing runtime (e.g., Docker)

We use the installation steps for Ubuntu here. If your instances are using other operating systems, please refer to the Docker installation document here.

  • set up the repository
sudo apt-get update
sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg \
  • add Docker’s official GPG key
curl -fsSL | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
  • set up the stable 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 > /dev/null
  • install Docker engine
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli
  • post-installation steps for Linux (optional)

Manage Docker as a non-root user:

sudo usermod -aG docker $USER
newgrp docker

Now you should be able to run docker commands without sudo.

Installing kubeadm, kubelet and kubectl

  • download the Google Cloud public signing key
sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg
  • add the 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
  • update apt package index, install kubelet, kubeadm and kubectl, and pin their version
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl

Creating a cluster with kubeadm

Run the following command on one of the created nodes to initialize it as a control-plane node:

kubeadm init --apiserver-advertise-address=<node's-ip-address> --pod-network-cidr=

The <node's-ip-address> in the command above should be the node's internal IP address, which could be found on the OpenStack dashboard. The value of option --pod-network-cidr has to be because we are going to use Flannel as the network add-on: (Depending on which third-party network add-on you choose, option --pod-network-cidr might be optional, or have different values.)

After running this command, you should be able to see some outputs like the following:

Your Kubernetes control-plane has initialized successfully!


You can now join any number of machines by running the following on each node
as root:

  kubeadm join ...

Now you can run the kubeadm join ... command on the other nodes to make them join the created K8s cluster.

Making kubectl work for your non-root user

Run the following commands, which are also part of the kubeadm init output:

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

Installing a Pod network add-on

Here we use Flannel as an example. You only need to install it on the control-plane node:

kubectl apply -f

Congrats! Now you have successfully deployed a Kubernetes cluster that you have full control of. You can run something like kubectl get nodes to see if all of your nodes are ready :)

Tag:CloudOps, OpenStack

Add a new comment.