Skip to main content

Ansible

Ansible is the configuration-management tool for every host that doesn't run Talos Linux. Talos is API-driven and immutable — Ansible would be redundant. The Proxmox hosts, the NetBird connector LXCs on them, and the operator's Fedora workstation are all mutable Linux, and that's where Ansible earns its keep.

Source of truth: ansible/ at the repo root.

Where Ansible fits​

The IaC tool and Ansible are complementary: OpenTofu creates the box, Ansible turns it into a useful one.

Playbooks and roles​

Four playbooks live under ansible/playbooks/, and they map cleanly onto the host groups:

PlaybookHostsWhat it does
proxmox_commissioning.yamlproxmox_hostsApplies the igpu-passthrough role — IOMMU in GRUB, VFIO modules, the iGPU bound to vfio-pci, initramfs regenerated
proxmox_update.ymlproxmoxapt upgrade + autoremove, and keeps the operator SSH keys in root's authorized_keys
netbird_lxc_unattended_upgrades.yamlnetbird_lxcsEnables unattended-upgrades for Debian and the NetBird package origin on the connector LXCs
local_software.yamllocalhostSets up the Fedora workstation — zsh (with the dotfiles and Nerd Font), and optionally vscode, nextcloud, homebrew, docker, netbird, thunderbird

The roles under ansible/roles/ are exactly the ones those playbooks reference: igpu-passthrough for the hypervisors, and docker, homebrew, netbird, nextcloud, thunderbird, vscode, zsh for the workstation. The igpu-passthrough role is the load-bearing one — it is what makes the GPU passthrough into the Talos worker VMs possible.

Inventory pattern​

There is a single inventory, ansible/inventory.yml, wired in through ansible.cfg so no -i flag is needed. It groups hosts by role, not by physical location:

  • proxmox → proxmox_hosts: proxmox-1 … proxmox-4 at 192.168.100.51–54, reached as root.
  • netbird_lxcs: lxc-proxmox{1,2,3,4}-netbird at 192.168.100.71–74, the mesh connectors created by OpenTofu on each hypervisor.
  • synology: maresa at 192.168.0.5, the Docker host.
  • home-assist at 192.168.2.20, a standalone appliance.

Talos nodes are absent by design — there is no SSH to reach them. group_vars/edge.yaml and host_vars/edge-1.yaml are leftovers from the K3s edge era (December 2024 to October 2025, see K3s (legacy)) and match no host in the inventory.

Conventions​

  • Idempotent always. Running a playbook twice should be a no-op the second time.
  • No state files. Drift detection is --check --diff; if the diff is non-empty, that's the drift.
  • Nothing sensitive in the playbooks. The current plays carry only public SSH keys and package lists; cluster and cloud secrets live in SOPS on the Kubernetes and Tofu side (Operations → Secrets). The only Ansible Vault strings left are the K3s-era edge variables, kept for the record and referenced by no play.
  • Roles before tasks. A playbook should mostly compose roles, not declare tasks inline. Tasks-in-playbooks are a smell that wants extracting.

Day-2 commands​

# From ansible/ — the inventory comes from ansible.cfg
# Dry-run the hypervisor update
ansible-playbook playbooks/proxmox_update.yml --check --diff

# Apply
ansible-playbook playbooks/proxmox_update.yml

# Commission a single new hypervisor
ansible-playbook playbooks/proxmox_commissioning.yaml --limit proxmox-4

Where to look next​