diff --git a/k8s/switchboard.yaml b/k8s/switchboard.yaml new file mode 100644 index 0000000..9c65adb --- /dev/null +++ b/k8s/switchboard.yaml @@ -0,0 +1,240 @@ +# k8s/backend.yaml +# ============================================ +# Switchboard Core - Backend Deployment +# ============================================ +# Secrets: +# switchboard-db-credentials - POSTGRES_USER, POSTGRES_PASSWORD +# switchboard-admin - username, password, email (optional) +# switchboard-encryption - ENCRYPTION_KEY (required for v0.9.4+) +# +# PVC: +# switchboard-storage - Extraction scratch (always needed) +# Requires ReadWriteMany (RWX) — see k8s/storage-pvc.yaml +# With S3 backend, PVC is small (extraction status only, not blobs) +# +# Variables (Gitea CI): +# STORAGE_CLASS - StorageClass for PVC (e.g. "cephfs") +# STORAGE_SIZE - PVC size (e.g. "10Gi" for PVC, "1Gi" for S3) +# STORAGE_BACKEND - "pvc" or "s3" (default: "pvc") +# EXTRACTION_CONCURRENCY - Max concurrent extractions (default "3") +# EXTRACTOR_IMAGE - Sidecar image (LibreOffice headless) +# +# S3 secrets (Gitea Secrets — only when STORAGE_BACKEND=s3): +# S3_ENDPOINT - e.g. "http://minio:9000" or Ceph RGW URL +# S3_BUCKET - bucket name (must exist before deploy) +# S3_ACCESS_KEY - S3 access key +# S3_SECRET_KEY - S3 secret key +# +# Admin bootstrap: on every pod start, if SWITCHBOARD_ADMIN_* env vars +# are set, the backend upserts an admin user. Change the secret and +# restart the pod to reset the admin password. +# ============================================ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: switchboard-be${DEPLOY_SUFFIX} + namespace: ${NAMESPACE} + labels: + app: switchboard + component: backend + env: ${ENVIRONMENT} +spec: + replicas: ${BE_REPLICAS} + selector: + matchLabels: + app: switchboard + component: backend + env: ${ENVIRONMENT} + template: + metadata: + labels: + app: switchboard + component: backend + env: ${ENVIRONMENT} + spec: + containers: + - name: backend + image: ${IMAGE}:${IMAGE_TAG} + imagePullPolicy: Always + ports: + - containerPort: 8080 + name: http + env: + - name: ENVIRONMENT + value: "${ENVIRONMENT}" + - name: GIN_MODE + value: "${GIN_MODE}" + - name: PORT + value: "8080" + - name: BASE_PATH + value: "${BASE_PATH}" + - name: POSTGRES_HOST + value: "${POSTGRES_HOST}" + - name: POSTGRES_PORT + value: "${POSTGRES_PORT}" + - name: POSTGRES_DB + value: "${DB_NAME}" + - name: POSTGRES_USER + valueFrom: + secretKeyRef: + name: switchboard-db-credentials + key: POSTGRES_USER + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: switchboard-db-credentials + key: POSTGRES_PASSWORD + - name: DATABASE_URL + value: "postgres://$(POSTGRES_USER):$(POSTGRES_PASSWORD)@$(POSTGRES_HOST):$(POSTGRES_PORT)/$(POSTGRES_DB)?sslmode=disable" + - name: SWITCHBOARD_ADMIN_USERNAME + valueFrom: + secretKeyRef: + name: switchboard-admin + key: username + optional: true + - name: SWITCHBOARD_ADMIN_PASSWORD + valueFrom: + secretKeyRef: + name: switchboard-admin + key: password + optional: true + - name: SWITCHBOARD_ADMIN_EMAIL + valueFrom: + secretKeyRef: + name: switchboard-admin + key: email + optional: true + - name: SEED_USERS + valueFrom: + secretKeyRef: + name: switchboard-seed-users + key: users + optional: true + - name: ENCRYPTION_KEY + valueFrom: + secretKeyRef: + name: switchboard-encryption + key: ENCRYPTION_KEY + optional: true + # File storage (v0.12.0+) + - name: STORAGE_BACKEND + value: "${STORAGE_BACKEND}" + - name: STORAGE_PATH + value: "/data/storage" + - name: EXTRACTION_MODE + value: "sidecar" + - name: EXTRACTION_CONCURRENCY + value: "${EXTRACTION_CONCURRENCY}" + # S3 storage (optional — only used when STORAGE_BACKEND=s3) + - name: S3_ENDPOINT + valueFrom: + secretKeyRef: + name: switchboard-s3 + key: S3_ENDPOINT + optional: true + - name: S3_BUCKET + valueFrom: + secretKeyRef: + name: switchboard-s3 + key: S3_BUCKET + optional: true + - name: S3_ACCESS_KEY + valueFrom: + secretKeyRef: + name: switchboard-s3 + key: S3_ACCESS_KEY + optional: true + - name: S3_SECRET_KEY + valueFrom: + secretKeyRef: + name: switchboard-s3 + key: S3_SECRET_KEY + optional: true + - name: S3_REGION + valueFrom: + secretKeyRef: + name: switchboard-s3 + key: S3_REGION + optional: true + - name: S3_PREFIX + valueFrom: + secretKeyRef: + name: switchboard-s3 + key: S3_PREFIX + optional: true + - name: S3_FORCE_PATH_STYLE + value: "true" + volumeMounts: + - name: storage + mountPath: /data/storage + resources: + requests: + memory: "${MEMORY_REQUEST}" + cpu: "${CPU_REQUEST}" + limits: + memory: "${MEMORY_LIMIT}" + cpu: "${CPU_LIMIT}" + readinessProbe: + httpGet: + path: ${BASE_PATH}/health + port: 8080 + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 3 + failureThreshold: 3 + livenessProbe: + httpGet: + path: ${BASE_PATH}/health + port: 8080 + initialDelaySeconds: 10 + periodSeconds: 30 + timeoutSeconds: 5 + failureThreshold: 3 + + # Extractor sidecar (v0.12.0 Phase 2): + # Uncomment when switchboard-extractor image is built. + # See DESIGN-0.12.0.md — Phase 2: Extraction Pipeline. + # + # - name: extractor + # image: ${EXTRACTOR_IMAGE}:${IMAGE_TAG} + # imagePullPolicy: Always + # env: + # - name: STORAGE_PATH + # value: "/data/storage" + # - name: EXTRACTION_CONCURRENCY + # value: "${EXTRACTION_CONCURRENCY}" + # volumeMounts: + # - name: storage + # mountPath: /data/storage + # resources: + # requests: + # memory: "256Mi" + # cpu: "100m" + # limits: + # memory: "1Gi" + # cpu: "1000m" + + volumes: + - name: storage + persistentVolumeClaim: + claimName: switchboard-storage${DEPLOY_SUFFIX} +--- +apiVersion: v1 +kind: Service +metadata: + name: switchboard-be${DEPLOY_SUFFIX} + namespace: ${NAMESPACE} + labels: + app: switchboard + component: backend + env: ${ENVIRONMENT} +spec: + selector: + app: switchboard + component: backend + env: ${ENVIRONMENT} + ports: + - protocol: TCP + port: 8080 + targetPort: 8080 + name: http