Ansible — role catalog¶
Inventory of roles in ansible/roles/. Each role has its
README.md with variables, tags, and verification.
From zero to operational node?
This page is the catalog by role/phase. The complete order to
take a node from bare-metal to operational (includes hardening,
BIND, WiFi — currently outside phases 1-4 below) is in
ansible/bootstrap/README.md.
By implementation phase¶
| Phase | Role(s) | Playbook |
|---|---|---|
| 1 — Network | netplan_bridge |
playbook-set-static-ip.yml |
| 2 — Incus | incus_install, incus_cluster, incus_ui |
playbook-bootstrap.yml + playbook-incus-cluster.yml |
| 3 — K3s | k3s_* (10 roles) |
playbook-k3s.yml |
| 4 — GitOps | — (inline playbook) | playbook-dex-oauth-secrets.yml |
Roles¶
| Role | Purpose | Playbook | Tags |
|---|---|---|---|
netplan_bridge |
Static IP on br0 (Netplan) and static /etc/resolv.conf |
playbook-set-static-ip.yml |
— |
incus_install |
Incus package (Zabbly) | playbook-bootstrap.yml |
— |
incus_cluster |
Incus bootstrap/join/groups | playbook-incus-cluster.yml |
bootstrap, join, groups, scheduler |
incus_ui |
Incus native UI | playbook-incus-cluster.yml |
ui |
incus_ovn |
OVN for Incus (optional, off by default) | playbook-incus-cluster.yml |
ovn |
bind_dns |
BIND on deborah: LAN DNS and mco.local zones, its reverse and homelab.local |
playbook-bind-dns.yml |
— |
| — (no role) | Registers in Incus the metrics certificate read by vmagent (issued by cert-manager; read from Secret monitoring/incus-metrics) |
playbook-incus-metrics.yml |
— |
node_apt_metrics |
Exposes pending apt patches and whether the node needs a reboot to Prometheus (only alerts, installs nothing) | playbook-apt-metrics.yml |
— |
node_units_metrics |
Exposes host service memory and CPU (Ollama, k3s, incus, BIND) and top processes outside Kubernetes to Prometheus, to know what consumes when a node runs out of memory (only measures, changes nothing) | playbook-units-metrics.yml |
— |
k3s_prereqs |
Swap, kernel modules, sysctl, Longhorn requirements (open-iscsi, NFS) | playbook-k3s.yml |
prereqs, always |
k3s_server |
K3s control-plane | playbook-k3s.yml |
server, core |
k3s_cni |
CNI Canal/Calico/Cilium | playbook-k3s.yml |
cni, core |
k3s_agent |
K3s workers | playbook-k3s.yml |
agent, core |
k3s_kube_vip |
API VIP :6443 |
playbook-k3s.yml |
kube_vip |
k3s_cleanup_traefik |
Cleans Traefik/svclb | playbook-k3s.yml |
traefik |
k3s_node_labels |
Node labels | playbook-k3s.yml |
labels |
k3s_argocd |
Argo CD controller | playbook-k3s.yml |
argocd, gitops |
k3s_fetch_kubeconfig |
Local kubeconfig | playbook-k3s.yml |
kubeconfig |
k3s_os_hardening |
unattended-upgrades | playbook-k3s.yml |
hardening |
host_hardening |
SSH, default accounts, sysctl, auditd | playbook-hardening.yml |
— |
opkssh |
SSH to hosts with Dex identity (team devops) |
playbook-opkssh.yml |
— |
ollama_ondemand |
Multi-node Ollama (group llm_nodes: deborah, invincible, oliver) that only starts when a request arrives: socket + systemd proxy, downloads per architecture, MemoryMax per node, CPU cap (CPUQuota), and a guard that stops and alerts if it saturates the node for 2 hours, hardened systemd units, model downloads through the socket, models and priority by host_vars, and the agent that registers the node with the router (guide) |
playbook-ollama.yml |
models, cpu_guard |
host_firewall |
Host firewall with nftables (own table), applied with auto-rollback at 300 seconds if not confirmed; includes VXLAN, Geneve, etcd, and calico-node metrics (README, guide) |
playbook-firewall.yml |
— |
ollama_node |
Ollama registration agent as systemd service (ollama-node-register), running as user ollama-node (supplementary group ollama) and announcing node models to the router (guide) |
playbook-ollama.yml |
register |
wifi_failover |
Cable backup WiFi (nodes with WiFi) | playbook-wifi-failover.yml |
— |
storage_provision |
Formats and mounts a free disk (destructive) | playbook-storage-provision.yml |
— |
Role-less playbooks (inline tasks)¶
| Playbook | Phase | Description |
|---|---|---|
setup_sudo.yml |
Day 0 | Installs python3 and sudo and gives your admin user sudo (connect as root; user can be specified with -e bootstrap_admin_user=<usuario>) |
playbook-discovery.yml |
0 | Hardware inventory → ansible/reports/ |
playbook-incus-cluster.yml |
2 | Incus bootstrap/join/groups/UI |
playbook-dex-oauth-secrets.yml |
4 | Dex OAuth: 1Password + Argo CD + Incus/vCluster |
playbook-rotate-root-passwords.yml |
Security | Rotates root password → 1Password (HomeLab vault) |
playbook-k3s-uninstall.yml |
Appendix | Uninstalls K3s on the 3 nodes |
OAuth documentation: gitops/argocd/secrets/1password.md
K3s execution order¶
flowchart LR
prereqs[k3s_prereqs] --> server[k3s_server]
server --> cni[k3s_cni_opcional]
cni --> kube_vip[k3s_kube_vip_opcional]
server --> kube_vip
kube_vip --> agent[k3s_agent]
agent --> traefik[k3s_cleanup_traefik]
traefik --> labels[k3s_node_labels_opcional]
labels --> argocd[k3s_argocd_opcional]
argocd --> kubeconfig[k3s_fetch_kubeconfig_opcional]
kubeconfig --> hardening[k3s_os_hardening_opcional]
Global configuration¶
| File | Contents |
|---|---|
group_vars/incus_cluster/k3s_install.yml |
K3s playbook flags |
group_vars/dex_oauth_secrets.yml |
Dex OAuth |
group_vars/incus_cluster/vars.yml |
Incus storage, groups, UI |
group_vars/all.yml |
Gateway, control plane IP |
host_vars/*.yml |
Labels, kubelet args per node |