Build nas-otel derived image in CI/GHCR, not on-box
Date: 2026-06-28 Status: Accepted Decision: hl-wxz2 Deciders: Sean Brandt
Context
Section titled “Context”The Firewalla otel-collector role builds its custom journalctl image on the host via docker build and runs it under a systemd docker-compose@ unit. The nas role deploys via the TrueNAS app.* custom-app model, whose runtime pulls images from a registry and exposes no docker build step — making the on-box build mechanism structurally incompatible with the nas delivery path. The nas needs the same journalctl-in-an-image recipe the Firewalla role validated, but delivered a different way.
Decision
Section titled “Decision”Build the nas-otel derived image via a GitHub Actions workflow (.github/workflows/build-nas-otel.yml, modeled on build-headroom-otel.yml) to ghcr.io/fzymgc-house/nas-otel, and have the TrueNAS custom-app pull the (signed) image from the registry. Do not add a Dockerfile.j2 template to the nas role — the Dockerfile content is borrowed from the Firewalla recipe but lives under images/nas-otel/ and is built by CI, not on-box.
Rationale
Section titled “Rationale”- The on-box
docker buildis structurally impossible under the TrueNASapp.*runtime, not merely inconvenient — the custom-app model has no build step. - The repo already has a canonical CI → GHCR → registry-pull pattern (
build-headroom-otel.yml); reusing it keeps one delivery mechanism for all derived cluster images. - Decoupling the build from the appliance is what makes keyless cosign signing possible — OIDC signing requires the CI environment.
Alternatives Considered
Section titled “Alternatives Considered”- CI build to GHCR + registry pull by TrueNAS app (chosen): matches the TrueNAS custom-app delivery model; reuses the proven headroom CI pattern; decouples build from the appliance; enables signing.
- On-box docker build like the Firewalla role (rejected): TrueNAS custom-app runtime exposes no
docker buildstep; fundamentally incompatible with the nas delivery path (validated during design). - Bind-mount host
journalctlinto the distroless image (rejected):journalctlis dynamically linked and resolves its linker from the container filesystem, not the host — it can’t find its shared libraries. Known dead-end (validated on the Firewalla role, 2026-05).
Consequences
Section titled “Consequences”- Positive: one CI/registry delivery pattern for all derived images; enables image signing and provenance attestation.
- Negative: two-PR merge-gate sequencing (image must exist and be cosign-verified before the role change merges); a second build workflow to maintain alongside
build-headroom-otel.yml. - Neutral: Dockerfile content is borrowed from the Firewalla recipe but lives in
images/nas-otel/, not the role.