Playbook
Install Kubernetes
A Kubernetes node prepared with kubeadm, ready to join a cluster, or a new control plane.
Category
Runtimes
Time limit per server
40 minutes
Temporary failures
Retried automatically, up to 1 time
Version
1.0
Supported systems
Ubuntu 22.04+, Debian 12+, RHEL-compatible 9+ (AlmaLinux, Rocky Linux, RHEL, CentOS Stream, Oracle Linux)
Options
As they appear on the run form, with their defaults.
Kubernetes version
One choice
The three minor versions the Kubernetes project supports. Every server in a cluster should run the same one.
- 1.37 (newest)
- 1.36
- 1.35
Default: 1.37 (newest)
Role
One choice
A control plane needs at least 2 CPUs and 2 GB of memory.
- Worker node, ready to join a cluster
- Control plane, starting a new cluster
Default: Worker node, ready to join a cluster
Pod network
One choice
For a control plane. Flannel is the simplest; Calico also enforces network policies.
- Flannel
- Calico
Default: Flannel
Pod network range
Text
For a control plane. It must not overlap the network your servers are on.
Default: 10.244.0.0/16
Run workloads on the control plane
On or off
For a cluster of one server. Off keeps the control plane for Kubernetes itself.
Default: Off
Open the Kubernetes ports in the firewall
On or off
Only when firewalld or ufw is active. Off leaves the firewall as it is.
Default: On
When to use it
To build a Kubernetes cluster on servers you already run, the way the Kubernetes documentation sets one up with kubeadm. Run it once with Control plane on the server that will manage the cluster, and with Worker node on every server that will run workloads. The Kubernetes Node Setup template updates the server's packages first and then runs this playbook.
Supported on Ubuntu 22.04 and later, Debian 12 and later, and RHEL-compatible 9 and later, on x86_64 and aarch64. Kubernetes 1.35 and later run only on cgroup v2, which rules out RHEL 8 and Ubuntu 20.04.
Choosing the options
Kubernetes version — the three minor versions the Kubernetes project supports: 1.37 (the newest), 1.36 and 1.35. Every server in a cluster should run the same one. Choose 1.37 for a new cluster.
Role
- Worker node, ready to join a cluster — installs everything a node needs and stops before joining. Any server size works.
- Control plane, starting a new cluster — also starts the cluster with
kubeadm initand installs the pod network. Needs at least 2 CPUs and 2 GB of memory.
Pod network — for a control plane:
- Flannel — the simplest pod network. Choose it unless you need network policies.
- Calico — also enforces Kubernetes network policies, which restrict which pods may talk to each other.
Pod network range — for a control plane. The addresses pods get, from /16 to /24. 10.244.0.0/16 suits most setups; choose another range only if it overlaps the network your servers are on.
Run workloads on the control plane — for a cluster of one server. Off keeps the control plane for Kubernetes itself, which is right once you have workers.
Open the Kubernetes ports in the firewall — when firewalld or ufw is active, opens what Kubernetes needs: 6443, 2379–2380, 10250, 10257 and 10259 on a control plane; 10250, 10256 and 30000–32767 on a worker; and the pod network's traffic between servers (8472/udp for Flannel, 179/tcp, 4789/udp and IP-in-IP for Calico). Off leaves the firewall as it is.
What it does on the server
- Turns swap off, now and at boot, keeping a copy of
/etc/fstab. - Loads the
overlayandbr_netfilterkernel modules and turns on IP forwarding (/etc/modules-load.d/k8s.conf,/etc/sysctl.d/k8s.conf). - On the RHEL family, sets SELinux to permissive, as the Kubernetes installation guide requires.
- Installs containerd: the distribution's
containerdon Ubuntu and Debian,containerd.iofrom Docker's repository on the RHEL family. A containerd already installed, such as Docker's, is used. - Adds the chosen version's repository from pkgs.k8s.io, after checking its signing key, and installs
kubelet,kubeadmandkubectl, held at that version so routine package updates never move the cluster. - Configures containerd for Kubernetes: the CRI plugin on, the systemd cgroup driver, and the pause image kubeadm expects. The previous configuration is kept beside it.
- For a control plane: runs
kubeadm init, sets upkubectlfor root, installs Flannelv0.28.9or Calicov3.32.2from their official manifests (checked against pinned checksums), and waits until the node is Ready.
The join command kubeadm init prints is never shown in the run, because it carries a token that lets any machine join the cluster. kubeadm's full output is kept on the server in /root/kubeadm-init.log, readable only by root.
After the run
Add a worker: on the control plane, over SSH, run kubeadm token create --print-join-command --ttl 1h. It prints a kubeadm join command valid for an hour. Run that command on the worker over SSH, then check on the control plane with kubectl get nodes: the worker shows as Ready within a few minutes. Use SSH rather than the Command Runner for these two commands: the Command Runner keeps every command and its output in the run history, and the join command carries a token.
Use the cluster: kubectl works for root on the control plane. To use it from your computer, copy /etc/kubernetes/admin.conf from the control plane to ~/.kube/config on your computer, and treat that file as a password: it gives full control of the cluster.
Upgrade later: upgrades are done with kubeadm upgrade, one minor version at a time. This playbook never changes an installed version.
Common problems
"A control plane needs at least 2 CPUs and 1700 MB of memory" — kubeadm refuses to start a control plane on less. Use a larger server, or make this one a worker.
"This server uses cgroup v1." — Kubernetes 1.35 and later need cgroup v2. Remove systemd.unified_cgroup_hierarchy=0 from the kernel command line, or use a newer distribution.
"Kubernetes … is installed here. Moving to … is an upgrade" — The server already runs another Kubernetes version. Run the playbook with that version, or upgrade with kubeadm upgrade.
"This server has already joined a cluster as a worker" — To turn it into a control plane, remove it from its cluster (kubectl drain and kubectl delete node on the control plane) and run kubeadm reset -f on it first.
"kubeadm could not initialise the control plane" — kubeadm's own reason is in the output (the lines with [ERROR name the check that failed). What it had set up was undone, so fix the cause and run the playbook again.
"The control plane is running, but the node was not Ready after 7 minutes." — Usually the pod network's images are still downloading on a slow connection. The pods listed show what is still starting. Check again with kubectl get pods -A a few minutes later; run the playbook again if a pod is failing.
A worker stays NotReady after joining — Its pod network pod is still starting or cannot reach the control plane. Check kubectl get pods -n kube-system -o wide on the control plane, and that the workers can reach the control plane on port 6443 and each other on the pod network's ports.
"…'s own containerd package is installed, and Docker's packages would replace it." (Install Docker, after Kubernetes) — Kubernetes uses the distribution's containerd on Ubuntu and Debian. Keep Docker and Kubernetes on separate servers there.