fix(bp-gitea): switch to CNPG-managed postgres, drop bitnamilegacy subchart (Closes #584) (#586)

Squash merge: fix(bp-gitea) switch to CNPG-managed postgres (Closes #584)
This commit is contained in:
e3mrah 2026-05-02 15:18:49 +04:00 committed by GitHub
parent 942be6f58d
commit 8d2ba0495d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 233 additions and 53 deletions

View File

@ -39,10 +39,15 @@ spec:
# bp-gateway-api (issue #503): chart ships an HTTPRoute template;
# gateway.networking.k8s.io/v1 CRDs must be registered first.
- name: bp-gateway-api
# bp-cnpg (issue #584): chart ships a CNPG Cluster CR;
# postgresql.cnpg.io/v1 CRD must be registered before bp-gitea
# applies so the Capabilities gate in cnpg-cluster.yaml creates
# the Cluster rather than skipping it silently.
- name: bp-cnpg
chart:
spec:
chart: bp-gitea
version: 1.1.2
version: 1.2.0
sourceRef:
kind: HelmRepository
name: bp-gitea

View File

@ -84,7 +84,7 @@ spec:
chart:
spec:
chart: bp-harbor
version: 1.2.2
version: 1.2.3
sourceRef:
kind: HelmRepository
name: bp-harbor

View File

@ -36,10 +36,18 @@ spec:
targetNamespace: gitea
dependsOn:
- name: bp-keycloak
# bp-gateway-api (issue #503): chart ships an HTTPRoute template;
# gateway.networking.k8s.io/v1 CRDs must be registered first.
- name: bp-gateway-api
# bp-cnpg (issue #584): chart ships a CNPG Cluster CR;
# postgresql.cnpg.io/v1 CRD must be registered before bp-gitea
# applies so the Capabilities gate in cnpg-cluster.yaml creates
# the Cluster rather than skipping it silently.
- name: bp-cnpg
chart:
spec:
chart: bp-gitea
version: 1.1.2
version: 1.2.0
sourceRef:
kind: HelmRepository
name: bp-gitea
@ -59,11 +67,11 @@ spec:
values:
global:
sovereignFQDN: omantel.omani.works
# gitea hostname is gitea.omantel.omani.works. The DNS A record
# was already published by the Phase-0 catalyst-dns helper.
ingress:
hosts:
- host: gitea.omantel.omani.works
paths:
- path: /
pathType: Prefix
# Per-Sovereign overrides — issue #387:
# Cilium Gateway HTTPRoute exposes Gitea at gitea.omantel.omani.works.
# Upstream chart's own Ingress is disabled (gitea.ingress.enabled=false
# in platform/gitea/chart/values.yaml) — Sovereigns ingress through
# cilium-gateway from clusters/_template/bootstrap-kit/01-cilium.yaml.
# The DNS A record was already published by the Phase-0 catalyst-dns helper.
gateway:
host: gitea.omantel.omani.works

View File

@ -81,7 +81,7 @@ spec:
chart:
spec:
chart: bp-harbor
version: 1.2.2
version: 1.2.3
sourceRef:
kind: HelmRepository
name: bp-harbor

View File

@ -36,10 +36,18 @@ spec:
targetNamespace: gitea
dependsOn:
- name: bp-keycloak
# bp-gateway-api (issue #503): chart ships an HTTPRoute template;
# gateway.networking.k8s.io/v1 CRDs must be registered first.
- name: bp-gateway-api
# bp-cnpg (issue #584): chart ships a CNPG Cluster CR;
# postgresql.cnpg.io/v1 CRD must be registered before bp-gitea
# applies so the Capabilities gate in cnpg-cluster.yaml creates
# the Cluster rather than skipping it silently.
- name: bp-cnpg
chart:
spec:
chart: bp-gitea
version: 1.1.2
version: 1.2.0
sourceRef:
kind: HelmRepository
name: bp-gitea

View File

@ -81,7 +81,7 @@ spec:
chart:
spec:
chart: bp-harbor
version: 1.2.2
version: 1.2.3
sourceRef:
kind: HelmRepository
name: bp-harbor

View File

@ -3,12 +3,22 @@
#
# Verifies, in order:
# 1. `helm template` renders without error.
# 2. The render contains exactly 5 CustomResourceDefinitions:
# 2. The render contains exactly 10 CustomResourceDefinitions
# (experimental channel — required by Cilium 1.16.x which checks for
# TLSRoute at operator startup; standard channel only ships 5 CRDs and
# the cilium gateway controller stays disabled without TLSRoute):
# Standard channel (5):
# - gatewayclasses.gateway.networking.k8s.io
# - gateways.gateway.networking.k8s.io
# - grpcroutes.gateway.networking.k8s.io
# - httproutes.gateway.networking.k8s.io
# - referencegrants.gateway.networking.k8s.io
# Experimental-only (5):
# - backendlbpolicies.gateway.networking.k8s.io
# - backendtlspolicies.gateway.networking.k8s.io
# - tcproutes.gateway.networking.k8s.io
# - tlsroutes.gateway.networking.k8s.io
# - udproutes.gateway.networking.k8s.io
# 3. Each CRD carries `helm.sh/resource-policy: keep` so a Helm
# uninstall does NOT delete it (Gateway API CRDs are foundational —
# deleting them on uninstall would orphan every HTTPRoute on the

View File

@ -5,7 +5,7 @@ metadata:
labels:
catalyst.openova.io/section: pts-2-3-per-sovereign-supporting-services
spec:
version: 1.1.2
version: 1.2.0
card:
title: gitea
summary: Gitea — per-Sovereign Git server. Catalyst control plane. Hosts catalog (public Blueprint mirror), catalog-sovereign (Sovereign-curated private Blueprints), one Gitea Org per Catalyst Organization, and system (sovereign-admin scope).

View File

@ -1,6 +1,6 @@
apiVersion: v2
name: bp-gitea
version: 1.1.3
version: 1.2.0
description: |
Catalyst-curated Blueprint umbrella chart for Gitea. Depends on the
upstream `gitea` chart (dl.gitea.com) as a Helm subchart so

View File

@ -0,0 +1,65 @@
{{- /*
CNPG-managed Postgres cluster for Gitea.
Gitea requires PostgreSQL for its database (repositories, users, issues,
pull requests, etc.). bp-gitea ships this Cluster CR so the database is
provisioned by CNPG alongside the HelmRelease — no separate Helm release or
manual setup required. Mirrors the same pattern used by bp-harbor
(platform/harbor/chart/templates/cnpg-cluster.yaml).
The Cluster name defaults to `gitea-pg`; CNPG synthesises a `gitea-pg-app`
Secret that `templates/database-secret.yaml` mirrors via reflector into
`gitea-database-secret`, which the Gitea deployment reads for the DB password.
Capabilities gate: bp-cnpg ships the `postgresql.cnpg.io/v1` CRD. On a cold
install before bp-cnpg is reconciling, the apiserver rejects this Cluster.
The Capabilities check skips this template until the CRD is registered.
The Sovereign's bootstrap order MUST land bp-cnpg before bp-gitea.
*/}}
{{- if .Capabilities.APIVersions.Has "postgresql.cnpg.io/v1" }}
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: {{ .Values.postgres.cluster.name | default "gitea-pg" }}
namespace: {{ .Values.postgres.cluster.namespace | default .Release.Namespace }}
labels:
catalyst.openova.io/blueprint: bp-gitea
catalyst.openova.io/component: gitea
annotations:
# Allow the k8s-reflector (bp-reflector) to reflect the CNPG-generated
# `gitea-pg-app` Secret into the `gitea` namespace so that
# `gitea-database-secret` (templates/database-secret.yaml) gets the
# real password populated at runtime rather than empty on first install.
reflector.v1.k8s.emberstack.com/reflection-allowed: "true"
reflector.v1.k8s.emberstack.com/reflection-allowed-namespaces: {{ .Values.postgres.cluster.namespace | default .Release.Namespace | quote }}
spec:
instances: {{ .Values.postgres.cluster.instances | default 1 }}
imageName: ghcr.io/cloudnative-pg/postgresql:{{ .Values.postgres.cluster.pgVersion | default "16" }}
bootstrap:
initdb:
database: {{ .Values.postgres.cluster.database | default "gitea" | quote }}
owner: {{ .Values.postgres.cluster.owner | default "gitea" | quote }}
postgresql:
parameters:
max_connections: "100"
shared_buffers: "64MB"
effective_cache_size: "192MB"
work_mem: "4MB"
maintenance_work_mem: "64MB"
log_statement: "ddl"
log_min_duration_statement: "1000"
resources:
{{- toYaml .Values.postgres.cluster.resources | nindent 4 }}
storage:
size: {{ .Values.postgres.cluster.storageSize | default "5Gi" }}
storageClass: {{ .Values.postgres.cluster.storageClass | default "local-path" | quote }}
enableSuperuserAccess: true
monitoring:
enablePodMonitor: false
{{- end }}

View File

@ -0,0 +1,43 @@
{{- /*
Placeholder Secret that reflector (bp-reflector) populates from the CNPG-
generated `gitea-pg-app` Secret.
Gitea reads the database password from GITEA__database__PASSWD environment
variable. CNPG produces `gitea-pg-app` with a `password` key. This Secret
acts as the bridge: reflector copies all keys from `gitea-pg-app` into this
Secret including `password`, which the Gitea deployment references via
secretKeyRef.
Why not Helm `lookup`?
Helm `lookup` is evaluated only during `helm install` / `helm upgrade`
template rendering. On a fresh Sovereign, CNPG bootstraps the Cluster AFTER
the bp-gitea HelmRelease applies. The first Helm render finds `gitea-pg-app`
absent and writes an empty password. Reflector is event-driven: as soon as
`gitea-pg-app` is created (or rotated), the watch fires and this Secret is
updated — no operator action required.
Per docs/INVIOLABLE-PRINCIPLES.md #10 (credential hygiene): no plaintext
credentials appear in this committed template. The reflector copies bytes from
a live cluster Secret.
*/}}
apiVersion: v1
kind: Secret
metadata:
name: gitea-database-secret
namespace: {{ .Values.postgres.cluster.namespace | default .Release.Namespace }}
labels:
catalyst.openova.io/blueprint: bp-gitea
catalyst.openova.io/component: gitea
annotations:
# Reflector (bp-reflector) copies all keys from gitea-pg-app into this
# Secret. Gitea reads GITEA__database__PASSWD from the `password` key.
reflector.v1.k8s.emberstack.com/reflects: "{{ .Values.postgres.cluster.namespace | default .Release.Namespace }}/{{ .Values.postgres.cluster.name | default "gitea-pg" }}-app"
# Helm resource-policy keep — do not delete on helm uninstall (the
# Secret is independently managed by reflector after initial creation).
helm.sh/resource-policy: keep
type: Opaque
# Bootstrap empty data — reflector overwrites these within seconds of
# gitea-pg-app being created by CNPG. Empty values here prevent
# CreateContainerConfigError (secret key missing) during initial render.
data:
password: ""

View File

@ -33,6 +33,14 @@ gitea:
server:
DOMAIN: gitea.catalyst.local
ROOT_URL: https://gitea.catalyst.local
# Wire CNPG-managed Postgres (replaces bitnami subchart).
# Password is injected at runtime via additionalConfigFromEnvs below.
database:
DB_TYPE: postgres
HOST: gitea-pg-rw.gitea.svc.cluster.local:5432
NAME: gitea
USER: gitea
SSL_MODE: disable
# Gitea built-in metrics + ServiceMonitor — DEFAULT OFF.
#
# Per docs/INVIOLABLE-PRINCIPLES.md #4 and
@ -48,34 +56,27 @@ gitea:
enabled: false
serviceMonitor:
enabled: false
# Inject DB password from the reflector-managed gitea-database-secret.
# Reflector copies `gitea-pg-app` (CNPG-generated) into
# `gitea-database-secret`; the `password` key holds the postgres user
# password. GITEA__database__PASSWD overrides the empty value in
# gitea.config.database above.
additionalConfigFromEnvs:
- name: GITEA__database__PASSWD
valueFrom:
secretKeyRef:
name: gitea-database-secret
key: password
# Bitnami postgresql subchart DISABLED — bitnami/* and bitnamilegacy/*
# images are unavailable via the Harbor proxy_cache (DockerHub returns
# text/html for these namespaces — image pull fails with "unexpected media
# type text/html"). Replaced by bp-cnpg-managed Cluster
# (templates/cnpg-cluster.yaml + templates/database-secret.yaml), the
# same pattern used by bp-harbor. Fixes ImagePullBackOff on otech22.
postgresql-ha:
enabled: false
postgresql:
enabled: true
global:
postgresql:
auth:
username: gitea
database: gitea
# Bitnami evacuated docker.io/bitnami/postgresql tags around 2025-09;
# the chart's default 16.3.0-debian-12-r23 returns 404. bitnamilegacy
# is the frozen archive that still serves these tags. Same workaround
# as #191 for bp-keycloak. Long-term: cnpg subchart override.
image:
repository: bitnamilegacy/postgresql
tag: 16.3.0-debian-12-r23
# PostgreSQL exporter + ServiceMonitor + PrometheusRule — DEFAULT OFF.
metrics:
enabled: false
image:
repository: bitnamilegacy/postgres-exporter
serviceMonitor:
enabled: false
prometheusRule:
enabled: false
volumePermissions:
image:
repository: bitnamilegacy/os-shell
enabled: false
redis-cluster:
enabled: false
valkey-cluster:
@ -88,6 +89,31 @@ gitea:
ingress:
enabled: false
# ─── CNPG-managed Postgres cluster for Gitea ──────────────────────────────
# Per the Harbor pattern (templates/cnpg-cluster.yaml in bp-harbor), Gitea's
# postgres is provisioned by CNPG rather than the Bitnami subchart. The
# CNPG Cluster creates a `gitea-pg-app` Secret; database-secret.yaml uses
# reflector to mirror it into `gitea-database-secret`, which the Gitea
# deployment reads via a secretKeyRef for GITEA__database__PASSWD.
postgres:
cluster:
name: gitea-pg
# namespace defaults to .Release.Namespace (gitea)
namespace: ""
instances: 1
pgVersion: "16"
database: gitea
owner: gitea
storageSize: 5Gi
storageClass: local-path
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: 500m
memory: 512Mi
# ─── Catalyst HTTPRoute (Cilium Gateway API, issue #387) ──────────────────
# Replaces the upstream chart's networking.k8s.io/v1.Ingress on Sovereigns.
# Per-Sovereign overlay supplies `gateway.host` (e.g. git.<sovereign-fqdn>).

View File

@ -38,7 +38,7 @@ description: |
this Blueprint hard-depends on bp-cnpg + bp-cert-manager. The
earlier dependency on bp-seaweedfs is REMOVED (cloud-direct S3 path).
type: application
version: 1.2.2
version: 1.2.3
appVersion: "2.14.3"
keywords: [catalyst, blueprint, harbor, oci, registry, container]
maintainers:

View File

@ -11,14 +11,16 @@ key `HARBOR_DATABASE_PASSWORD` in the named Secret. CNPG produces
installs where the Cluster boots after the chart is applied)
Solution: use the k8s-reflector (bp-reflector, slot 05a) to copy
`harbor-pg-app` into this Secret via the `reflect-from-namespace/name`
annotation. The `reflect-allowed-namespaces` annotation on the source
Secret is set by the CNPG Cluster via the `cnpg-cluster.yaml` template's
extra annotations. Reflector propagates the full key set from `harbor-pg-app`
into `harbor-database-secret`, including `password`. Harbor core reads
`HARBOR_DATABASE_PASSWORD` from the secret — since reflector copies ALL keys,
we also explicitly alias it below via a second strategy using
`reflect-from-namespace/name` so the upstream key set arrives whole.
`harbor-pg-app` into this Secret via the `reflects` annotation. The
`reflection-allowed` annotations on the SOURCE Secret (`harbor-pg-app`)
are added at runtime by the `harbor-pg-app-annotator` post-install Job
(templates/cnpg-app-annotator-job.yaml), which polls until CNPG creates
the Secret then PATCHes the annotations in. Once the source carries
`reflection-allowed: true`, Reflector propagates the full key set from
`harbor-pg-app` into `harbor-database-secret`, including `password` and
`HARBOR_DATABASE_PASSWORD`. Harbor core reads `HARBOR_DATABASE_PASSWORD`
from the secret on the next CrashLoop retry — typically within seconds
of Reflector firing.
Why not Helm `lookup`?
Helm `lookup` is evaluated only during `helm install` / `helm upgrade`

View File

@ -57,6 +57,15 @@ slots:
name: bp-sealed-secrets
depends_on: [bp-cert-manager]
wave: present
- slot: 5a
name: bp-reflector
# emberstack/reflector — secret/configmap mirror controller (issue #543).
# Propagates ghcr-pull secret to every namespace so cross-namespace
# ImagePullBackOff gaps are eliminated. Slot 5a: after sealed-secrets,
# before spire. dependsOn bp-cert-manager (CRDs must exist).
# Used by bp-gitea + bp-harbor to propagate CNPG-generated pg-app Secrets.
depends_on: [bp-cert-manager]
wave: present
- slot: 6
name: bp-spire
depends_on: [bp-cert-manager]
@ -82,7 +91,9 @@ slots:
- slot: 10
name: bp-gitea
# bp-gateway-api dep (issue #503): chart ships an HTTPRoute template.
depends_on: [bp-keycloak, bp-gateway-api]
# bp-cnpg dep (issue #584): chart ships a CNPG Cluster CR; postgresql.cnpg.io/v1
# CRD must be registered before bp-gitea applies so Capabilities gate fires.
depends_on: [bp-keycloak, bp-gateway-api, bp-cnpg]
wave: present
- slot: 11
name: bp-powerdns
@ -91,7 +102,9 @@ slots:
wave: present
- slot: 12
name: bp-external-dns
depends_on: [bp-cert-manager, bp-powerdns]
# bp-reflector dep (issue #543): external-dns HTTPRoute uses reflector-mirrored
# ghcr-pull secret; reflector must be Ready before external-dns deploys.
depends_on: [bp-cert-manager, bp-powerdns, bp-reflector]
wave: present
- slot: 13
name: bp-catalyst-platform