The same deployment as Flux, but client-side and with the value schema
in your hands: each release pushes the
Timoni module (CUE) to
oci://forgejo.lihnet.mallon.ie/eagraiclainne/timoni, defaulting to
that release's server image. No in-cluster operator.
Prerequisites
- A Kubernetes cluster and
kubectlpointed at it - timoni installed locally
- A Forgejo token with
package:read. Timoni reads the Docker credential store, sodocker login forgejo.lihnet.mallon.iecovers the module pull
Namespace & registry access
The pods pull the server image from the private registry, and the
module does not set imagePullSecrets — attach a pull secret
to the namespace's default ServiceAccount:
kubectl create namespace eagraiclainne
kubectl -n eagraiclainne create secret docker-registry gitea-registry-auth \
--docker-server=forgejo.lihnet.mallon.ie \
--docker-username=your-username \
--docker-password=your-token
kubectl -n eagraiclainne patch serviceaccount default \
-p '{"imagePullSecrets":[{"name":"gitea-registry-auth"}]}'
Storage
The module defaults to SQLite: a 1Gi PVC mounted at
/data, the server owning /data/eagraiclainne.db
and applying its schema on boot. Single replica, Recreate
rollouts. With that default there is nothing to do here — skip to
Values.
To run the PostgreSQL backend instead, set
database: driver: "postgres" in your values and stand up a
CloudNativePG cluster first —
the module binds to the generated eagraiclainne-db-rw Service
and eagraiclainne-db-app Secret by default:
# install the operator (version-specific manifest, pinned)
kubectl apply --server-side -f \
https://raw.githubusercontent.com/cloudnative-pg/cloudnative-pg/release-1.25/releases/cnpg-1.25.0.yaml
kubectl -n cnpg-system rollout status deployment/cnpg-controller-manager
# eagraiclainne-db-cluster.yaml
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: eagraiclainne-db
namespace: eagraiclainne
spec:
instances: 2
imageName: ghcr.io/cloudnative-pg/postgresql:17.2
bootstrap:
initdb:
database: eagraiclainne
owner: app
storage:
size: 1Gi
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
memory: 512Mi
kubectl apply -f eagraiclainne-db-cluster.yaml
kubectl -n eagraiclainne wait --for=condition=Ready cluster/eagraiclainne-db --timeout=300s
Values
The defaults deploy the released image on the SQLite PVC, with telemetry off (stdout exporters). The overlay is where you switch the storage engine, opt in to an OTLP collector, or pin the JWT secret outside the database — or apply with no values file at all and take every default:
cat > prod-values.cue <<'EOF'
values: {
// Optional: grow the sqlite PVC (default 1Gi), or switch engines
// entirely — "postgres" binds the CNPG names above instead.
// database: storage: "5Gi"
// database: driver: "postgres"
// Optional: export telemetry to your collector (see the install
// overview's Telemetry section). Left out, everything goes to stdout.
// config: otlp: { endpoint: "lgtm.observability:4317", insecure: true }
// Optional: pin the signing secret (32+ bytes). Left out, the server
// generates one on first boot and keeps it in the database.
// secret: jwtSecret: "a-real-32-byte-or-longer-secret-value!!"
}
EOF
The full schema lives in deploy/timoni/eagraiclainne — replicas, resources, service port, database secret name, timeouts.
Apply
timoni -n eagraiclainne apply eagraiclainne \
oci://forgejo.lihnet.mallon.ie/eagraiclainne/timoni \
--version v1.0.0 \
--values prod-values.cue
Verify
timoni -n eagraiclainne status eagraiclainne
kubectl -n eagraiclainne rollout status deployment/eagraiclainne
kubectl -n eagraiclainne port-forward svc/eagraiclainne 8080:8080 &
curl -sS http://localhost:8080/ | head -c 200
Then expose the Service through your ingress of choice and open it —
first sign-in takes it from
there. To upgrade, run apply again with the next
--version. Schema changes apply themselves when the new pod
boots.