How to Add a Bare-Metal Worker Node (Ansible)
This guide details the explicit, step-by-step playbook sequence necessary to provision and join a fresh bare-metal Debian machine into our Kubernetes cluster, using the strict numerical sequence defined in our homelab architecture.
Prerequisites
Before executing these playbooks, ensure the following conditions are met:
- The new node has Debian installed (e.g., Debian 13 Trixie).
- The node is connected to the same Layer 2 network switch.
- You have noted the IP address assigned to the new node by your DHCP server, and defined it in your Ansible
hosts.yamlinventory.
Execution Sequence
The homelab project enforces a strict, reproducible execution order (numbered 00 through 09).
1. Initial Access & Escalation
Fresh minimal Debian installations often lack the sudo package, and direct root SSH access is typically disabled. Our initial playbooks gracefully handle standard SSH access and utilize su for root escalation.
- Step 1: Distribute SSH Keys Push your automation user's public SSH key to the new node so subsequent playbooks don't require manual SSH passwords.
ansible-playbook -i ansible/inventory/hosts.yaml ansible/playbooks/00-setup-ssh.yaml -l <new-node-name> --ask-pass
- Step 2: Install Sudo
Elevate privileges using
become_method: suto installsudoand authorize the automation user.
ansible-playbook -i ansible/inventory/hosts.yaml ansible/playbooks/01-setup-sudo.yaml -l <new-node-name> --ask-pass --ask-become-pass
!!! info "Important"
You will be prompted for both the standard user password (SSH password) and the root password (BECOME password).
2. Core Node Provisioning
Now that passwordless sudo is configured, you can execute the core bootstrap sequence using --ask-become-pass (or -K).
- Step 3: Bootstrap Debian Hardens the OS, configures kernel parameters, disables swap memory, and sets the physical hostname.
ansible-playbook -i ansible/inventory/hosts.yaml ansible/playbooks/02-bootstrap-debian.yaml -l <new-node-name> -K
- Step 4: Install Container Runtime
Installs
containerdand configures it to utilizesystemdcgroups.
ansible-playbook -i ansible/inventory/hosts.yaml ansible/playbooks/03-install-containerd.yaml -l <new-node-name> -K
- Step 5: Install Kubernetes Binaries
Installs
kubeadm,kubelet, andkubectl. This step includes mandatory dependencies like conntrack and ethtool to passkubeadmpreflight checks.
ansible-playbook -i ansible/inventory/hosts.yaml ansible/playbooks/04-install-k8s.yaml -l <new-node-name> -K
3. Join the Cluster
Once the core binaries are in place, physically join the node to the control plane.
- Step 6: Generate Join Token SSH into the control plane node and generate the join command:
- Step 7: Execute Join Command SSH into the new worker node and execute the generated string:
sudo kubeadm join 192.168.1.51:6443 --token <short-token> --discovery-token-ca-cert-hash sha256:<long-hash>
!!! warning "Common Error"
Ensure you do not accidentally pass the sha256:... hash into the --token parameter, as it will trigger an invalid token preflight failure.
4. Post-Join Configuration
- Step 8: Apply Role and Hardware Labels From your admin workstation, run the custom labeling script to categorize the node.
- Step 9: Optional Hardware Add-ons
If the node requires specific roles (e.g., VPN, GPU), execute the respective playbooks (
07-install-tailscale.yamlor08-install-nvidia.yaml).
Architecture Notes
By encapsulating these disparate configuration tasks into sequential, idempotent playbooks, we conform to the principle of Infrastructure as Code (IaC). The node can be completely wiped and re-provisioned in minutes, minimizing downtime during hardware migrations.