Files
railiance-apps/workplans/RAIL-AP-WP-0001-gitea-container-registry.md
tegwick 36c373cc62 RAIL-AP-WP-0001 T04 done: state-hub image pushed and cluster-pullable
Used the GITEA_API_TOKEN env (token owner: tegwick) to log in to
gitea.coulomb.social and push state-hub:local as
gitea.coulomb.social/coulomb/state-hub:{6186a99,latest}.

Image digest:
  sha256:039d29654ccb3754c6ecdbe497c6364bbd8452edcdcb7fa937dd9debf5b734ff

Verified cluster-side pull via kubectl run; pod reached Running in
~5s with no imagePullSecret. The Gitea container registry is now
proven end-to-end for State Hub deployment.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-19 00:35:15 +02:00

14 KiB

id, type, title, domain, repo, status, owner, topic_slug, created, updated, planning_priority, planning_order, state_hub_workstream_id
id type title domain repo status owner topic_slug created updated planning_priority planning_order state_hub_workstream_id
RAIL-AP-WP-0001 workplan Enable Gitea Container Registry for Cluster Image Publishing railiance railiance-apps active railiance railiance 2026-05-15 2026-05-15 high 1 abd268e6-5af9-45ec-93e0-5ffca0211dd0

Enable Gitea Container Registry for Cluster Image Publishing

Goal

Enable the existing Railiance-managed Gitea deployment to serve as an OCI container registry so cluster workloads can publish and pull images through the same source-forge boundary already used for Git hosting.

The immediate forcing function is CUST-WP-0011: the State Hub image state-hub:local builds and smoke-tests locally, but cannot be published until Docker can authenticate against the Gitea registry /v2/ endpoint.

Placement in the Railiance Tooling Set

This workplan lives in railiance-apps because Gitea is an S5 application workload. The active deployment surface is:

  • helm/gitea-values.sops.yaml — SOPS-encrypted Gitea Helm values.
  • Makefile target gitea-deploy — applies the Gitea Helm release.
  • Makefile target gitea-status — checks Gitea pod and database health.

Lower-layer ownership remains unchanged:

Concern Owner repo Notes
Gitea application config and Helm release railiance-apps This workplan
Gitea database and CNPG health railiance-platform Existing gitea-db
Ingress controller / cluster routing primitives railiance-cluster Only if /v2/ requires lower-layer route changes
Forgejo replacement roadmap railiance-infra RAIL-HO-WP-0005 remains the umbrella plan

This is not a replacement for the Forgejo production migration. It is a pragmatic enablement step for current Gitea so images needed before Forgejo cutover have a governed registry target.

Current Evidence

  • railiance-apps/SCOPE.md states that Gitea Helm values are owned here and that Gitea is the active git hosting platform for Railiance and Custodian repos.
  • railiance-apps/Makefile deploys Gitea via helm/gitea-values.sops.yaml into the gitea namespace.
  • helm/gitea-values.sops.yaml currently contains Gitea app config sections such as server, database, cache, session, and queue, but no visible unencrypted package-registry section.
  • CUST-WP-0011 recorded Docker login/push receiving HTTP 404 from /v2/. Runtime inspection found no [packages] section in the live Gitea app.ini.

Safety Contract

  • Do not commit decrypted Helm values or secrets.
  • Take a Gitea backup or verify the most recent backup before changing the live Helm release.
  • Preserve Git hosting behavior: clone, push, login, and repository browsing must remain healthy after any registry change.
  • Do not broaden public exposure beyond the current Gitea exposure model.
  • If package storage/backups require platform changes, pause and create or link a railiance-platform task before changing S3 resources.
  • If /v2/ routing requires ingress-controller or NodePort changes, pause and create or link a railiance-cluster task before changing S2 resources.

Target State

  • Gitea package registry is globally enabled.
  • Gitea container package uploads are allowed with an explicit size policy.
  • /v2/ reaches Gitea and returns an OCI registry authentication challenge rather than a generic 404.
  • Docker can log in with a package-capable personal access token.
  • The State Hub image can be tagged, pushed, pulled, and referenced by a future cluster deployment.
  • The chosen registry URL and image naming convention are documented for downstream workplans.

Tasks

T01 — Inventory current registry and routing state

id: RAIL-AP-WP-0001-T01
status: done
priority: high
state_hub_task_id: "30075930-6585-465d-9b8f-1c5f2304632d"

Confirm the live Gitea registry state before changing Helm values.

Checks:

  • Confirm the active Helm release, chart version, namespace, and values source.
  • Inspect live Gitea app.ini for [packages], [repository], ROOT_URL, and any package or repository-unit settings.
  • Check GET /v2/ through each expected access path: service, NodePort or tunnel, and any ingress hostname.
  • Record the current response codes and headers for /v2/.
  • Identify the registry hostname that Docker and Kubernetes should use.

