OpenTofu libvirt module (k3s-dev NAT 10.73.0.0/24, 3x 6GiB/4vCPU VMs, 20G OS +
40G thin data, host-passthrough), cloud-init baseline (k3s/Cilium/Longhorn
prereqs, static net), Ansible k3s-HA + Cilium (kube-proxy replacement, Gateway
API, Hubble; flannel/kube-proxy/Traefik disabled). PM fix: escape ${...} in a
cloud-init template comment (tofu templatefile parse). tofu fmt/init/validate =
Success; ansible --syntax-check + yamllint pass. NOTHING executed (no apply).
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
46 lines
2.3 KiB
Markdown
46 lines
2.3 KiB
Markdown
# infra/cloud-init — first-boot baseline templates
|
|
|
|
Phase 1 **T-1.2**. The "Baseline" node lifecycle stage (docs/02 stage 2). These
|
|
templates are consumed by the OpenTofu `libvirt_cloudinit_disk` in `../tofu/`
|
|
(via `templatefile()`), one seed per node. **Authoring only — never applied.**
|
|
|
|
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.
|
|
- `meta-data.yaml.tftpl` — NoCloud instance-id / local-hostname.
|
|
- `network-config.yaml.tftpl` — netplan v2 **static** IP (DHCP is off on the NAT).
|
|
|
|
`${...}` tokens are **OpenTofu** template vars filled by `../tofu/main.tf`
|
|
(`hostname`, `fqdn`, `username`, `ssh_authorized_key`, `ip`, `prefix`, `gateway`)
|
|
— they are not cloud-init/Jinja.
|
|
|
|
## 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.
|