Ctrl K
ComunidadGuías…

deployment/production/production-deployment.yml

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# Janua Platform - Production Deployment Configuration
# Phase 3: Production Deployment & Validation
# Enterprise-grade Kubernetes deployment with zero-downtime patterns

apiVersion: v1
kind: Namespace
metadata:
  name: janua-production
  labels:
    app: janua
    environment: production
    version: "1.0.0"

---
# ConfigMap for production configuration
apiVersion: v1
kind: ConfigMap
metadata:
  name: janua-config
  namespace: janua-production
data:
  ENVIRONMENT: "production"
  DEBUG: "false"
  ENABLE_DOCS: "false"
  LOG_LEVEL: "INFO"
  CORS_ORIGINS: "https://janua.dev,https://dashboard.janua.dev,https://docs.janua.dev"
  TRUSTED_HOSTS: "janua.dev,*.janua.dev"
  # Database configuration
  DATABASE_POOL_SIZE: "20"
  DATABASE_MAX_OVERFLOW: "30"
  DATABASE_POOL_TIMEOUT: "30"
  DATABASE_POOL_RECYCLE: "1800"
  # Performance settings
  CACHE_DEFAULT_TTL: "300"
  PERFORMANCE_MONITORING: "true"
  SLOW_QUERY_THRESHOLD_MS: "100"
  # Enterprise features
  ENABLE_ORGANIZATIONS: "true"
  ENABLE_SCIM: "true"
  ENABLE_WEBHOOKS: "true"
  ENABLE_SSO: "true"
  ENABLE_MFA: "true"
  ENABLE_AUDIT_LOGS: "true"

---
# Secret for sensitive configuration
apiVersion: v1
kind: Secret
metadata:
  name: janua-secrets
  namespace: janua-production
type: Opaque
stringData:
  DATABASE_URL: "postgresql://janua:REPLACE_WITH_ACTUAL_PASSWORD@postgres-service:5432/janua"
  REDIS_URL: "redis://:REPLACE_WITH_ACTUAL_PASSWORD@redis-service:6379/0"
  JWT_SECRET_KEY: "REPLACE_WITH_ACTUAL_JWT_SECRET"
  SECRET_KEY: "REPLACE_WITH_ACTUAL_SECRET_KEY"
  SENDGRID_API_KEY: "REPLACE_WITH_ACTUAL_SENDGRID_KEY"
  SENTRY_DSN: "REPLACE_WITH_ACTUAL_SENTRY_DSN"
  GRAFANA_PASSWORD: "REPLACE_WITH_ACTUAL_GRAFANA_PASSWORD"
  # Email (Resend) - Centralized for all MADFAM apps
  RESEND_API_KEY: "REPLACE_WITH_ACTUAL_RESEND_KEY"
  # Internal API - Service-to-service communication for MADFAM apps
  INTERNAL_API_KEY: "REPLACE_WITH_ACTUAL_INTERNAL_API_KEY"

