Install K8s on Bare Metal or Hypervisor

Prepare the nodes

My setup will be four VMs:

  • kube-admin - Control plane/master node
  • kube-0 - Compute node #1
  • kube-1 - Compute node #2
  • kube-2 - compute node #3

I can generate them using my kvmgr tool: -c 2 -m 2048 -d 10G -o focal -n kube-admin -c 2 -m 2048 -d 20G -o focal -n kube-0 -c 2 -m 2048 -d 20G -o focal -n kube-1 -c 2 -m 2048 -d 20G -o focal -n kube-2

After the VMs are up, add the IPs to /etc/hosts  kube-admin  kube-0  kube-1 kube-2

Kernel config

This procedure is run on all four nodes before installing kubernetes.

Configure the bridge module to load on every boot:

sudo modprobe br_netfilter

Configure the network stack to bridge correctly:

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
net.ipv4.ip_forward = 1
sudo sysctl --system

Install Containerd

Containerd is the docker runtime for this setup.

sudo apt install -y containerd

Install Kubelet

First, install the prereqs for HTTPS repositories:

sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl

Import the k8s keyring:

sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg

Add the Apt repo:

echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] kubernetes-focal main" | sudo tee /etc/apt/sources.list.d/kubernetes.list

Install the packages on the server:

sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl

Optionally, pin the current package versions to prevent upgrades.

sudo apt-mark hold kubelet kubeadm kubectl

Install admin node tools

Create a kubeadm-config.yaml file:

# kubeadm-config.yaml
kind: ClusterConfiguration
kubernetesVersion: v1.21.0
kind: KubeletConfiguration
cgroupDriver: systemd

Begin the init process:

sudo kubeadm init --pod-network-cidr=""

This take a few minutes to start the kubelet.

When the command completes successfully:

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

Check the cluster status:

$ kubectl get all
NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP    <none>        443/TCP   2m23s

Adding a node to the cluster

This command needs to be run on the rest of the nodes, kube-0, kube-1, kube-2.

kubeadm join --token d3elti.x8dheeghld76txud \
    --discovery-token-ca-cert-hash sha256:4dc30c96de01f73c26ea645fbf34e45822c232c04fb1df58aca3a58df7c9b827

Install Calico

Calico provides the pod network abstraction layer for this cluster.

Install it from the manifest:

kubectl apply -f

Check status:

kubectl get pods -n kube-system

At this point the system should be ready:

$ kubectl get nodes
NAME         STATUS   ROLES                  AGE     VERSION
kube-0       Ready    <none>                 8m19s   v1.21.0
kube-1       Ready    <none>                 7m35s   v1.21.0
kube-2       Ready    <none>                 7m2s    v1.21.0
kube-admin   Ready    control-plane,master   32m     v1.21.0

The cluster is now complete, though barebones. Additional considerations should be made for shared storage and load balancing.