- Database deployment script (scripts/deploy-database.sh) - Kubernetes manifests for CNPG PostgreSQL cluster (k8s/base/) - Documentation (docs/DEPLOYMENT_GUIDE.md, DATASTORE_SPEC.md, INTEGRATION_SPEC.md) - README with architecture overview and operations guide
285 lines
6.9 KiB
YAML
285 lines
6.9 KiB
YAML
# Copyright 2026 Umbra Tools (umbratools.com)
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
---
|
|
# ServiceAccount for web
|
|
apiVersion: v1
|
|
kind: ServiceAccount
|
|
metadata:
|
|
name: umbratrans-web
|
|
namespace: umbratrans
|
|
labels:
|
|
app: umbratrans-web
|
|
|
|
---
|
|
# Role for web (minimal permissions)
|
|
apiVersion: rbac.authorization.k8s.io/v1
|
|
kind: Role
|
|
metadata:
|
|
name: umbratrans-web
|
|
namespace: umbratrans
|
|
rules:
|
|
- apiGroups: [""]
|
|
resources: ["pods", "services", "configmaps"]
|
|
verbs: ["get", "list", "watch"]
|
|
- apiGroups: ["postgresql.cnpg.io"]
|
|
resources: ["clusters", "backups"]
|
|
verbs: ["get", "list", "watch"]
|
|
|
|
---
|
|
apiVersion: rbac.authorization.k8s.io/v1
|
|
kind: RoleBinding
|
|
metadata:
|
|
name: umbratrans-web
|
|
namespace: umbratrans
|
|
subjects:
|
|
- kind: ServiceAccount
|
|
name: umbratrans-web
|
|
namespace: umbratrans
|
|
roleRef:
|
|
kind: Role
|
|
name: umbratrans-web
|
|
apiGroup: rbac.authorization.k8s.io
|
|
|
|
---
|
|
# ConfigMap for static files (served by web)
|
|
apiVersion: v1
|
|
kind: ConfigMap
|
|
metadata:
|
|
name: umbratrans-static
|
|
namespace: umbratrans
|
|
labels:
|
|
app: umbratrans-web
|
|
data:
|
|
# Static files are built into the image, this is for runtime config
|
|
nginx.conf: |
|
|
# Not used - FastAPI serves static files directly
|
|
|
|
---
|
|
# Secret for web configuration (non-sensitive)
|
|
apiVersion: v1
|
|
kind: Secret
|
|
metadata:
|
|
name: umbratrans-web-config
|
|
namespace: umbratrans
|
|
type: Opaque
|
|
stringData:
|
|
UMBRA_ENV: "production"
|
|
UMBRATRANS_REPOSITORY: "postgres"
|
|
UMBRATRANS_PRODUCTIONS_ROOT: "/mnt/productions"
|
|
UMBRATRANS_STATIC_ROOT: "/app/web"
|
|
UMBRATRANS_ALLOWED_HOSTS: "umbratrans.bdmurphy.me,localhost"
|
|
UMBRATRANS_VERIFICATION_BASE_URL: "https://umbratrans.bdmurphy.me"
|
|
UMBRATRANS_COOKIE_SECURE: "true"
|
|
UMBRATRANS_REQUIRE_CSRF: "true"
|
|
UMBRATRANS_MAILER: "smtp"
|
|
UMBRATRANS_SMTP_HOST: "smtp.example.com"
|
|
UMBRATRANS_SMTP_PORT: "587"
|
|
UMBRATRANS_SMTP_USERNAME: "umbra@example.com"
|
|
UMBRATRANS_SMTP_SENDER: "umbratrans@umbra.example.com"
|
|
UMBRATRANS_SMTP_STARTTLS: "true"
|
|
# Sensitive values in separate secret
|
|
# UMBRATRANS_DATABASE_DSN: from umbratrans-db-credentials
|
|
# UMBRATRANS_SMTP_PASSWORD: from umbratrans-smtp
|
|
# UMBRATRANS_TOKEN_PEPPER: from umbratrans-secrets
|
|
|
|
---
|
|
# Deployment for web API + UI
|
|
apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: umbratrans-web
|
|
namespace: umbratrans
|
|
labels:
|
|
app: umbratrans-web
|
|
component: web
|
|
spec:
|
|
replicas: 2
|
|
selector:
|
|
matchLabels:
|
|
app: umbratrans-web
|
|
strategy:
|
|
type: RollingUpdate
|
|
rollingUpdate:
|
|
maxSurge: 1
|
|
maxUnavailable: 0
|
|
template:
|
|
metadata:
|
|
labels:
|
|
app: umbratrans-web
|
|
component: web
|
|
annotations:
|
|
prometheus.io/scrape: "true"
|
|
prometheus.io/port: "8442"
|
|
prometheus.io/path: "/api/metrics"
|
|
spec:
|
|
serviceAccountName: umbratrans-web
|
|
securityContext:
|
|
runAsNonRoot: true
|
|
runAsUser: 1000
|
|
runAsGroup: 1000
|
|
fsGroup: 1000
|
|
seccompProfile:
|
|
type: RuntimeDefault
|
|
initContainers:
|
|
- name: migrate
|
|
image: umbratrans-web:latest
|
|
imagePullPolicy: IfNotPresent
|
|
command: ["python", "-m", "umbratrans_web.cli", "migrate"]
|
|
envFrom:
|
|
- secretRef:
|
|
name: umbratrans-web-config
|
|
- secretRef:
|
|
name: umbratrans-db-credentials
|
|
- secretRef:
|
|
name: umbratrans-smtp
|
|
- secretRef:
|
|
name: umbratrans-secrets
|
|
resources:
|
|
requests:
|
|
memory: "128Mi"
|
|
cpu: "100m"
|
|
limits:
|
|
memory: "256Mi"
|
|
cpu: "500m"
|
|
containers:
|
|
- name: web
|
|
image: umbratrans-web:latest
|
|
imagePullPolicy: IfNotPresent
|
|
command: ["python", "-m", "umbratrans_web", "serve"]
|
|
args:
|
|
- "--host"
|
|
- "0.0.0.0"
|
|
- "--port"
|
|
- "8442"
|
|
- "--repository"
|
|
- "postgres"
|
|
- "--allow-production"
|
|
ports:
|
|
- name: http
|
|
containerPort: 8442
|
|
protocol: TCP
|
|
envFrom:
|
|
- secretRef:
|
|
name: umbratrans-web-config
|
|
- secretRef:
|
|
name: umbratrans-db-credentials
|
|
- secretRef:
|
|
name: umbratrans-smtp
|
|
- secretRef:
|
|
name: umbratrans-secrets
|
|
volumeMounts:
|
|
- name: productions
|
|
mountPath: /mnt/productions
|
|
readOnly: true
|
|
- name: artifacts
|
|
mountPath: /mnt/artifacts
|
|
readOnly: false
|
|
- name: tmp
|
|
mountPath: /tmp
|
|
livenessProbe:
|
|
httpGet:
|
|
path: /api/health
|
|
port: 8442
|
|
initialDelaySeconds: 15
|
|
periodSeconds: 30
|
|
timeoutSeconds: 5
|
|
failureThreshold: 3
|
|
readinessProbe:
|
|
httpGet:
|
|
path: /api/health
|
|
port: 8442
|
|
initialDelaySeconds: 5
|
|
periodSeconds: 10
|
|
timeoutSeconds: 3
|
|
failureThreshold: 3
|
|
startupProbe:
|
|
httpGet:
|
|
path: /api/health
|
|
port: 8442
|
|
initialDelaySeconds: 5
|
|
periodSeconds: 10
|
|
timeoutSeconds: 3
|
|
failureThreshold: 30
|
|
resources:
|
|
requests:
|
|
memory: "256Mi"
|
|
cpu: "250m"
|
|
limits:
|
|
memory: "512Mi"
|
|
cpu: "1000m"
|
|
volumes:
|
|
- name: productions
|
|
persistentVolumeClaim:
|
|
claimName: umbratrans-productions
|
|
- name: artifacts
|
|
persistentVolumeClaim:
|
|
claimName: umbratrans-artifacts
|
|
- name: tmp
|
|
emptyDir:
|
|
sizeLimit: 1Gi
|
|
|
|
---
|
|
# Service for web
|
|
apiVersion: v1
|
|
kind: Service
|
|
metadata:
|
|
name: umbratrans-web
|
|
namespace: umbratrans
|
|
labels:
|
|
app: umbratrans-web
|
|
spec:
|
|
selector:
|
|
app: umbratrans-web
|
|
ports:
|
|
- name: http
|
|
port: 80
|
|
targetPort: 8442
|
|
protocol: TCP
|
|
type: ClusterIP
|
|
|
|
---
|
|
# HorizontalPodAutoscaler for web
|
|
apiVersion: autoscaling/v2
|
|
kind: HorizontalPodAutoscaler
|
|
metadata:
|
|
name: umbratrans-web
|
|
namespace: umbratrans
|
|
spec:
|
|
scaleTargetRef:
|
|
apiVersion: apps/v1
|
|
kind: Deployment
|
|
name: umbratrans-web
|
|
minReplicas: 2
|
|
maxReplicas: 10
|
|
metrics:
|
|
- type: Resource
|
|
resource:
|
|
name: cpu
|
|
target:
|
|
type: Utilization
|
|
averageUtilization: 70
|
|
- type: Resource
|
|
resource:
|
|
name: memory
|
|
target:
|
|
type: Utilization
|
|
averageUtilization: 80
|
|
behavior:
|
|
scaleDown:
|
|
stabilizationWindowSeconds: 300
|
|
policies:
|
|
- type: Percent
|
|
value: 10
|
|
periodSeconds: 60
|
|
scaleUp:
|
|
stabilizationWindowSeconds: 60
|
|
policies:
|
|
- type: Percent
|
|
value: 50
|
|
periodSeconds: 60
|
|
- type: Pods
|
|
value: 2
|
|
periodSeconds: 60
|
|
selectPolicy: Max
|