# ============================================================================= # GAMILIT Backend - Kubernetes Deployment # ============================================================================= # Purpose: Deploys GAMILIT backend API with horizontal pod autoscaling # Namespace: gamilit-production # Replicas: 3 (min) - 10 (max with HPA) # Resources: CPU 250m-500m, Memory 512Mi-1Gi per pod # ============================================================================= apiVersion: apps/v1 kind: Deployment metadata: name: gamilit-backend namespace: gamilit-production labels: app: gamilit component: backend tier: api version: v1.0.0 annotations: deployment.kubernetes.io/revision: "1" description: "GAMILIT Platform Backend API - Node.js + Express + TypeScript" spec: replicas: 3 revisionHistoryLimit: 10 strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 # Maximum number of pods that can be created above desired replicas maxUnavailable: 0 # Ensure zero-downtime during rolling updates selector: matchLabels: app: gamilit component: backend tier: api template: metadata: labels: app: gamilit component: backend tier: api version: v1.0.0 annotations: prometheus.io/scrape: "true" prometheus.io/port: "3006" prometheus.io/path: "/metrics" spec: # Security context for pod securityContext: runAsNonRoot: true runAsUser: 1001 fsGroup: 1001 seccompProfile: type: RuntimeDefault # Service account (for RBAC) serviceAccountName: gamilit-backend # Init containers (run before main container) initContainers: # Check database connectivity before starting - name: wait-for-database image: postgres:16-alpine command: - sh - -c - | echo "Waiting for PostgreSQL to be ready..." until pg_isready -h gamilit-postgres -p 5432 -U gamilit_user; do echo "PostgreSQL is unavailable - sleeping" sleep 2 done echo "PostgreSQL is ready!" env: - name: PGPASSWORD valueFrom: secretKeyRef: name: gamilit-db-secret key: password # Main application containers containers: - name: backend image: ghcr.io/gamilit/backend:1.0.0 # Replace with your registry imagePullPolicy: Always # Security context for container securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true runAsNonRoot: true runAsUser: 1001 capabilities: drop: - ALL ports: - name: http containerPort: 3006 protocol: TCP # Environment variables env: # General - name: NODE_ENV value: "production" - name: PORT value: "3006" - name: LOG_LEVEL value: "info" # Database - Connection from ConfigMap - name: DB_HOST valueFrom: configMapKeyRef: name: gamilit-backend-config key: db_host - name: DB_PORT valueFrom: configMapKeyRef: name: gamilit-backend-config key: db_port - name: DB_NAME valueFrom: configMapKeyRef: name: gamilit-backend-config key: db_name - name: DB_USER valueFrom: secretKeyRef: name: gamilit-db-secret key: username - name: DB_PASSWORD valueFrom: secretKeyRef: name: gamilit-db-secret key: password - name: DB_POOL_MIN value: "10" - name: DB_POOL_MAX value: "100" - name: DB_SSL value: "true" # JWT Secrets - name: JWT_SECRET valueFrom: secretKeyRef: name: gamilit-jwt-secret key: jwt_secret - name: JWT_EXPIRES_IN value: "7d" - name: JWT_REFRESH_EXPIRES_IN value: "30d" # CORS - name: CORS_ORIGIN valueFrom: configMapKeyRef: name: gamilit-backend-config key: cors_origin # Redis (optional) - name: REDIS_URL valueFrom: secretKeyRef: name: gamilit-redis-secret key: redis_url optional: true # Resource limits and requests resources: requests: cpu: 250m memory: 512Mi limits: cpu: 500m memory: 1Gi # Liveness probe - restart if unhealthy livenessProbe: httpGet: path: /api/health port: http scheme: HTTP initialDelaySeconds: 30 periodSeconds: 10 timeoutSeconds: 5 successThreshold: 1 failureThreshold: 3 # Readiness probe - remove from service if not ready readinessProbe: httpGet: path: /api/health port: http scheme: HTTP initialDelaySeconds: 15 periodSeconds: 5 timeoutSeconds: 3 successThreshold: 1 failureThreshold: 2 # Startup probe - for slow-starting containers startupProbe: httpGet: path: /api/health port: http initialDelaySeconds: 0 periodSeconds: 5 timeoutSeconds: 3 failureThreshold: 30 # 30 * 5s = 150s max startup time # Volume mounts volumeMounts: - name: tmp mountPath: /tmp - name: logs mountPath: /app/logs # Volumes volumes: - name: tmp emptyDir: {} - name: logs emptyDir: {} # Node affinity (prefer different nodes for HA) affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchExpressions: - key: component operator: In values: - backend topologyKey: kubernetes.io/hostname # Tolerations (if using tainted nodes) tolerations: - key: "app" operator: "Equal" value: "gamilit" effect: "NoSchedule" # DNS policy dnsPolicy: ClusterFirst # Restart policy restartPolicy: Always # Termination grace period terminationGracePeriodSeconds: 30 --- # ============================================================================= # GAMILIT Backend - Service Account # ============================================================================= apiVersion: v1 kind: ServiceAccount metadata: name: gamilit-backend namespace: gamilit-production labels: app: gamilit component: backend --- # ============================================================================= # GAMILIT Backend - ConfigMap # ============================================================================= apiVersion: v1 kind: ConfigMap metadata: name: gamilit-backend-config namespace: gamilit-production labels: app: gamilit component: backend data: # Database db_host: "gamilit-postgres.gamilit-production.svc.cluster.local" db_port: "5432" db_name: "gamilit_platform" # CORS cors_origin: "https://gamilit.com,https://www.gamilit.com" # Application node_env: "production" port: "3006" log_level: "info"