Skip to content

host_setup

Everything that is not Kubernetes. Runs on every host in the cluster group, control plane and workers alike.

Invoked by play 2 (hosts: cluster, serial: 1, become: true), tag host_setup.

Task files, in execution order

tasks/main.yml includes nine files. The order matters: packages before anything that uses them, and the two reboot-capable tasks last.

flowchart TD
    pkg["install-packages.yml<br/>tag: packages"]
    snapd["remove-snapd.yml<br/>tag: packages"]
    hosts["update-etc-hosts.yml<br/>tag: network"]
    mpath["update-multipath.yml<br/>tag: storage"]
    sysctl["update-sysctl.yml<br/>tag: network"]
    fail2ban["install-fail2ban.yml<br/>tag: security"]
    ufw["setup-ufw.yml<br/>tag: security"]
    swap["disable-swap.yml<br/>tag: system"]
    cgroup["enable-memory-cgroup.yml<br/>tag: system"]:::danger
    rebootd["Reboot handler<br/>flushed at end of play 2"]:::danger

    pkg --> snapd --> hosts --> mpath --> sysctl --> fail2ban --> ufw --> swap --> cgroup
    cgroup -.->|"notifies, if kernel cmdline changed"| rebootd

    classDef danger stroke:#e53935,stroke-width:3px
File Does
install-packages.yml Installs the host_setup_install_packages list: curl, jq, vim, rsync, socat, conntrack, ethtool, ipvsadm and friends
remove-snapd.yml Removes snaps via uninstall-snaps.yml, purges snapd, then blocks reinstallation
update-etc-hosts.yml Writes entries from host_setup_etc_hosts_json
update-multipath.yml Blacklists devices so multipathd does not claim Longhorn's block devices
update-sysctl.yml Kernel networking parameters for Kubernetes: bridge-nf-call, IP forwarding
install-fail2ban.yml Installs and configures fail2ban with exponential backoff
setup-ufw.yml Enables UFW with host_setup_ufw_rules
disable-swap.yml Swaps off now and removes the fstab entry
enable-memory-cgroup.yml Edits the kernel command line if memory cgroups are off; notifies the reboot handler

Variables

39 defaults, all prefixed host_setup_. The ones you are most likely to change:

Variable Purpose
host_setup_sshd_port The SSH port UFW must keep open
host_setup_install_packages Package list
host_setup_ufw_rules Firewall rules
host_setup_ufw_tailnet_ports Kubernetes ports opened inbound on tailscale0. Empty unless tailscale_node_enable is true
host_setup_snapd_purge false keeps a cloud provider's agent snap. See the snapd gotcha below
host_setup_etc_hosts_json Static /etc/hosts entries
host_setup_boot_cmdline_paths Where to look for the kernel command line, differs between Pi and generic Ubuntu
host_setup_cgroup_kernel_args The arguments appended to enable memory cgroups
host_setup_fail2ban_bantime, _bantime_factor, _bantime_maxtime Exponential ban backoff
host_setup_fail2ban_ignoreips Never ban these, put your own subnet here
host_setup_docker_default_data_path Docker data root, for the minikube path

Full list in stage1/roles/host_setup/defaults/main.yml. Values come from the environment via Bitwarden.

Handlers notified

restart fail2ban, clean apt cache, update package cache, and Reboot host.

multipathd is masked, not restarted

update-multipath.yml stops, disables and masks multipathd.service and multipathd.socket so Longhorn's environment check clears. It notifies nothing: a masked unit cannot be restarted. See Handlers.

Re-run behaviour

Idempotent. A second run reports no changes unless a package upgrade is available or a config value changed.

The exception is enable-memory-cgroup.yml: once the kernel command line contains the arguments it stops notifying, so the reboot happens exactly once.

Gotchas

UFW and your SSH port

setup-ufw.yml runs on every cluster host and enables the firewall. It rate-limits port 22 and opens the host's actual ansible_port. If a worker's port in worker_hosts_json does not match its real sshd port, UFW will lock you out of that host mid-play.

Fix the inventory before running, not after.

The tailnet rules are not the security boundary

With tailscale_node_enable true, setup-ufw.yml opens 6443/tcp, 10250/tcp, 8472/udp and 4240/tcp inbound on tailscale0. That interface carries traffic from every device on the tailnet, not only cluster nodes, and 8472 is Cilium's VXLAN, which authenticates nothing and hands the decapsulated frame straight to the pod network.

The tailnet policy file scoping tag:k8s-node is what actually decides which devices can reach those ports. A tailnet with no policy is flat. See tailscale_node.

The rules are add-only. Setting tailscale_node_enable back to false stops new hosts getting them but leaves them on hosts that already have them, matching tailscale_node, which also never un-joins a node.

Memory cgroups need a reboot

On Raspberry Pi, memory cgroups are off by default. Enabling them requires a kernel command line change and a reboot, which is why play 2 ends with meta: flush_handlers. A first run on a Pi will reboot the host. Plan for it.

snapd removal is aggressive

remove-snapd.yml uninstalls every snap, purges snapd, and installs an APT preference blocking reinstallation. It frees memory and removes a source of unattended restarts, but it is not something you want on a host you also use as a desktop.

It is gated at the include, not inside the file: the file's own purge blocks check host_setup_snapd_purge, but its "Shutdown services, sockets and timers" step does not, and would stop and disable snapd.service regardless. Set snapd_purge: false in worker_hosts_json for a cloud node. On OCI the Oracle Cloud Agent is a snap, and it reports the memory metric that A1 idle reclamation measures. Keeping it also means OCI IAM is a command-execution path onto the node, via the agent's Run Command plugin.