Files
key-cape/workplans/KEY-WP-0002-container-image-gitea.md
tegwick 1d68639225
Some checks failed
Build and Publish Container Image / build-and-push (push) Has been cancelled
Align KeyCape image namespace with deployment
2026-05-24 17:17:37 +02:00

6.6 KiB

id, type, title, domain, repo, status, owner, topic_slug, created, updated, capability_request_id, state_hub_workstream_id
id type title domain repo status owner topic_slug created updated capability_request_id state_hub_workstream_id
KEY-WP-0002 workplan KeyCape Container Image — Build & Publish to Gitea OCI Registry netkingdom key-cape done netkingdom netkingdom 2026-03-22 2026-03-21 c8843c7a-460a-47a2-b45a-b8d3940f9aa2

KEY-WP-0002 — KeyCape Container Image — Build & Publish to Gitea OCI Registry

Problem

KeyCape has a Dockerfile but no automated build pipeline and no published image. Other services (k3s deployments, local dev) that need to run KeyCape must build locally from source. There is no versioned artefact to reference in Helm charts or manifests.

The capability request for this work was originally misrouted to railiance. It belongs here: KeyCape owns its own image.

Goal

Produce a versioned OCI image for KeyCape, published to the Gitea container registry on CoulombCore (92.205.130.254:32166), triggered automatically on every merge to main and on semver tags (v*).

Gitea OCI registry endpoint: 92.205.130.254:32166 Image name: 92.205.130.254:32166/coulomb/key-cape

Why Gitea, not GHCR? The net-kingdom cluster is self-hosted. Keeping images in Gitea (also self-hosted on CoulombCore) avoids any external registry dependency and keeps image pulls within the cluster network. GHCR is a future option once public distribution is needed.

Design

Image naming & tagging

Trigger Tags applied
push to main latest, main-<short-sha>
tag v1.2.3 1.2.3, 1.2, 1, latest

Build

Multi-stage Dockerfile already present — no changes needed to the build itself. The image builds to a distroless static binary (~10 MB).

Registry auth

Gitea issues a personal access token (or machine account token) with write:packages scope. Stored as Gitea Actions secret REGISTRY_TOKEN; username stored as REGISTRY_USER.

For local make push, credentials are passed via docker login before the push target runs.

Makefile targets

IMAGE_REGISTRY ?= 92.205.130.254:32166
IMAGE_REPO     ?= coulomb/key-cape
IMAGE_TAG      ?= latest
IMAGE          := $(IMAGE_REGISTRY)/$(IMAGE_REPO):$(IMAGE_TAG)

image:
	docker build -t $(IMAGE) .

push: image
	docker push $(IMAGE)

image-tag:
	docker tag $(IMAGE) $(IMAGE_REGISTRY)/$(IMAGE_REPO):$(IMAGE_TAG)

Gitea Actions workflow

.gitea/workflows/image.yaml — triggers on push to main and on v* tags:

  • Checkout
  • Set up Docker Buildx
  • Login to 92.205.130.254:32166 using secrets
  • Build and push with metadata-action tags
  • (Optional) sign with cosign if available

k3s insecure registry

Gitea runs over plain HTTP on port 32166 (NodePort). k3s must be configured to treat this endpoint as an insecure registry so image pulls work from within the cluster:

# /etc/rancher/k3s/registries.yaml  (on CoulombCore)
mirrors:
  "92.205.130.254:32166":
    endpoint:
      - "http://92.205.130.254:32166"

k3s picks this up on restart (or SIGHUP). Worker nodes (if any) need the same file.


Tasks

T01 — Makefile: image, push, image-tag targets

id: KEY-WP-0002-T01
status: done
priority: high
state_hub_task_id: "749472fc-edb9-4948-9ebc-58d5f38327ee"

Add image, push, and image-tag targets to Makefile with IMAGE_REGISTRY, IMAGE_REPO, IMAGE_TAG variables defaulting to the Gitea endpoint and coulomb/key-cape:latest.

Gate: make image builds successfully locally; IMAGE_TAG=dev make image produces a differently-tagged image.


T02 — Gitea Actions workflow

id: KEY-WP-0002-T02
status: done
priority: high
state_hub_task_id: "8ecf18cc-a3bb-4ede-a09c-fcd0d26d7f9d"

Create .gitea/workflows/image.yaml:

  • Trigger: push to main, push tags matching v*
  • Runner: act_runner label (or ubuntu-latest if configured)
  • Steps: checkout → docker buildx → login → build+push
  • Tags via docker/metadata-action: latest on main, semver on tags

Secrets required (document in README.md under "CI"):

  • REGISTRY_USER — Gitea username or machine account
  • REGISTRY_TOKEN — Gitea personal access token with write:packages

Gate: workflow file is syntactically valid; documented in README.


T03 — k3s insecure registry config on CoulombCore

id: KEY-WP-0002-T03
status: done
priority: high
state_hub_task_id: "2dde67f9-944f-418d-a2e9-7367bc556425"

On CoulombCore, create/update /etc/rancher/k3s/registries.yaml to add the Gitea NodePort as an HTTP mirror. Restart k3s (or send SIGHUP) and verify crictl pull 92.205.130.254:32166/coulomb/key-cape:latest works.

Gate: image pull from within the cluster succeeds without TLS errors.


T04 — Create Gitea machine account & token

id: KEY-WP-0002-T04
status: done
priority: medium
state_hub_task_id: "25775e10-3164-4adb-9c41-835c86fde5f8"

In Gitea (http://92.205.130.254:32166), create a machine account ci-netkingdom (or reuse an existing service account) with access to the netkingdom organisation. Generate a token with write:packages scope and store it in:

  • Gitea Actions secrets on the key-cape repo: REGISTRY_USER, REGISTRY_TOKEN
  • The net-kingdom credential store (SOPS-encrypted) under credentials/gitea-ci-token.enc.yaml

Gate: docker login 92.205.130.254:32166 succeeds with the token; secret is in the credential store.


T05 — Smoke test: push and pull a dev image

id: KEY-WP-0002-T05
status: done
priority: medium
state_hub_task_id: "0f6ab38f-6d34-41af-9180-f19c687947b5"

Manually trigger a build-and-push:

docker login 92.205.130.254:32166
IMAGE_TAG=dev make push

Then verify the image is pullable from CoulombCore:

# on CoulombCore
crictl pull 92.205.130.254:32166/coulomb/key-cape:dev

Gate: pull succeeds; image is listed in Gitea -> Packages -> coulomb/key-cape.


T06 — Update README with registry & CI docs

id: KEY-WP-0002-T06
status: done
priority: low
state_hub_task_id: "946cd34d-94da-4fa9-a781-ed36f6c827a3"

Add a "Container Image" section to README.md documenting:

  • Registry URL and image name
  • How to pull (docker pull 92.205.130.254:32166/coulomb/key-cape:latest)
  • How to build and push locally (Makefile targets)
  • CI secrets required for the Actions workflow

Gate: README section present and accurate.


Done Criteria

  • make image and make push work locally
  • .gitea/workflows/image.yaml present and documented
  • k3s can pull the image from Gitea without TLS errors
  • Machine account token stored in credential store
  • Smoke test: dev image pushed and pulled successfully
  • README updated