- Update backend Dockerfile with PostgreSQL deps and entrypoint - Add entrypoint.sh with db/redis wait and auto-migration - Add /ready endpoint for Kubernetes readiness probe - Enhance /health endpoint with database and Redis status - Update k8s deployment with PostgreSQL and Redis services - Add proper secrets management for database credentials - Update k8s readiness probe to use /ready endpoint
485 lines
10 KiB
YAML
485 lines
10 KiB
YAML
# ============================================
|
|
# Document Translation API - Kubernetes Deployment
|
|
# ============================================
|
|
# Apply with: kubectl apply -f k8s/
|
|
|
|
apiVersion: v1
|
|
kind: Namespace
|
|
metadata:
|
|
name: translate-api
|
|
labels:
|
|
app: translate-api
|
|
|
|
---
|
|
# ConfigMap for application settings
|
|
apiVersion: v1
|
|
kind: ConfigMap
|
|
metadata:
|
|
name: translate-config
|
|
namespace: translate-api
|
|
data:
|
|
TRANSLATION_SERVICE: "ollama"
|
|
OLLAMA_BASE_URL: "http://ollama-service:11434"
|
|
OLLAMA_MODEL: "llama3"
|
|
MAX_FILE_SIZE_MB: "50"
|
|
RATE_LIMIT_REQUESTS_PER_MINUTE: "60"
|
|
RATE_LIMIT_TRANSLATIONS_PER_MINUTE: "10"
|
|
LOG_LEVEL: "INFO"
|
|
# Database and Redis URLs are in secrets for security
|
|
|
|
---
|
|
# Secret for sensitive data
|
|
apiVersion: v1
|
|
kind: Secret
|
|
metadata:
|
|
name: translate-secrets
|
|
namespace: translate-api
|
|
type: Opaque
|
|
stringData:
|
|
# CHANGE ALL THESE IN PRODUCTION!
|
|
ADMIN_USERNAME: "admin"
|
|
ADMIN_PASSWORD_HASH: "" # Use: echo -n 'yourpassword' | sha256sum
|
|
JWT_SECRET: "" # Generate with: openssl rand -hex 32
|
|
DATABASE_URL: "postgresql://translate:translate_secret@postgres-service:5432/translate_db"
|
|
REDIS_URL: "redis://redis-service:6379/0"
|
|
DEEPL_API_KEY: ""
|
|
OPENAI_API_KEY: ""
|
|
OPENROUTER_API_KEY: ""
|
|
STRIPE_SECRET_KEY: ""
|
|
STRIPE_WEBHOOK_SECRET: ""
|
|
|
|
---
|
|
# Backend Deployment
|
|
apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: backend
|
|
namespace: translate-api
|
|
labels:
|
|
app: backend
|
|
spec:
|
|
replicas: 2
|
|
selector:
|
|
matchLabels:
|
|
app: backend
|
|
template:
|
|
metadata:
|
|
labels:
|
|
app: backend
|
|
spec:
|
|
containers:
|
|
- name: backend
|
|
image: translate-api-backend:latest
|
|
imagePullPolicy: IfNotPresent
|
|
ports:
|
|
- containerPort: 8000
|
|
envFrom:
|
|
- configMapRef:
|
|
name: translate-config
|
|
- secretRef:
|
|
name: translate-secrets
|
|
resources:
|
|
requests:
|
|
memory: "512Mi"
|
|
cpu: "250m"
|
|
limits:
|
|
memory: "2Gi"
|
|
cpu: "1000m"
|
|
readinessProbe:
|
|
httpGet:
|
|
path: /ready
|
|
port: 8000
|
|
initialDelaySeconds: 10
|
|
periodSeconds: 10
|
|
failureThreshold: 3
|
|
livenessProbe:
|
|
httpGet:
|
|
path: /health
|
|
port: 8000
|
|
initialDelaySeconds: 30
|
|
periodSeconds: 30
|
|
failureThreshold: 3
|
|
volumeMounts:
|
|
- name: uploads
|
|
mountPath: /app/uploads
|
|
- name: outputs
|
|
mountPath: /app/outputs
|
|
volumes:
|
|
- name: uploads
|
|
persistentVolumeClaim:
|
|
claimName: uploads-pvc
|
|
- name: outputs
|
|
persistentVolumeClaim:
|
|
claimName: outputs-pvc
|
|
|
|
---
|
|
# Backend Service
|
|
apiVersion: v1
|
|
kind: Service
|
|
metadata:
|
|
name: backend-service
|
|
namespace: translate-api
|
|
spec:
|
|
selector:
|
|
app: backend
|
|
ports:
|
|
- port: 8000
|
|
targetPort: 8000
|
|
type: ClusterIP
|
|
|
|
---
|
|
# Frontend Deployment
|
|
apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: frontend
|
|
namespace: translate-api
|
|
labels:
|
|
app: frontend
|
|
spec:
|
|
replicas: 2
|
|
selector:
|
|
matchLabels:
|
|
app: frontend
|
|
template:
|
|
metadata:
|
|
labels:
|
|
app: frontend
|
|
spec:
|
|
containers:
|
|
- name: frontend
|
|
image: translate-api-frontend:latest
|
|
imagePullPolicy: IfNotPresent
|
|
ports:
|
|
- containerPort: 3000
|
|
env:
|
|
- name: NEXT_PUBLIC_API_URL
|
|
value: "http://backend-service:8000"
|
|
resources:
|
|
requests:
|
|
memory: "128Mi"
|
|
cpu: "100m"
|
|
limits:
|
|
memory: "512Mi"
|
|
cpu: "500m"
|
|
readinessProbe:
|
|
httpGet:
|
|
path: /
|
|
port: 3000
|
|
initialDelaySeconds: 10
|
|
periodSeconds: 10
|
|
|
|
---
|
|
# Frontend Service
|
|
apiVersion: v1
|
|
kind: Service
|
|
metadata:
|
|
name: frontend-service
|
|
namespace: translate-api
|
|
spec:
|
|
selector:
|
|
app: frontend
|
|
ports:
|
|
- port: 3000
|
|
targetPort: 3000
|
|
type: ClusterIP
|
|
|
|
---
|
|
# Ingress for external access
|
|
apiVersion: networking.k8s.io/v1
|
|
kind: Ingress
|
|
metadata:
|
|
name: translate-ingress
|
|
namespace: translate-api
|
|
annotations:
|
|
kubernetes.io/ingress.class: nginx
|
|
nginx.ingress.kubernetes.io/proxy-body-size: "100m"
|
|
nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
|
|
nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
|
|
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
|
spec:
|
|
tls:
|
|
- hosts:
|
|
- translate.yourdomain.com
|
|
secretName: translate-tls
|
|
rules:
|
|
- host: translate.yourdomain.com
|
|
http:
|
|
paths:
|
|
- path: /api
|
|
pathType: Prefix
|
|
backend:
|
|
service:
|
|
name: backend-service
|
|
port:
|
|
number: 8000
|
|
- path: /translate
|
|
pathType: Prefix
|
|
backend:
|
|
service:
|
|
name: backend-service
|
|
port:
|
|
number: 8000
|
|
- path: /health
|
|
pathType: Prefix
|
|
backend:
|
|
service:
|
|
name: backend-service
|
|
port:
|
|
number: 8000
|
|
- path: /admin
|
|
pathType: Prefix
|
|
backend:
|
|
service:
|
|
name: backend-service
|
|
port:
|
|
number: 8000
|
|
- path: /
|
|
pathType: Prefix
|
|
backend:
|
|
service:
|
|
name: frontend-service
|
|
port:
|
|
number: 3000
|
|
|
|
---
|
|
# Persistent Volume Claims
|
|
apiVersion: v1
|
|
kind: PersistentVolumeClaim
|
|
metadata:
|
|
name: uploads-pvc
|
|
namespace: translate-api
|
|
spec:
|
|
accessModes:
|
|
- ReadWriteMany
|
|
resources:
|
|
requests:
|
|
storage: 10Gi
|
|
|
|
---
|
|
apiVersion: v1
|
|
kind: PersistentVolumeClaim
|
|
metadata:
|
|
name: outputs-pvc
|
|
namespace: translate-api
|
|
spec:
|
|
accessModes:
|
|
- ReadWriteMany
|
|
resources:
|
|
requests:
|
|
storage: 20Gi
|
|
|
|
---
|
|
# Horizontal Pod Autoscaler for Backend
|
|
apiVersion: autoscaling/v2
|
|
kind: HorizontalPodAutoscaler
|
|
metadata:
|
|
name: backend-hpa
|
|
namespace: translate-api
|
|
spec:
|
|
scaleTargetRef:
|
|
apiVersion: apps/v1
|
|
kind: Deployment
|
|
name: backend
|
|
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
|
|
|
|
---
|
|
# ============================================
|
|
# PostgreSQL Database
|
|
# ============================================
|
|
apiVersion: v1
|
|
kind: PersistentVolumeClaim
|
|
metadata:
|
|
name: postgres-pvc
|
|
namespace: translate-api
|
|
spec:
|
|
accessModes:
|
|
- ReadWriteOnce
|
|
resources:
|
|
requests:
|
|
storage: 10Gi
|
|
|
|
---
|
|
apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: postgres
|
|
namespace: translate-api
|
|
labels:
|
|
app: postgres
|
|
spec:
|
|
replicas: 1
|
|
selector:
|
|
matchLabels:
|
|
app: postgres
|
|
template:
|
|
metadata:
|
|
labels:
|
|
app: postgres
|
|
spec:
|
|
containers:
|
|
- name: postgres
|
|
image: postgres:16-alpine
|
|
ports:
|
|
- containerPort: 5432
|
|
env:
|
|
- name: POSTGRES_USER
|
|
value: "translate"
|
|
- name: POSTGRES_PASSWORD
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: postgres-secrets
|
|
key: password
|
|
- name: POSTGRES_DB
|
|
value: "translate_db"
|
|
- name: PGDATA
|
|
value: "/var/lib/postgresql/data/pgdata"
|
|
volumeMounts:
|
|
- name: postgres-data
|
|
mountPath: /var/lib/postgresql/data
|
|
resources:
|
|
requests:
|
|
memory: "256Mi"
|
|
cpu: "100m"
|
|
limits:
|
|
memory: "512Mi"
|
|
cpu: "500m"
|
|
readinessProbe:
|
|
exec:
|
|
command:
|
|
- pg_isready
|
|
- -U
|
|
- translate
|
|
- -d
|
|
- translate_db
|
|
initialDelaySeconds: 5
|
|
periodSeconds: 10
|
|
livenessProbe:
|
|
exec:
|
|
command:
|
|
- pg_isready
|
|
- -U
|
|
- translate
|
|
- -d
|
|
- translate_db
|
|
initialDelaySeconds: 30
|
|
periodSeconds: 30
|
|
volumes:
|
|
- name: postgres-data
|
|
persistentVolumeClaim:
|
|
claimName: postgres-pvc
|
|
|
|
---
|
|
apiVersion: v1
|
|
kind: Secret
|
|
metadata:
|
|
name: postgres-secrets
|
|
namespace: translate-api
|
|
type: Opaque
|
|
stringData:
|
|
password: "translate_secret_change_me" # CHANGE IN PRODUCTION!
|
|
|
|
---
|
|
apiVersion: v1
|
|
kind: Service
|
|
metadata:
|
|
name: postgres-service
|
|
namespace: translate-api
|
|
spec:
|
|
selector:
|
|
app: postgres
|
|
ports:
|
|
- port: 5432
|
|
targetPort: 5432
|
|
type: ClusterIP
|
|
|
|
---
|
|
# ============================================
|
|
# Redis Cache
|
|
# ============================================
|
|
apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: redis
|
|
namespace: translate-api
|
|
labels:
|
|
app: redis
|
|
spec:
|
|
replicas: 1
|
|
selector:
|
|
matchLabels:
|
|
app: redis
|
|
template:
|
|
metadata:
|
|
labels:
|
|
app: redis
|
|
spec:
|
|
containers:
|
|
- name: redis
|
|
image: redis:7-alpine
|
|
command:
|
|
- redis-server
|
|
- --appendonly
|
|
- "yes"
|
|
- --maxmemory
|
|
- "256mb"
|
|
- --maxmemory-policy
|
|
- "allkeys-lru"
|
|
ports:
|
|
- containerPort: 6379
|
|
resources:
|
|
requests:
|
|
memory: "128Mi"
|
|
cpu: "50m"
|
|
limits:
|
|
memory: "256Mi"
|
|
cpu: "200m"
|
|
readinessProbe:
|
|
exec:
|
|
command:
|
|
- redis-cli
|
|
- ping
|
|
initialDelaySeconds: 5
|
|
periodSeconds: 10
|
|
livenessProbe:
|
|
exec:
|
|
command:
|
|
- redis-cli
|
|
- ping
|
|
initialDelaySeconds: 30
|
|
periodSeconds: 30
|
|
volumeMounts:
|
|
- name: redis-data
|
|
mountPath: /data
|
|
volumes:
|
|
- name: redis-data
|
|
emptyDir: {}
|
|
|
|
---
|
|
apiVersion: v1
|
|
kind: Service
|
|
metadata:
|
|
name: redis-service
|
|
namespace: translate-api
|
|
spec:
|
|
selector:
|
|
app: redis
|
|
ports:
|
|
- port: 6379
|
|
targetPort: 6379
|
|
type: ClusterIP
|