WP-0011: deploy scaffolding for revenue.coulomb.social

Record T01 package (in-repo k8s/railiance, combined /ui + API app,
dedicated CNPG). Add Dockerfile, healthz, migration/bootstrap scripts,
kustomize manifests, ArgoCD Application (in railiance-platform), and
docs/deployment.md. T05 left open for operator DNS/OpenBao/image push.
This commit is contained in:
tegwick 2026-08-05 16:41:00 +02:00
parent 3064c0fe0c
commit 9e4e84f9ee
26 changed files with 691 additions and 142 deletions

View file

@ -0,0 +1,54 @@
# Idempotent founding binky admin credential (WP-0011-T01/T05).
# Safe to re-run: no-op when a binky credential already exists.
# Capture TOKEN= from job logs once on first bootstrap; store in a password
# manager — never commit.
apiVersion: batch/v1
kind: Job
metadata:
name: target-revenue-bootstrap-binky
namespace: target-revenue
labels:
app.kubernetes.io/name: target-revenue
app.kubernetes.io/component: bootstrap
annotations:
argocd.argoproj.io/sync-wave: "2"
argocd.argoproj.io/hook: Sync
argocd.argoproj.io/hook-delete-policy: BeforeHookCreation
spec:
ttlSecondsAfterFinished: 86400
backoffLimit: 2
template:
metadata:
labels:
app.kubernetes.io/name: target-revenue
app.kubernetes.io/component: bootstrap
spec:
restartPolicy: OnFailure
securityContext:
runAsNonRoot: true
runAsUser: 10001
fsGroup: 10001
containers:
- name: bootstrap
image: forgejo.coulomb.social/coulomb/target-revenue:0.1.0
imagePullPolicy: IfNotPresent
env:
- name: TRF_BOOTSTRAP_BINKY
value: "1"
- name: TRF_DATABASE_URL
valueFrom:
secretKeyRef:
name: target-revenue-runtime
key: TRF_MIGRATE_DATABASE_URL
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
resources:
requests:
cpu: 50m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mi

View file

@ -0,0 +1,36 @@
# Dedicated CNPG Cluster for Target Revenue Trust Service pilot data (WP-0011).
# Co-located in the target-revenue workload namespace so one ArgoCD Application
# can own the full stack (issue-core pattern + database).
#
# Pre-req secrets in namespace target-revenue (OpenBao ExternalSecret or
# operator-seeded): target-revenue-pg-credentials, target-revenue-trf-app-credentials.
# See docs/deployment.md.
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: target-revenue-pg
namespace: target-revenue
labels:
app.kubernetes.io/name: target-revenue-pg
app.kubernetes.io/part-of: target-revenue
app.kubernetes.io/component: database
annotations:
argocd.argoproj.io/sync-wave: "-2"
spec:
instances: 1
imageName: ghcr.io/cloudnative-pg/postgresql:16
storage:
size: 5Gi
bootstrap:
initdb:
database: target_revenue
owner: trf_owner
secret:
name: target-revenue-pg-credentials
managed:
roles:
- name: trf_app
ensure: present
login: true
passwordSecret:
name: target-revenue-trf-app-credentials

View file

@ -0,0 +1,78 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: target-revenue
namespace: target-revenue
labels:
app.kubernetes.io/name: target-revenue
app.kubernetes.io/part-of: target-revenue
annotations:
argocd.argoproj.io/sync-wave: "3"
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: target-revenue
template:
metadata:
labels:
app.kubernetes.io/name: target-revenue
app.kubernetes.io/part-of: target-revenue
spec:
securityContext:
runAsNonRoot: true
runAsUser: 10001
fsGroup: 10001
containers:
- name: target-revenue
image: forgejo.coulomb.social/coulomb/target-revenue:0.1.0
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 8000
env:
- name: TRF_DATABASE_URL
valueFrom:
secretKeyRef:
name: target-revenue-runtime
key: TRF_DATABASE_URL
- name: TRF_SIGNING_KEY_HEX
valueFrom:
secretKeyRef:
name: target-revenue-runtime
key: TRF_SIGNING_KEY_HEX
- name: TRF_CONTROL_PLANE_SECRET_KEY
valueFrom:
secretKeyRef:
name: target-revenue-runtime
key: TRF_CONTROL_PLANE_SECRET_KEY
readinessProbe:
httpGet:
path: /healthz
port: http
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
httpGet:
path: /healthz
port: http
initialDelaySeconds: 15
periodSeconds: 20
resources:
requests:
cpu: 50m
memory: 256Mi
limits:
cpu: 1000m
memory: 512Mi
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
volumeMounts:
- name: tmp
mountPath: /tmp
volumes:
- name: tmp
emptyDir: {}

