blumeops/docs/how-to/configuration/build-spork-container.md
Erich Blume 76f262b31f Add custom Kingfisher container built from sporked feature branches
- Dockerfile: deterministic build from pinned CONTAINER_APP_VERSION + FEATURES
- Merges named feature branches at specific SHAs for reproducibility
- Switch CronJob to custom image with --clone-url-base and --all-organizations
- Add kingfisher to service-versions.yaml (version tracks upstream main SHA)
- Document spork container builds in new how-to card
- Document spork workflow in CLAUDE.md
- Update kingfisher service docs for custom image

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 18:11:35 -07:00

2.8 KiB

title modified last-reviewed tags
Build a Spork Container 2026-03-29 2026-03-29
how-to
containers
git

Build a Spork Container

How to build a container image from a spork-strategy project with fully-pinned, reproducible inputs.

Why not use the deploy branch directly?

The deploy branch is force-pushed on every mirror-sync. Building from deploy is not reproducible — the same Dockerfile run a week later gives different code. Instead, spork containers build their own merge tree from explicit inputs:

  • CONTAINER_APP_VERSION — the commit on main to base on (the upstream version)
  • FEATURES — space-separated branch=sha pairs to merge on top

This makes builds reproducible regardless of when they run.

Prerequisites

  • Sporked project set up (see create-a-spork)
  • Container build tooling (mise run container-build-and-release)

Get the SHAs

cd ~/code/3rd/kingfisher
git fetch origin

# Upstream SHA (what main is based on)
git rev-parse --short origin/main
# e.g., 1d37d29

# Feature branch SHAs
git rev-parse --short origin/feature/upstream/clone-url-base
# e.g., 677c7a5

Build the container

# The version in service-versions.yaml is the upstream SHA
mise run container-build-and-release kingfisher 1d37d29 \
    --build-arg CONTAINER_APP_VERSION=1d37d29 \
    --build-arg FEATURES="feature/upstream/clone-url-base=677c7a5"

The container tag will be 1d37d29-<blumeops-commit>.

Update the deployment

  1. Update argocd/manifests/kingfisher/kustomization.yaml with the new tag
  2. Update service-versions.yaml if the upstream SHA changed
  3. Sync the ArgoCD app

How the Dockerfile works

The build stage:

  1. Clones the sporked repo from forge
  2. Checks out main at CONTAINER_APP_VERSION
  3. For each entry in FEATURES, fetches the branch and merges at the pinned SHA
  4. Builds from source with cargo build --release

If any merge conflicts, the build fails loudly.

The runtime stage is minimal: debian-slim + git + the binary.

Note on CONTAINER_APP_VERSION

For most blumeops containers, CONTAINER_APP_VERSION is an upstream release version like 5.22.0 or v2.19.2. For sporked containers it's a git SHA — the upstream commit the build is based on. This is a deliberate abuse of the naming convention to satisfy the container-version-check hook. Don't confuse it with an upstream release number.

Reproducibility guarantee

Given the same CONTAINER_APP_VERSION and FEATURES, the build produces identical source code regardless of what deploy, blumeops, or main currently look like on forge. The only external dependency is the Rust/Boost toolchain version in the FROM line.

See also