Files
UmbraDatastore/k8s/base/04-worker-deployments.yaml
umbra audio cce2ce55dc Initial commit: UmbraDatastore configuration and deployment scripts
- 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
2026-10-31 19:47:27 -07:00

339 lines
9.1 KiB
YAML

# Copyright 2026 Umbra Tools (umbratools.com)
# SPDX-License-Identifier: Apache-2.0
---
# ServiceAccount for workers
apiVersion: v1
kind: ServiceAccount
metadata:
name: umbratrans-worker
namespace: umbratrans
labels:
app: umbratrans-worker
---
# Role for workers
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: umbratrans-worker
namespace: umbratrans
rules:
- apiGroups: [""]
resources: ["pods", "services", "configmaps", "secrets"]
verbs: ["get", "list", "watch"]
- apiGroups: ["batch"]
resources: ["jobs", "cronjobs"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
- apiGroups: ["postgresql.cnpg.io"]
resources: ["clusters", "backups"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: umbratrans-worker
namespace: umbratrans
subjects:
- kind: ServiceAccount
name: umbratrans-worker
namespace: umbratrans
roleRef:
kind: Role
name: umbratrans-worker
apiGroup: rbac.authorization.k8s.io
---
# Secret for worker configuration
apiVersion: v1
kind: Secret
metadata:
name: umbratrans-worker-config
namespace: umbratrans
type: Opaque
stringData:
UMBRA_ENV: "production"
UMBRATRANS_REPOSITORY: "postgres"
UMBRATRANS_PRODUCTIONS_ROOT: "/mnt/productions"
UMBRATRANS_ALLOWED_HOSTS: "umbratrans.bdmurphy.me"
OLLAMA_BASE_URL: "http://ollama:11434/v1"
# UMBRATRANS_DATABASE_DSN: from umbratrans-db-credentials
---
# Deployment for Translation Workers
apiVersion: apps/v1
kind: Deployment
metadata:
name: umbratrans-worker-translation
namespace: umbratrans
labels:
app: umbratrans-worker-translation
component: worker
workload: translation
spec:
replicas: 3
selector:
matchLabels:
app: umbratrans-worker-translation
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
template:
metadata:
labels:
app: umbratrans-worker-translation
component: worker
workload: translation
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "9090"
prometheus.io/path: "/metrics"
spec:
serviceAccountName: umbratrans-worker
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
# Node affinity for GPU nodes
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: nvidia.com/gpu.present
operator: In
values: ["true"]
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: workload
operator: In
values: ["translation"]
tolerations:
- key: "nvidia.com/gpu"
operator: "Exists"
effect: "NoSchedule"
containers:
- name: worker
image: umbratrans-worker:latest
imagePullPolicy: IfNotPresent
command: ["python", "-m", "umbratrans_web.cli", "worker", "translation"]
envFrom:
- secretRef:
name: umbratrans-worker-config
- secretRef:
name: umbratrans-db-credentials
- secretRef:
name: umbratrans-secrets
volumeMounts:
- name: productions
mountPath: /mnt/productions
- name: artifacts
mountPath: /mnt/artifacts
- name: tmp
mountPath: /tmp
resources:
requests:
memory: "2Gi"
cpu: "2000m"
nvidia.com/gpu: "1"
limits:
memory: "4Gi"
cpu: "4000m"
nvidia.com/gpu: "1"
livenessProbe:
exec:
command: ["python", "-c", "import psycopg; psycopg.connect('$UMBRATRANS_DATABASE_DSN', connect_timeout=3).close()"]
initialDelaySeconds: 30
periodSeconds: 60
timeoutSeconds: 10
failureThreshold: 3
readinessProbe:
exec:
command: ["python", "-c", "import psycopg; psycopg.connect('$UMBRATRANS_DATABASE_DSN', connect_timeout=3).close()"]
initialDelaySeconds: 10
periodSeconds: 30
timeoutSeconds: 5
failureThreshold: 3
volumes:
- name: productions
persistentVolumeClaim:
claimName: umbratrans-productions
- name: artifacts
persistentVolumeClaim:
claimName: umbratrans-artifacts
- name: tmp
emptyDir:
sizeLimit: 2Gi
---
# HorizontalPodAutoscaler for translation workers
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: umbratrans-worker-translation
namespace: umbratrans
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: umbratrans-worker-translation
minReplicas: 1
maxReplicas: 20
metrics:
- type: External
external:
metric:
name: umbratrans_translation_queue_depth
target:
type: AverageValue
averageValue: "10"
behavior:
scaleDown:
stabilizationWindowSeconds: 600
scaleUp:
stabilizationWindowSeconds: 60
---
# Deployment for Audio Workers
apiVersion: apps/v1
kind: Deployment
metadata:
name: umbratrans-worker-audio
namespace: umbratrans
labels:
app: umbratrans-worker-audio
component: worker
workload: audio
spec:
replicas: 2
selector:
matchLabels:
app: umbratrans-worker-audio
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
app: umbratrans-worker-audio
component: worker
workload: audio
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "9090"
prometheus.io/path: "/metrics"
spec:
serviceAccountName: umbratrans-worker
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: nvidia.com/gpu.present
operator: In
values: ["true"]
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: workload
operator: In
values: ["audio"]
tolerations:
- key: "nvidia.com/gpu"
operator: "Exists"
effect: "NoSchedule"
containers:
- name: worker
image: umbratrans-worker:latest
imagePullPolicy: IfNotPresent
command: ["python", "-m", "umbratrans_web.cli", "worker", "audio"]
envFrom:
- secretRef:
name: umbratrans-worker-config
- secretRef:
name: umbratrans-db-credentials
- secretRef:
name: umbratrans-secrets
volumeMounts:
- name: productions
mountPath: /mnt/productions
- name: artifacts
mountPath: /mnt/artifacts
- name: tmp
mountPath: /tmp
resources:
requests:
memory: "4Gi"
cpu: "2000m"
nvidia.com/gpu: "1"
limits:
memory: "8Gi"
cpu: "4000m"
nvidia.com/gpu: "1"
livenessProbe:
exec:
command: ["python", "-c", "import psycopg; psycopg.connect('$UMBRATRANS_DATABASE_DSN', connect_timeout=3).close()"]
initialDelaySeconds: 30
periodSeconds: 60
timeoutSeconds: 10
failureThreshold: 3
readinessProbe:
exec:
command: ["python", "-c", "import psycopg; psycopg.connect('$UMBRATRANS_DATABASE_DSN', connect_timeout=3).close()"]
initialDelaySeconds: 10
periodSeconds: 30
timeoutSeconds: 5
failureThreshold: 3
volumes:
- name: productions
persistentVolumeClaim:
claimName: umbratrans-productions
- name: artifacts
persistentVolumeClaim:
claimName: umbratrans-artifacts
- name: tmp
emptyDir:
sizeLimit: 4Gi
---
# HorizontalPodAutoscaler for audio workers
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: umbratrans-worker-audio
namespace: umbratrans
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: umbratrans-worker-audio
minReplicas: 1
maxReplicas: 10
metrics:
- type: External
external:
metric:
name: umbratrans_audio_queue_depth
target:
type: AverageValue
averageValue: "5"
behavior:
scaleDown:
stabilizationWindowSeconds: 900
scaleUp:
stabilizationWindowSeconds: 120