Files
reactbin/specs/013-k8s-manifests/contracts/operator-deploy.md
agatha bf27c97deb Feat: Add Kubernetes manifests for k3s production deployment
Adds complete k8s/ manifest tree: Namespace, VaultAuth + VaultStaticSecret
CRDs (VSO secret sync from Vault KV v2), API and UI Deployments and Services,
nginx Ingress with cert-manager TLS, MinIO StatefulSet with PVC and init Job,
and Alembic init container on the API Deployment for automatic schema
migrations. Includes .yamllint.yml config and validate-k8s Makefile target.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-07 21:19:09 +00:00

2.6 KiB

Contract: Operator Deployment Interface

The manifests in k8s/ define the operator's deployment interface — the inputs required before applying and the observable outputs after applying.

Pre-deployment Prerequisites (Operator-supplied)

Prerequisite Details
Vault KV v2 secret at reactbin/api/config Must contain keys: DATABASE_URL, JWT_SECRET_KEY, OWNER_USERNAME, OWNER_PASSWORD, S3_ENDPOINT_URL, S3_BUCKET_NAME, S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY, API_BASE_URL
Vault KV v2 secret at reactbin/minio/credentials Must contain keys: MINIO_ROOT_USER, MINIO_ROOT_PASSWORD
Vault Kubernetes auth role A role in the Vault Kubernetes auth mount bound to the default service account in the reactbin namespace with read access to both paths above
VaultConnection resource Named default in the operator's VSO namespace pointing to the Vault server address
External PostgreSQL database A dedicated database and user created; DATABASE_URL in Vault reflects the credentials
DNS The production domain resolves to the cluster ingress IP
ClusterIssuer A cert-manager ClusterIssuer named letsencrypt-prod exists in the cluster
Image tags The operator substitutes the latest placeholder in k8s/api/deployment.yaml and k8s/ui/deployment.yaml with the real image tag before applying

Apply Command

# Substitute image tags
sed -i 's|reactbin-api:latest|reactbin-api:<tag>|g' k8s/api/deployment.yaml
sed -i 's|reactbin-ui:latest|reactbin-ui:<tag>|g' k8s/ui/deployment.yaml

# Apply all manifests
kubectl apply -f k8s/

Applying is idempotent — safe to re-run on every deployment.

Observable Outputs (Post-apply)

Resource Expected State
Namespace/reactbin Active
Deployment/api in reactbin 1/1 Ready (init container completes first)
Deployment/ui in reactbin 1/1 Ready
StatefulSet/minio in reactbin 1/1 Ready
Job/minio-init-bucket in reactbin Completed
Secret/api-env in reactbin Created by VSO, populated with all API env keys
Secret/minio-credentials in reactbin Created by VSO, populated with MinIO root keys
Certificate/reactbin-tls in reactbin Issued (may take up to 2 minutes on first apply)
Ingress/reactbin in reactbin Address populated with cluster ingress IP

Verification Commands

# All pods running
kubectl get pods -n reactbin

# API health
curl -sf https://<domain>/api/v1/health

# UI reachable
curl -sf https://<domain>/

# Docs correctly gated (should return 404)
curl -o /dev/null -w "%{http_code}" https://<domain>/docs