Files
orca/.ciagent/CLARIFY_v0.14.md
T
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

5.8 KiB

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.