Files
orca/.ciagent/CLARIFY_v0.14.md
Jon Chery 9853aee589 docs(P00): clarify — v0.14 ingress bootstrap decisions
9 decisions (D-255..D-263) resolved: podman container model,
--network host, mounted step-ca CA, dynamic config volume mount,
floating-IP LXC registered as linux node, IngressMode on model.Node,
MAC generation rules, native-mode DNAT target = LXC IP, LXC nesting.

---ci---
project: orca
phase: 0
milestone: v0.14
status: clarify
---/ci---
2026-08-10 18:08:26 +00:00

79 lines
5.8 KiB
Markdown

# CLARIFY v0.14: Ingress Bootstrap Completeness
**Autonomy**: full (config `autonomy.level = "full"`)
**Budget**: 10 questions (used: 5 interactive, 5 auto-resolved)
**Result**: all ambiguities resolved; 9 decisions (D-255..D-263) recorded in PROJECT.md
## Interactive Questions (resolved with operator)
### Q1: iptables vs nft emitter
**Ambiguity**: Codebase is nft-only (D-218). Operator said "iptables used for SNAT/DNAT".
**Resolution**: D-255 (partial) — Extend the existing nft emitter (`internal/emitter/nft.go`) with SNAT/MASQUERADE postrouting rules. "iptables" in the operator's description is read as "kernel NAT" — nft is the modern backend. No literal iptables emitter.
**Confidence**: 0.95
### Q2: ingress LXC lifecycle
**Ambiguity**: Should the floating-IP LXC be registered as an orca-managed node or left as a one-shot external proxy?
**Resolution**: D-259 — Register as a managed `linux` node (name=`ingress`, addr=`<floating-ip>:8443`). `orca job run` pushes traefik dynamic config to it like any linux node. This makes routing-to-other-hosts work.
**Confidence**: 0.92
### Q3: Floating-IP network topology
**Ambiguity**: Where does SNAT run and how does the LXC get the public IP?
**Resolution**: LXC owns floating IP on eth0 (`net0 bridge=vmbr0,hwaddr=<mac>,ip=<floating-ip>/<prefix>,gw=<gateway>`). nft runs inside the LXC. Matches Hetzner/OVH floating-IP-with-MAC model.
**Confidence**: 0.90
### Q4: TLS cert resolver in the image
**Ambiguity**: The emitted static config references `certResolver: orca` but never declares the `certificatesResolvers.orca` block. v0.11 claimed P10 would wire step-ca but it was never implemented.
**Resolution**: D-257 — Bake a `certificatesResolvers.orca.tls: { }` block pointing at a mounted `/etc/orca/step-ca-root.crt` CA file. No ACME (offline-first, R-001). If the file is absent at start, traefik logs a warning and serves plain HTTP (graceful degradation). The orca bootstrap pushes the cluster root CA into the container volume.
**Confidence**: 0.90
### Q5: Container networking
**Ambiguity**: nft DNAT targets 127.0.0.1:8080/8443 on the host. How does the podman container receive that traffic?
**Resolution**: D-256 — `--network host` so traefik binds 127.0.0.1:8080/8443 directly on the host (or LXC) loopback. No container port publishing. Simplest, matches the hybrid R-017 model.
**Confidence**: 0.92
### Q6: Dynamic config volume strategy
**Ambiguity**: How does the podman traefik container consume dynamic config? Today `orca job run` writes `/etc/traefik/dynamic/orca-<svc>.yaml` on the host.
**Resolution**: D-258 — Mount `/etc/traefik/dynamic` from host (`-v /etc/traefik/dynamic:/etc/traefik/dynamic:Z`). Zero changes to the existing `deployRemote` WriteFile path. The image's file provider watches `/etc/traefik/dynamic` as today.
**Confidence**: 0.95
## Auto-resolved questions (full autonomy, no operator interaction)
### Q7: Floating-IP mode — does the PVE host also register as a node?
**Ambiguity**: In floating-IP mode, only the ingress LXC handles traffic. Does the PVE host also get registered?
**Resolution**: D-259 — Yes. The PVE host registers as a `proxmox` node (for `pct`/`qm` workload dispatch). The ingress LXC registers as a `linux` node (for traefik dynamic config pushes). Both are in the registry.
**Confidence**: 0.92
### Q8: `--ingress-mode` persistence
**Ambiguity**: Should `--ingress-mode` be stored on the node record so `doctor ingress` knows which check path to run?
**Resolution**: D-260 — Yes. Add `IngressMode` field to `model.Node` + a schema migration (0007). Values: `""` (legacy/default for linux/localhost), `"native"`, `"floating-ip"`.
**Confidence**: 0.90
### Q9: MAC generation when `--mac` omitted
**Ambiguity**: In floating-IP mode, if `--mac` is not provided, should orca generate one or require it?
**Resolution**: D-261 — Interactive mode: generate a random locally-administered MAC (`02:XX:XX:XX:XX:XX`) and print it for operator confirmation. `--json` mode: require `--mac` explicitly (no silent generation — non-interactive means explicit inputs).
**Confidence**: 0.88
### Q10: Proxmox native nft DNAT target
**Ambiguity**: In native mode, traefik runs inside an LXC. LXC has its own network namespace. nft DNAT to `127.0.0.1:8443` on the PVE host would NOT reach a container inside an LXC (different loopback). What's the DNAT target?
**Resolution**: D-262 — The nft DNAT target is parameterized via `NftClusterConfig.DNATTarget` (default `127.0.0.1:8443`). For proxmox native mode, the DNAT target is the LXC's bridge IP (`<lxc-ip>:8443`). The LXC gets a DHCP/static bridge IP; orca discovers it after `pct start` via `pct list` or `pct inspect`.
**Confidence**: 0.90
## Additional decisions (derived from constraints, no ambiguity)
### D-263: LXC podman requirements
Ubuntu 24.04 LXC template does not have podman preinstalled. Bootstrap must:
1. `pct create` with `--features nesting=1,keyctl=1` (required for podman in unprivileged LXC)
2. After LXC start: `apt-get update && apt-get install -y podman nftables` inside the LXC
3. Then `podman pull orca-traefik:<tag>` + `podman run ...`
This adds ~30-60s to the join time. Documented in `docs/uat.md`.
### Image tag strategy
The `orca-traefik` image uses the same version tag as the orca release (`v0.13.x` line). The podman reconciler resolves the tag from `internal/cli.version`. In dev builds (version="dev"), it falls back to `latest`.
### Registry auth
The `orca-traefik` image is in the same registry/org as `orca` (`git.cloudinit.dev/coreci/`). Pulls are anonymous (REQ-045, repo is public). No `podman login` needed on workers.
## Requirements impact
No new requirements beyond REQ-171..REQ-179 (already in REQUIREMENTS.md). The clarify stage confirmed scope and resolved all implementation ambiguities. The 9 decisions (D-255..D-263) are recorded in PROJECT.md.