Files
home-network-k3s-impl/infra/devcontainer
jakman85andClaude Opus 4.8 5d2b248b68 Phase 1 toolchain: pinned dev container (prereqs not all Python)
Per operator rule: OpenTofu/age/sops/flux are Go binaries, so bake the toolchain
into a pinned Fedora-44 dev container (matches host libvirt 12) instead of a venv.
infra/devcontainer/: Containerfile + versions.env (tofu 1.9.0, age 1.2.1, sops
3.9.4, flux 2.4.0, kubectl 1.32.0, helm 3.16.0) + dev.sh (runs with host libvirt
socket + repo + ssh mounted) + README. Built & validated: all tools resolve;
virsh reaches host libvirt from inside the container.

Also record resolved Phase 1 decisions in PHASE1-SCOPE.md (6GiB/4vCPU x3;
k3s-dev NAT 10.73.0.0/24; container toolchain). Gate green.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-08-16 00:59:47 -05:00
..

Dev toolbox (containerized baseline)

The Phase 1 prerequisites are not all Python (OpenTofu, age, sops, flux are Go binaries; only Ansible is Python). Per the operator's rule, the toolchain is therefore a pinned dev container baked with everything needed to drive the local KVM cluster — no host pollution, one reproducible baseline.

What's inside (pinned in versions.env)

OpenTofu, age + age-keygen, sops, flux, kubectl, helm, ansible-core, libvirt-client (so the tofu dmacvicar/libvirt provider can talk to the host libvirt), qemu-img, cloud-init seed tooling (cloud-utils/genisoimage), openssh-clients, and common utilities.

Use

cd infra/devcontainer
./dev.sh build        # build the image (needs network: base image + pinned binaries)
./dev.sh              # build if needed + open a shell in /work (the repo)
./dev.sh run tofu -version

ENGINE=docker ./dev.sh to use docker instead of rootless podman.

How it reaches the host KVM

dev.sh runs the container with:

  • --network host — so Ansible can SSH to the cluster VMs on the k3s-dev NAT subnet (10.73.0.0/24) and kubectl/flux can reach the API server.
  • -v /run/libvirt:/run/libvirt + LIBVIRT_DEFAULT_URI=qemu:///system — so OpenTofu/virsh drive the host libvirt daemon (the socket is world-writable; no group change needed).
  • --security-opt label=disable — lets the container use the host libvirt socket without relabeling it (SELinux hosts).
  • -v $REPO:/work and -v ~/.ssh:/root/.ssh:ro — the repo and your SSH keys.

Notes

  • Versions are best-effort pins; if a download 404s at build, bump the value in versions.env (one line) to the current stable and rebuild. The image records the resolved set at /etc/dev-toolchain-versions.
  • Secrets never enter the image. The SOPS age private key is generated at bootstrap and kept out of git (.gitignore guards age.key).
  • This container is the toolchain, not the cluster. It provisions the 3 KVM nodes (T-1.1–T-1.4); the cluster itself runs on libvirt on the host.