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>
This commit is contained in:
92
specs/013-k8s-manifests/quickstart.md
Normal file
92
specs/013-k8s-manifests/quickstart.md
Normal file
@@ -0,0 +1,92 @@
|
||||
# Quickstart: Kubernetes Production Deployment
|
||||
|
||||
## Before You Apply
|
||||
|
||||
1. Store API secrets in Vault at `reactbin/api/config` (KV v2):
|
||||
```
|
||||
DATABASE_URL = postgresql+asyncpg://reactbin:<pw>@<host>:5432/reactbin
|
||||
JWT_SECRET_KEY = <long-random-string>
|
||||
OWNER_USERNAME = <your-username>
|
||||
OWNER_PASSWORD = <your-password>
|
||||
S3_ENDPOINT_URL = http://minio.reactbin.svc.cluster.local:9000
|
||||
S3_BUCKET_NAME = reactbin
|
||||
S3_ACCESS_KEY_ID = <same as MINIO_ROOT_USER>
|
||||
S3_SECRET_ACCESS_KEY = <same as MINIO_ROOT_PASSWORD>
|
||||
API_BASE_URL = https://<your-domain>
|
||||
API_DOCS_ENABLED = false
|
||||
```
|
||||
|
||||
2. Store MinIO credentials in Vault at `reactbin/minio/credentials` (KV v2):
|
||||
```
|
||||
MINIO_ROOT_USER = <choose a strong username>
|
||||
MINIO_ROOT_PASSWORD = <choose a strong password>
|
||||
```
|
||||
|
||||
3. Create a Vault Kubernetes auth role bound to the `default` service account in the `reactbin` namespace with read access to both paths above.
|
||||
|
||||
4. Confirm DNS resolves to the cluster ingress IP and the `letsencrypt-prod` ClusterIssuer exists.
|
||||
|
||||
## Deploy
|
||||
|
||||
```bash
|
||||
# Substitute the real image tags
|
||||
sed -i 's|reactbin-api:latest|reactbin-api:v1.0.0|g' k8s/api/deployment.yaml
|
||||
sed -i 's|reactbin-ui:latest|reactbin-ui:v1.0.0|g' k8s/ui/deployment.yaml
|
||||
|
||||
# Apply everything
|
||||
kubectl apply -f k8s/
|
||||
```
|
||||
|
||||
## Verify
|
||||
|
||||
```bash
|
||||
# Watch pods come up (init container runs first on the API pod)
|
||||
kubectl get pods -n reactbin -w
|
||||
|
||||
# API health
|
||||
curl -sf https://<your-domain>/api/v1/health && echo "API OK"
|
||||
|
||||
# UI reachable
|
||||
curl -sf -o /dev/null -w "%{http_code}\n" https://<your-domain>/
|
||||
|
||||
# Docs correctly gated
|
||||
curl -o /dev/null -w "%{http_code}\n" https://<your-domain>/docs # → 404
|
||||
curl -o /dev/null -w "%{http_code}\n" https://<your-domain>/redoc # → 404
|
||||
|
||||
# Check migration init container ran
|
||||
kubectl logs -n reactbin -l app=api -c alembic-migrate
|
||||
```
|
||||
|
||||
## Scenario: Migration fails on deploy
|
||||
|
||||
```bash
|
||||
# Pod will be stuck in Init state
|
||||
kubectl get pods -n reactbin
|
||||
# NAME READY STATUS RESTARTS
|
||||
# api-xxx-yyy 0/1 Init:CrashLoopBackOff 2
|
||||
|
||||
# See why
|
||||
kubectl logs -n reactbin <pod-name> -c alembic-migrate
|
||||
|
||||
# Fix the issue (e.g. correct DATABASE_URL in Vault, wait for VSO to resync)
|
||||
# Then delete the pod to force a fresh rollout
|
||||
kubectl rollout restart deployment/api -n reactbin
|
||||
```
|
||||
|
||||
## Scenario: Update to a new image version
|
||||
|
||||
```bash
|
||||
kubectl set image deployment/api api=reactbin-api:v1.1.0 -n reactbin
|
||||
kubectl set image deployment/ui ui=reactbin-ui:v1.1.0 -n reactbin
|
||||
# Kubernetes rolls out new pods; init container runs migrations before traffic switches
|
||||
```
|
||||
|
||||
## Scenario: Restore after MinIO pod restart
|
||||
|
||||
MinIO uses a PersistentVolumeClaim. Pod restarts do not affect stored data. Verify:
|
||||
|
||||
```bash
|
||||
kubectl delete pod -n reactbin minio-0
|
||||
kubectl get pods -n reactbin -w # minio-0 restarts, PVC reattaches
|
||||
# Previously uploaded images should still be accessible via the API
|
||||
```
|
||||
Reference in New Issue
Block a user