View file

@ -0,0 +1,46 @@
# Runtime secrets for Trust Service + Control Plane (WP-0011).
#
# OpenBao path (platform KV v2): workloads/target-revenue/runtime-secrets
# Fields:
# TRF_SIGNING_KEY_HEX — 64 hex chars Ed25519 seed (32 bytes)
# TRF_CONTROL_PLANE_SECRET_KEY — session cookie signing secret
# TRF_DATABASE_URL — psycopg DSN for trf_app role
# TRF_MIGRATE_DATABASE_URL — DSN for trf_owner (migrate/bootstrap Jobs)
#
# Pre-reqs: ESO + ClusterSecretStore openbao (railiance-platform);
# OpenBao policy granting read of the path above.
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: target-revenue-runtime
namespace: target-revenue
labels:
app.kubernetes.io/name: target-revenue
app.kubernetes.io/part-of: target-revenue
annotations:
argocd.argoproj.io/sync-wave: "0"
spec:
refreshInterval: 1h
secretStoreRef:
name: openbao
kind: ClusterSecretStore
target:
name: target-revenue-runtime
creationPolicy: Owner
data:
- secretKey: TRF_SIGNING_KEY_HEX
remoteRef:
key: workloads/target-revenue/runtime-secrets
property: TRF_SIGNING_KEY_HEX
- secretKey: TRF_CONTROL_PLANE_SECRET_KEY
remoteRef:
key: workloads/target-revenue/runtime-secrets
property: TRF_CONTROL_PLANE_SECRET_KEY
- secretKey: TRF_DATABASE_URL
remoteRef:
key: workloads/target-revenue/runtime-secrets
property: TRF_DATABASE_URL
- secretKey: TRF_MIGRATE_DATABASE_URL
remoteRef:
key: workloads/target-revenue/runtime-secrets
property: TRF_MIGRATE_DATABASE_URL

View file

@ -0,0 +1,30 @@
# Public surface: revenue.coulomb.social (WP-0011).
# Trust Service API at / ; Control Plane UI at /ui/ (combined ASGI app).
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: target-revenue
namespace: target-revenue
labels:
app.kubernetes.io/name: target-revenue
app.kubernetes.io/part-of: target-revenue
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
argocd.argoproj.io/sync-wave: "4"
spec:
ingressClassName: traefik
rules:
- host: revenue.coulomb.social
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: target-revenue
port:
number: 80
tls:
- hosts:
- revenue.coulomb.social
secretName: target-revenue-tls

View file

@ -0,0 +1,15 @@
# Target Revenue Trust Service + Control Plane on Railiance (WP-0011).
# Synced by ArgoCD Application target-revenue (path k8s/railiance).
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: target-revenue
resources:
- cnpg-cluster.yaml
- externalsecret.yaml
- migrate-job.yaml
- bootstrap-job.yaml
- deployment.yaml
- service.yaml
- ingress.yaml

View file

@ -0,0 +1,52 @@
# One-shot migrations Job (WP-0011-T03). Re-run by deleting the Job or
# bumping the name suffix when a new migration ships.
apiVersion: batch/v1
kind: Job
metadata:
name: target-revenue-migrate
namespace: target-revenue
labels:
app.kubernetes.io/name: target-revenue
app.kubernetes.io/component: migrate
annotations:
argocd.argoproj.io/sync-wave: "1"
argocd.argoproj.io/hook: Sync
argocd.argoproj.io/hook-delete-policy: BeforeHookCreation
spec:
ttlSecondsAfterFinished: 86400
backoffLimit: 3
template:
metadata:
labels:
app.kubernetes.io/name: target-revenue
app.kubernetes.io/component: migrate
spec:
restartPolicy: OnFailure
securityContext:
runAsNonRoot: true
runAsUser: 10001
fsGroup: 10001
containers:
- name: migrate
image: forgejo.coulomb.social/coulomb/target-revenue:0.1.0
imagePullPolicy: IfNotPresent
env:
- name: TRF_RUN_MIGRATIONS
value: "1"
- name: TRF_DATABASE_URL
valueFrom:
secretKeyRef:
name: target-revenue-runtime
key: TRF_MIGRATE_DATABASE_URL
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
resources:
requests:
cpu: 50m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mi

View file

@ -0,0 +1,16 @@
apiVersion: v1
kind: Service
metadata:
name: target-revenue
namespace: target-revenue
labels:
app.kubernetes.io/name: target-revenue
app.kubernetes.io/part-of: target-revenue
spec:
type: ClusterIP
selector:
app.kubernetes.io/name: target-revenue
ports:
- name: http
port: 80
targetPort: http