Files
home-network-k3s-impl/infra/cloud-init
jakman85andClaude Opus 4.8 39123d7806 infra(cloud-init): deliver baseline via bpg user-data snippet; drop netplan/meta-data templates
bpg/proxmox generates cloud-init network-config (static IP/gw/DNS) and
meta-data natively from the VM initialization block, so remove
network-config.yaml.tftpl and meta-data.yaml.tftpl. The rich first-boot
baseline (users, SSH key, packages, kernel modules, Longhorn /dev/vdb
mount, swap-off) is preserved and shipped as a user-data snippet
referenced by initialization.user_data_file_id. Comments updated
(libvirt -> Proxmox); /dev/vdb still valid (data disk is virtio1).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-08-25 10:23:21 -05:00
..

infra/cloud-init — first-boot baseline templates

The "Baseline" node lifecycle stage (docs/02 stage 2). user-data.yaml.tftpl is rendered by OpenTofu (templatefile()) and shipped to Proxmox as a cloud-init user-data snippet (proxmox_virtual_environment_file, one per node), referenced by each VM's initialization.user_data_file_id. Authoring only — never applied.

Migrated from libvirt: bpg/proxmox generates the cloud-init network-config (static IP/gateway/DNS) and meta-data natively from the VM's initialization block, so the old network-config.yaml.tftpl / meta-data.yaml.tftpl templates were removed. Only the user-data (this baseline) is still a hand-authored template. Requires the snippets content type enabled on the image datastore (see ../tofu/README).

Serves R-ENV-01 (nodes are "created, baselined, cluster-joined, managed as code") and lays the kernel/OS floor ADR-0001 (k3s) + ADR-0002 (Cilium) + ADR-0003 (Longhorn) + ADR-0005 (KubeVirt) require.

Files

  • user-data.yaml.tftpl — #cloud-config: login user + injected SSH public key, hostname, package baseline, kernel modules, sysctls, Longhorn data-disk mount, swap-off.

${...} tokens are OpenTofu template vars filled by ../tofu/main.tf (hostname, fqdn, username, ssh_authorized_key) — they are not cloud-init/Jinja. IP/gateway/DNS are no longer templated here; bpg/proxmox injects them from the VM's initialization block.

Baseline (cloud-init's job) vs. Ansible's job

cloud-init does (here) Ansible does (T-1.3)
user + SSH public key, hostname install k3s (HA, embedded etcd)
static networking join nodes, disable flannel/kube-proxy/traefik/servicelb
overlay, br_netfilter, iscsi_tcp, dm_crypt, nfs modules install Cilium (kube-proxy replacement, Gateway API, Hubble)
bridge-nf + ip_forward sysctls, inotify limits verify readiness
open-iscsi + nfs-common (Longhorn client prereqs) Flux + SOPS bootstrap handoff
mount /dev/vdb at /var/lib/longhorn —
swapoff + strip swap from fstab —

Why these specifics

  • overlay / br_netfilter + bridge-nf-call sysctls — pod networking / iptables bridging Cilium and kube-networking need.
  • ip_forward / forwarding — routing between pods, nodes, and egress.
  • iscsi_tcp + open-iscsi (iscsid) and nfs / nfs-common — Longhorn attaches volumes over iSCSI and uses the NFS client for backup/RWX (ADR-0003).
  • dm_crypt — headroom for Longhorn volume encryption.
  • swap off — kubelet/k3s expectation.
  • qemu-guest-agent — lets libvirt/tofu read guest state.

Nested-virt for KubeVirt (Phase 5) comes from the tofu host-passthrough CPU mode, not from here.