---
# API Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: janua-api
  namespace: janua-production
  labels:
    app: janua-api
    component: backend
    version: "1.0.0"
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0 # Zero-downtime deployment
  selector:
    matchLabels:
      app: janua-api
  template:
    metadata:
      labels:
        app: janua-api
        component: backend
        version: "1.0.0"
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port: "8000"
        prometheus.io/path: "/metrics/performance"
    spec:
      # Security Context
      securityContext:
        runAsNonRoot: true
        runAsUser: 1000
        fsGroup: 1000

      # Init Container for Database Migrations
      initContainers:
        - name: database-migration
          image: janua/api:latest
          command: ["python", "-m", "alembic", "upgrade", "head"]
          envFrom:
            - configMapRef:
                name: janua-config
            - secretRef:
                name: janua-secrets
          securityContext:
            runAsNonRoot: true
            runAsUser: 1000
            allowPrivilegeEscalation: false
            readOnlyRootFilesystem: true
            capabilities:
              drop:
                - ALL

      containers:
        - name: api
          image: janua/api:latest
          ports:
            - containerPort: 8000
              name: http
              protocol: TCP

          # Environment Configuration
          envFrom:
            - configMapRef:
                name: janua-config
            - secretRef:
                name: janua-secrets

          # Resource Limits and Requests
          resources:
            requests:
              cpu: 500m
              memory: 1Gi
            limits:
              cpu: 2000m
              memory: 4Gi

          # Health Checks
          livenessProbe:
            httpGet:
              path: /health
              port: 8000
            initialDelaySeconds: 30
            periodSeconds: 10
            timeoutSeconds: 5
            failureThreshold: 3

          readinessProbe:
            httpGet:
              path: /ready
              port: 8000
            initialDelaySeconds: 5
            periodSeconds: 5
            timeoutSeconds: 3
            successThreshold: 1
            failureThreshold: 3

          # Startup Probe (for slower startup)
          startupProbe:
            httpGet:
              path: /health
              port: 8000
            initialDelaySeconds: 10
            periodSeconds: 10
            timeoutSeconds: 5
            failureThreshold: 12 # 2 minutes max startup time

          # Security Context
          securityContext:
            runAsNonRoot: true
            runAsUser: 1000
            allowPrivilegeEscalation: false
            readOnlyRootFilesystem: true
            capabilities:
              drop:
                - ALL

          # Volume Mounts (for read-only filesystem)
          volumeMounts:
            - name: tmp-volume
              mountPath: /tmp
            - name: cache-volume
              mountPath: /app/.cache

      # Volumes
      volumes:
        - name: tmp-volume
          emptyDir: {}
        - name: cache-volume
          emptyDir: {}

      # Node Selection and Anti-Affinity
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
            - weight: 100
              podAffinityTerm:
                labelSelector:
                  matchExpressions:
                    - key: app
                      operator: In
                      values:
                        - janua-api
                topologyKey: kubernetes.io/hostname

      # Termination Grace Period
      terminationGracePeriodSeconds: 60

---
# API Service
apiVersion: v1
kind: Service
metadata:
  name: janua-api-service
  namespace: janua-production
  labels:
    app: janua-api
    component: backend
  annotations: {}
spec:
  type: ClusterIP
  ports:
    - port: 80
      targetPort: 8000
      protocol: TCP
      name: http
  selector:
    app: janua-api

---
# Horizontal Pod Autoscaler
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: janua-api-hpa
  namespace: janua-production
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: janua-api
  minReplicas: 3
  maxReplicas: 10
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70
    - type: Resource
      resource:
        name: memory
        target:
          type: Utilization
          averageUtilization: 80
  behavior:
    scaleUp:
      stabilizationWindowSeconds: 60
      policies:
        - type: Percent
          value: 50
          periodSeconds: 60
    scaleDown:
      stabilizationWindowSeconds: 300
      policies:
        - type: Percent
          value: 10
          periodSeconds: 60

---
# Pod Disruption Budget
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: janua-api-pdb
  namespace: janua-production
spec:
  minAvailable: 2
  selector:
    matchLabels:
      app: janua-api

---
# Network Policy (Security)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: janua-api-netpol
  namespace: janua-production
spec:
  podSelector:
    matchLabels:
      app: janua-api
  policyTypes:
    - Ingress
    - Egress
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              name: janua-ingress
        - podSelector:
            matchLabels:
              app: janua-nginx
      ports:
        - protocol: TCP
          port: 8000
  egress:
    - to:
        - podSelector:
            matchLabels:
              app: postgres
      ports:
        - protocol: TCP
          port: 5432
    - to:
        - podSelector:
            matchLabels:
              app: redis
      ports:
        - protocol: TCP
          port: 6379
    - to: [] # Allow all outbound for external services (SendGrid, etc.)
      ports:
        - protocol: TCP
          port: 443
        - protocol: TCP
          port: 80

---
# Ingress for API
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: janua-api-ingress
  namespace: janua-production
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
    nginx.ingress.kubernetes.io/proxy-body-size: "10m"
    nginx.ingress.kubernetes.io/proxy-connect-timeout: "30"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "30"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "30"
    nginx.ingress.kubernetes.io/rate-limit: "60"
    nginx.ingress.kubernetes.io/rate-limit-window: "1m"
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
    nginx.ingress.kubernetes.io/configuration-snippet: |
      more_set_headers "X-Frame-Options: DENY";
      more_set_headers "X-Content-Type-Options: nosniff";
      more_set_headers "X-XSS-Protection: 1; mode=block";
      more_set_headers "Referrer-Policy: strict-origin-when-cross-origin";
      more_set_headers "Permissions-Policy: geolocation=(), microphone=(), camera=()";
spec:
  tls:
    - hosts:
        - api.janua.dev
      secretName: janua-api-tls
  rules:
    - host: api.janua.dev
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: janua-api-service
                port:
                  number: 80