generated from coulomb/repo-seed
Some checks failed
Build and Publish Container Image / build-and-push (push) Has been cancelled
246 lines
6.6 KiB
Markdown
246 lines
6.6 KiB
Markdown
---
|
|
id: KEY-WP-0002
|
|
type: workplan
|
|
title: "KeyCape Container Image — Build & Publish to Gitea OCI Registry"
|
|
domain: netkingdom
|
|
repo: key-cape
|
|
status: done
|
|
owner: netkingdom
|
|
topic_slug: netkingdom
|
|
created: "2026-03-22"
|
|
updated: "2026-03-21"
|
|
capability_request_id: ""
|
|
state_hub_workstream_id: "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
|
|
|
|
```makefile
|
|
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:
|
|
|
|
```yaml
|
|
# /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
|
|
|
|
```task
|
|
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
|
|
|
|
```task
|
|
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
|
|
|
|
```task
|
|
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
|
|
|
|
```task
|
|
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
|
|
|
|
```task
|
|
id: KEY-WP-0002-T05
|
|
status: done
|
|
priority: medium
|
|
state_hub_task_id: "0f6ab38f-6d34-41af-9180-f19c687947b5"
|
|
```
|
|
|
|
Manually trigger a build-and-push:
|
|
```bash
|
|
docker login 92.205.130.254:32166
|
|
IMAGE_TAG=dev make push
|
|
```
|
|
|
|
Then verify the image is pullable from CoulombCore:
|
|
```bash
|
|
# 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
|
|
|
|
```task
|
|
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
|