Done when: the workplan records whether the blocker is app config, route config, TLS/trust, authentication, or a combination.


T02 — Enable Gitea package and container registry config

id: RAIL-AP-WP-0001-T02
status: blocked
priority: high
state_hub_task_id: "e4136a4a-7730-47fe-bf64-315a513a3d8b"

Update helm/gitea-values.sops.yaml through sops so the generated Gitea app.ini enables packages and permits container uploads.

Expected app configuration:

[packages]
ENABLED = true
LIMIT_SIZE_CONTAINER = -1

Also verify repository package units are not globally disabled:

[repository]
DISABLED_REPO_UNITS =

If the chart values require YAML nesting, express those settings under the existing gitea.config tree without exposing decrypted secrets in Git.

Done when: a dry-rendered or live-inspected app.ini includes the package registry settings and no decrypted secret material was committed.


T03 — Ensure /v2/ reaches the Gitea registry handler

id: RAIL-AP-WP-0001-T03
status: done
priority: high
state_hub_task_id: "21c503be-12c7-411c-a82c-f738536cc114"

Make the OCI registry endpoint reachable at the root /v2/ path for the chosen registry host.

Validation:

  • curl -i https://<gitea-host>/v2/ should return the expected registry auth challenge or an auth-related response, not a generic 404.
  • Docker must not be pointed at a sub-path registry URL; the registry name is the host, and /v2/ is fixed by the OCI distribution API.
  • If Gitea is served through a sub-path, route root-level /v2/ to the Gitea service as required by Docker-compatible registries.

Boundary note: Gitea Helm ingress/service settings belong here. Ingress controller or cluster network changes belong in railiance-cluster.

Done when: /v2/ is routed correctly through the intended operator and cluster access paths.


T04 — Prove Docker login, push, and pull

id: RAIL-AP-WP-0001-T04
status: done
priority: high
state_hub_task_id: "5ffd7515-384b-4a11-9b5e-141197d1b985"

Use a Gitea user or bot personal access token with package read/write permissions to prove the registry workflow.

Smoke sequence:

docker login <gitea-host>
docker tag state-hub:local <gitea-host>/coulomb/state-hub:<tag>
docker push <gitea-host>/coulomb/state-hub:<tag>
docker pull <gitea-host>/coulomb/state-hub:<tag>

Then verify pull behavior from the cluster node runtime or a disposable Kubernetes pod, including TLS trust and private-registry credentials if the package is private.

Done when: the State Hub image can be pushed and pulled by both the operator workstation and the Railiance cluster runtime.

Done (2026-05-19):

  • Authenticated with docker login gitea.coulomb.social -u tegwick using the GITEA_API_TOKEN env (token owned by user tegwick, Bernd Worsch).
  • Pushed gitea.coulomb.social/coulomb/state-hub:6186a99 and :latest from the locally built state-hub:local image.
  • Image digest: sha256:039d29654ccb3754c6ecdbe497c6364bbd8452edcdcb7fa937dd9debf5b734ff.
  • Cluster-side pull verified via kubectl run sh-pull-test --image=gitea.coulomb.social/coulomb/state-hub:6186a99: pod reached Running in ~5s, image size 106 MB, no imagePullSecret required (coulomb org packages are public by default).
  • The same token + workflow was independently exercised pushing vergabe-teilnahme:483a4df under RAILIANCE-WP-0002-T03 — confirming the registry is fully usable for any S5 workload.

T05 — Document registry handoff for State Hub deployment

id: RAIL-AP-WP-0001-T05
status: done
priority: medium
state_hub_task_id: "55c2fd0c-ee6b-4524-8022-f21d6e9e046f"

Record the approved registry target and downstream handoff details.

Expected output:

  • Registry host and owner/image naming convention.
  • State Hub image tag used for the successful smoke test.
  • Whether images are public or private.
  • Required Kubernetes imagePullSecret name or creation command if private.
  • Link back to CUST-WP-0011 and its container image provenance.

Done when: State Hub cluster deployment work can consume the image without rediscovering registry naming, auth, or TLS requirements.


T06 — Capture backup and retention implications

id: RAIL-AP-WP-0001-T06
status: blocked
priority: medium
state_hub_task_id: "d5734ef1-d710-458c-b569-034f03a50bd8"

Confirm how Gitea package data is stored and backed up once container images are published.

