Registry Publishing
Publishing a module means two things: pushing its image to a container registry, and listing that image in a module repo index so consumers can discover and install it. There is no chart publishing and no marketplace approval step — a repo index is just a static file.
The Pipeline
git tag vX.Y.Z
└─> GitHub workflow builds ghcr.io/<org>/<module>:<X.Y.Z> (v stripped)
└─> update module.yaml (add the version)
└─> regenerate components.yaml + values.yaml from the image
└─> tiny repo index . -o index.yaml
└─> consumers: tiny repo add / platform workspace repos
1. Tag a release
git tag v1.0.0
git push origin v1.0.0
The template's workflow (.github/workflows/release.yml) triggers on v[0-9]+.[0-9]+.[0-9]+ tags, strips the v (version=${GITHUB_REF_NAME#v}), and builds a multi-arch image:
ghcr.io/my-org/my-module:1.0.0 # bare version tag — this is what the index references
ghcr.io/my-org/my-module:latest
GHCR packages are private on first push. Make the package public once (repo → Packages → settings → visibility) so clusters can pull anonymously.
2. List it in a module repo
A module repo is a directory of per-module manifests plus a generated index.yaml, hosted as static files (GitHub Pages works). For each module:
my-module/
+-- module.yaml # identity + versions (hand-maintained)
+-- components.yaml # discovery info (generated from the image)
+-- values.yaml # rbac overlay (generated; only if the module declares RBAC)
module.yaml:
name: my-module
source: github.com/my-org/my-module
description: What it does
category: core
versions:
- version: 1.0.0
image: ghcr.io/my-org/my-module:1.0.0
chart: tinysystems/tinysystems-operator
chartVersion: 0.2.10
Generate the sibling files from the built image — never by hand:
# Discovery info (name/description/info/tags per component; no ports —
# a running node answers for those). Folded into the index so consumers
# can browse components before installing.
docker run --rm --entrypoint /manager ghcr.io/my-org/my-module:1.0.0 \
tools components-info --json > my-module/components.yaml
# RBAC overlay derived from registry.SetRequirements. Emits nothing if the
# module declares no RBAC — then there is no values.yaml at all.
docker run --rm --entrypoint /manager ghcr.io/my-org/my-module:1.0.0 \
tools rbac-values > my-module/values.yaml
3. Regenerate the index
tiny repo index . -o index.yaml
Like helm repo index: walks the directory for module.yaml files, folds in each sibling components.yaml, and writes a single index.yaml. Host the result anywhere static — no server, no platform involvement.
4. How consumers find it
With the tiny CLI:
tiny repo add myrepo https://my-org.github.io/modules/index.yaml
tiny repo update
tiny install my-module # or my-module@1.0.0
The public first-party index is https://tiny-systems.github.io/modules/index.yaml. On the platform, workspaces register their own module repos the same way — the workspace's repo list is what feeds its module catalog and installs. The platform is a consumer of indexes, not their owner.
Private Registries
If the image is not public, give the namespace a pull secret and reference it in the install values:
kubectl create secret docker-registry regcred \
--docker-server=ghcr.io \
--docker-username=myuser \
--docker-password=$GITHUB_TOKEN \
-n tinysystems
# values overlay
imagePullSecrets:
- name: regcred
Release Checklist
- Tests green;
tools rbac-check --strictpasses if the module touches the Kubernetes API. - Tag
vX.Y.Z, push; wait for the workflow to publishghcr.io/<org>/<module>:X.Y.Z. - First release only: make the GHCR package public.
- Add the version to
module.yaml; regeneratecomponents.yamlandvalues.yamlfrom the new image. tiny repo index . -o index.yaml; commit and publish the repo.- Verify:
tiny repo update && tiny install my-module@X.Y.Zon a test cluster.
Next Steps
- Versioning - Version strategy
- The Shared Operator Chart - How the image gets deployed
- Building Modules - Build process