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>
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.Makefiletargetgitea-deploy— applies the Gitea Helm release.Makefiletargetgitea-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.mdstates that Gitea Helm values are owned here and that Gitea is the active git hosting platform for Railiance and Custodian repos.railiance-apps/Makefiledeploys Gitea viahelm/gitea-values.sops.yamlinto thegiteanamespace.helm/gitea-values.sops.yamlcurrently contains Gitea app config sections such asserver,database,cache,session, andqueue, but no visible unencrypted package-registry section.CUST-WP-0011recorded Docker login/push receiving HTTP 404 from/v2/. Runtime inspection found no[packages]section in the live Giteaapp.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-platformtask before changing S3 resources. - If
/v2/routing requires ingress-controller or NodePort changes, pause and create or link arailiance-clustertask 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.inifor[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 tegwickusing theGITEA_API_TOKENenv (token owned by usertegwick, Bernd Worsch). - Pushed
gitea.coulomb.social/coulomb/state-hub:6186a99and:latestfrom the locally builtstate-hub:localimage. - Image digest:
sha256:039d29654ccb3754c6ecdbe497c6364bbd8452edcdcb7fa937dd9debf5b734ff. - Cluster-side pull verified via
kubectl run sh-pull-test --image=gitea.coulomb.social/coulomb/state-hub:6186a99: pod reachedRunningin ~5s, image size 106 MB, noimagePullSecretrequired (coulomborg packages are public by default). - The same token + workflow was independently exercised pushing
vergabe-teilnahme:483a4dfunderRAILIANCE-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
imagePullSecretname or creation command if private. - Link back to
CUST-WP-0011and 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-platformworkplan 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
defaultas revisionssh.helm.release.v1.gitea.v1throughv6. - Live deployment labels report chart
gitea-12.5.0, app version1.25.4, imagedocker.gitea.com/gitea:1.25.4-rootless. - Live Gitea service is
default/gitea, typeNodePort, port3000:32166/TCP. default/giteapod app.ini has serverROOT_URL = http://gitea.coulomb.social,SSH_DOMAIN = gitea.coulomb.social, andDOMAIN = gitea.coulomb.social.- No
[packages]section was found in the inspected live app.ini output, but the application handler is active: pod-local/v2/andhttp://92.205.130.254:32166/v2/both returned OCI registry401 UnauthorizedwithDocker-Distribution-Api-Version: registry/2.0. http://gitea.coulomb.social/v2/andhttps://gitea.coulomb.social/v2/returned generic404, so the immediate blocker is public hostname routing. A secondary cleanup is updatingROOT_URLtohttps://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.yamlwas 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 onlygitea.coulomb.social/v2*to the existingdefault/giteaservice. - Added
make gitea-ingress-deploy. - Updated Makefile variables so the default Gitea namespace matches the live
release namespace
default; this avoids accidentally deploying a parallelgiteanamespace release while the live release remains indefault. - Applied the ingress to the live cluster.
- Cert-manager issued
default/gitea-tls. http://gitea.coulomb.social/v2/now returns401 UnauthorizedwithDocker-Distribution-Api-Version: registry/2.0.https://gitea.coulomb.social/v2/now returns401 UnauthorizedwithDocker-Distribution-Api-Version: registry/2.0and 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
imagePullSecretcommand are documented indocs/gitea-container-registry.md. - This links back to
CUST-WP-0011, whose local image provenance isstate-hub:local.
T06 findings:
- Live Gitea package data is expected to use the existing
/datamount backed by PVCdefault/gitea-shared-storage(10Gi,local-path) unless package storage is separately configured later. - No Kubernetes
CronJobbackup resources were present in the live cluster inventory. Backup coverage forgitea-shared-storageneeds operator confirmation or arailiance-platformfollow-up before publishing many tags.
Completion Criteria
This workplan is complete when:
- Gitea's container registry is enabled through governed Helm values.
/v2/is reachable at the chosen registry host.state-hub:localhas been pushed as<gitea-host>/coulomb/state-hub:<tag>.- The pushed image can be pulled from the Railiance cluster runtime.
- 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.