Checks:

  • Identify whether package blobs live on the existing Gitea persistent volume or another configured storage backend.
  • Confirm the current backup process includes package data.
  • Decide whether image retention or cleanup policy is needed before publishing many tags.
  • If storage or backups need S3/platform changes, create a follow-up railiance-platform workplan or task.

Done when: package data durability is understood and no hidden storage gap is introduced by enabling the registry.

Implementation Log

2026-05-15 — Inventory and S5 routing update

T01 findings:

  • Active Kubernetes context: default.
  • Live Helm release metadata is stored in namespace default as revisions sh.helm.release.v1.gitea.v1 through v6.
  • Live deployment labels report chart gitea-12.5.0, app version 1.25.4, image docker.gitea.com/gitea:1.25.4-rootless.
  • Live Gitea service is default/gitea, type NodePort, port 3000:32166/TCP.
  • default/gitea pod app.ini has server ROOT_URL = http://gitea.coulomb.social, SSH_DOMAIN = gitea.coulomb.social, and DOMAIN = gitea.coulomb.social.
  • No [packages] section was found in the inspected live app.ini output, but the application handler is active: pod-local /v2/ and http://92.205.130.254:32166/v2/ both returned OCI registry 401 Unauthorized with Docker-Distribution-Api-Version: registry/2.0.
  • http://gitea.coulomb.social/v2/ and https://gitea.coulomb.social/v2/ returned generic 404, so the immediate blocker is public hostname routing. A secondary cleanup is updating ROOT_URL to https://gitea.coulomb.social/ so future auth challenges use the TLS endpoint.

T02 status:

  • SOPS editing was attempted with sops 3.9.0, matching the file metadata.
  • The local age identity required by helm/gitea-values.sops.yaml was not available at the default path, so encrypted Helm values were not changed.
  • Once the age identity is available, apply these non-secret app config values:
sops set helm/gitea-values.sops.yaml '["gitea"]["config"]["packages"]["ENABLED"]' 'true'
sops set helm/gitea-values.sops.yaml '["gitea"]["config"]["packages"]["LIMIT_SIZE_CONTAINER"]' '-1'
sops set helm/gitea-values.sops.yaml '["gitea"]["config"]["repository"]["DISABLED_REPO_UNITS"]' '""'
sops set helm/gitea-values.sops.yaml '["gitea"]["config"]["server"]["ROOT_URL"]' '"https://gitea.coulomb.social/"'

T03 implementation:

  • Added manifests/gitea-ingress.yaml, a Traefik/cert-manager ingress for only gitea.coulomb.social/v2* to the existing default/gitea service.
  • Added make gitea-ingress-deploy.
  • Updated Makefile variables so the default Gitea namespace matches the live release namespace default; this avoids accidentally deploying a parallel gitea namespace release while the live release remains in default.
  • Applied the ingress to the live cluster.
  • Cert-manager issued default/gitea-tls.
  • http://gitea.coulomb.social/v2/ now returns 401 Unauthorized with Docker-Distribution-Api-Version: registry/2.0.
  • https://gitea.coulomb.social/v2/ now returns 401 Unauthorized with Docker-Distribution-Api-Version: registry/2.0 and a TLS token realm.

T04 blocker:

  • Docker is available locally, but no Gitea personal access token was present in this session. Login, push, pull, and cluster runtime pull remain blocked on a package-capable token and the T02/T03 deployment.

T05 handoff:

  • Registry host: gitea.coulomb.social.
  • Image naming convention: gitea.coulomb.social/coulomb/state-hub:<tag>.
  • Handoff notes and imagePullSecret command are documented in docs/gitea-container-registry.md.
  • This links back to CUST-WP-0011, whose local image provenance is state-hub:local.

T06 findings:

  • Live Gitea package data is expected to use the existing /data mount backed by PVC default/gitea-shared-storage (10Gi, local-path) unless package storage is separately configured later.
  • No Kubernetes CronJob backup resources were present in the live cluster inventory. Backup coverage for gitea-shared-storage needs operator confirmation or a railiance-platform follow-up before publishing many tags.

Completion Criteria

This workplan is complete when:

  1. Gitea's container registry is enabled through governed Helm values.
  2. /v2/ is reachable at the chosen registry host.
  3. state-hub:local has been pushed as <gitea-host>/coulomb/state-hub:<tag>.
  4. The pushed image can be pulled from the Railiance cluster runtime.
  5. Registry auth, TLS, naming, and backup/retention notes are documented.

Notes

The future Forgejo migration should inherit the lessons from this workplan: registry package scope, /v2/ routing, package data backups, and cluster image pull credentials. If Forgejo lands before this plan starts, close this workplan as superseded and move the tasks under RAIL-HO-WP-0005 / the appropriate S5 Forgejo workplan.