Installing Kubernetes on Debian 12 with kubeadm and Configuring Control Plane and Worker Nodes
Recording the steps for installing and configuring Kubernetes, this time using kubeadm.
#Node setup
-
va, Master node
-
ca, Worker node
-
kr, Worker node
#Preparation
Update the system to the latest version, then remove no-longer-needed packages and clean up cached packages.
sudo apt update && sudo apt full-upgrade -ysudo apt autoremovesudo apt autocleanIf the kernel was updated, reboot.
Kubernetes nodes must not have swap enabled, so you need to disable the swap partition.
Then edit the /etc/fstab file and comment out or remove the swap line (if any).
Enable forwarding and related settings:
cat <<EOF | sudo tee /etc/modules-load.d/k8s.confoverlaybr_netfilterEOF
sudo modprobe overlaysudo modprobe br_netfilter
# sysctl params required by setup, params persist across rebootscat <<EOF | sudo tee /etc/sysctl.d/k8s.confnet.bridge.bridge-nf-call-iptables = 1net.bridge.bridge-nf-call-ip6tables = 1net.ipv4.ip_forward = 1EOF
# Apply sysctl params without rebootsudo sysctl --systemAccording to the official Kubernetes documentation, you should install the official Docker packages, so follow the Docker official docs.
#Install Docker
Remove any non-official Docker packages. If you followed this site’s earlier Docker introduction, you likely need to remove the non-official Docker. As for the difference between the official Docker packages and the Debian repository packages: the Debian repo usually ships an older Docker version; whether that matters depends on your needs.
Uninstall the non-official Docker packages to avoid conflicts with the official ones.
for pkg in docker.io docker-doc docker-compose podman-docker containerd runc; do sudo apt-get remove $pkg; doneInstall from the official documentation:
sudo apt-get updatesudo apt-get install ca-certificates curl gnupgsudo install -m 0755 -d /etc/apt/keyringscurl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpgsudo chmod a+r /etc/apt/keyrings/docker.gpg
echo \ "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \ "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \ sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get updatesudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-pluginStart Docker and enable it on boot:
sudo systemctl enable docker --nowNote: The official Docker packages are different from the docker-compose package in the Debian repository. With official Docker you use docker compose (Compose as a plugin). With the Debian package you use docker-compose as a standalone binary.
#Install cri-dockerd
cri-dockerd is the shim that lets Kubernetes talk to Docker. cri stands for Container Runtime Interface.
git clone https://github.com/Mirantis/cri-dockerd.gitcd cri-dockerdmake cri-dockerdsudo mkdir -p /usr/local/binsudo install -o root -g root -m 0755 cri-dockerd /usr/local/bin/cri-dockerdsudo install packaging/systemd/* /etc/systemd/systemsudo sed -i -e 's,/usr/bin/cri-dockerd,/usr/local/bin/cri-dockerd,' /etc/systemd/system/cri-docker.servicesudo systemctl daemon-reloadsudo systemctl enable cri-docker.servicesudo systemctl enable --now cri-docker.socketNote: building cri-dockerd from source requires Go. If you see an error about go not being found, install Go: sudo apt install golang
If later commands fail with socket connection issues, try rebooting the server and temporarily disabling the firewall.
#Install kubeadm, kubelet and kubectl
This part is also based on the official documentation. Note that even though we are on Debian 11/12, we still use the xenial (Ubuntu 16.04 LTS) repository.
sudo apt-get updatesudo apt-get install -y apt-transport-httpscurl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-archive-keyring.gpgecho "deb [signed-by=/etc/apt/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.listsudo apt-get updatesudo apt-get install -y kubelet kubeadm kubectlsudo apt-mark hold kubelet kubeadm kubectl # prevent these three from being upgraded automaticallyAt this point, kubeadm is installed.
#Configure the cluster
A very important topic is networking. There are many machines in a k8s cluster, but externally there may be only a single network interface. For example, if you host a website on k8s, there is only one IP address for external access, but every node in the cluster still needs an IP address for internal communication. These can be private or public addresses. Kubernetes itself does not provide a built-in networking solution; you need to install a plugin. See also the official documentation: installing addons.
Here we use https://www.tigera.io/project-calico/. Different CNI plugins have slightly different installation procedures.
#Set up the master (control plane) node
Initialize the cluster:
sudo kubeadm init --pod-network-cidr 192.168.0.0/16 --cri-socket unix:///var/run/cri-dockerd.sock --control-plane-endpoint master-node-01.acytoo.netIf the server itself has no public IP, you must still specify a control-plane endpoint; this can be either a domain name or an IP address.
Write down the kubeadm join command from the output. You will need its token when adding worker nodes. Each token expires after 24 hours by default.
If the token expires or you lose it, you can run kubeadm token create --print-join-command to generate a new one.
Follow the post-init instructions:
mkdir -p $HOME/.kubesudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/configsudo chown $(id -u):$(id -g) $HOME/.kube/configThen install the Calico network plugin.
#Install Calico
At the time of writing, the version is 3.26.1. Check the official site for the latest version: docs.tigera.io/calico/latest/getting-started/kubernetes/self-managed-onprem/onpremises
curl https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/calico.yaml -Okubectl apply -f calico.yamlNow the control plane node is set up. Check the status:
kubectl get nodekubectl get podkubectl get pods --all-namespacesBy default, for security reasons, Pods are not scheduled on the master (control plane) node.
#Set up worker nodes
Use the kubeadm join command on any server that already has kubeadm and the related tools installed:
sudo kubeadm join master-node-01.acytoo.net:6443 --token sluqvx.itdsjivbewuiinfx \ --discovery-token-ca-cert-hash sha256:95669c834aa9e861aed6a08783d1f893223ec327ad2612aba016c2b457afb2345 \ --cri-socket unix:///var/run/cri-dockerd.sockWorker nodes also need Calico installed.
#Possible errors
While setting everything up, I ran into quite a few issues. In most cases, the command-line error messages were enough to understand what went wrong—for example, the cri-socket service failing to start (check whether it was installed correctly, try starting it manually, then reboot), or port conflicts when specifying the cri-socket, and so on.
The only problem that really took me some time was a worker node failing to connect to socket 8080 (running kubectl get nods would show connection refused on 8080), and the node being stuck in NotReady after kubeadm join. There are many discussions online, and many people say that worker nodes must also have $HOME/.kube/config/admin.conf. But even when I ran init first and then join, it still didn’t work. In the end, I deleted the problematic worker node from the control plane and ran the same join command again—and it worked, without any admin.conf file on the worker.
Delete a worker node from the control plane:
kubectl drain [node name] --ignore-daemonsetskubectl delete node [node name]#Check status
Back on the control plane node, list the nodes:
kubectl get nodes#Conclusion
Kubernetes has many configuration options, installation tools, and installation approaches. This article uses kubeadm as the installation method and Calico as the network plugin. In theory, the same approach works for Debian 10/11/12 and other Debian-based distributions such as Ubuntu.