# ============================================ # 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