3. Infraestructura y Despliegue

3. Infraestructura y Despliegue

Esta sección cubre la infraestructura técnica, entornos de despliegue, estrategias de CI/CD y consideraciones de escalabilidad para el sistema DTEM.

3.1. Arquitectura de Entornos

3.1.1. Entornos Definidos

Development Environment

  • Propósito: Desarrollo local y pruebas unitarias
  • Infraestructura: Local/Docker Desktop
  • Datos: Datos de prueba y mock
  • Acceso: Desarrolladores individuales

Staging Environment

  • Propósito: Integración y pruebas de aceptación
  • Infraestructura: Cloud (similar a producción)
  • Datos: Datos anonimizados de producción
  • Acceso: Equipo QA y desarrolladores

Production Environment

  • Propósito: Operación del sistema en vivo
  • Infraestructura: Cloud/On-premise de alta disponibilidad
  • Datos: Datos reales de clientes
  • Acceso: Personal autorizado únicamente

3.1.2. Diagrama de Entornos

┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│   Development   │    │     Staging     │    │   Production    │
│                 │    │                 │    │                 │
│ ┌─────────────┐ │    │ ┌─────────────┐ │    │ ┌─────────────┐ │
│ │Local Docker │ │    │ │Cloud VMs    │ │    │ │Cloud Cluster│ │
│ │             │ │    │ │             │ │    │ │             │ │
│ │- PostgreSQL │ │    │ │- PostgreSQL │ │    │ │- PostgreSQL │ │
│ │- Redis      │ │    │ │- Redis      │ │    │ │- Redis      │ │
│ │- Node.js    │ │    │ │- Node.js    │ │    │ │- Node.js    │ │
│ └─────────────┘ │    │ └─────────────┘ │    │ └─────────────┘ │
│                 │    │                 │    │                 │
│ Git Integration │───▶│ CI/CD Pipeline  │───▶│  Auto Deploy    │
└─────────────────┘    └─────────────────┘    └─────────────────┘

3.2. Docker y Contenerización

3.2.1. Estrategia de Contenerización

Multi-stage Builds

# Dockerfile.base
FROM node:18-alpine AS base
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force

# Dockerfile.development
FROM base AS development
RUN npm ci
COPY . .
EXPOSE 3000
CMD ["npm", "run", "dev"]

# Dockerfile.production
FROM base AS production
COPY --from=development /app/dist ./dist
EXPOSE 3000
USER node
CMD ["node", "dist/index.js"]

Optimización de Imágenes

# Optimización para producción
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

FROM node:18-alpine AS runtime
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
WORKDIR /app

COPY --from=builder /app/node_modules ./node_modules
COPY --chown=nextjs:nodejs . .

USER nextjs
EXPOSE 3000
CMD ["npm", "start"]

3.2.2. Docker Compose para Desarrollo

# docker-compose.dev.yml
version: '3.8'

services:
  api:
    build:
      context: .
      target: development
    volumes:
      - .:/app
      - /app/node_modules
    environment:
      - NODE_ENV=development
      - DEBUG=*
    ports:
      - "3000:3000"
      - "9229:9229"  # Debug port
    command: npm run dev:debug

  postgres:
    image: postgres:14-alpine
    environment:
      POSTGRES_DB: dtem_dev
      POSTGRES_USER: dev
      POSTGRES_PASSWORD: dev123
    ports:
      - "5432:5432"
    volumes:
      - postgres_dev_data:/var/lib/postgresql/data

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    command: redis-server --appendonly yes

volumes:
  postgres_dev_data:

3.3. Kubernetes para Producción

3.3.1. Arquitectura Kubernetes

# namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: dtem-prod
  labels:
    name: dtem-prod
    environment: production

---
# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: dtem-config
  namespace: dtem-prod
data:
  NODE_ENV: "production"
  LOG_LEVEL: "info"
  API_PORT: "3000"
  DB_HOST: "postgres-service"
  REDIS_HOST: "redis-service"

---
# secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: dtem-secrets
  namespace: dtem-prod
type: Opaque
data:
  DB_PASSWORD: <base64-encoded-password>
  JWT_SECRET: <base64-encoded-jwt-secret>
  REDIS_PASSWORD: <base64-encoded-redis-password>

3.3.2. Deployments

# api-gateway-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-gateway
  namespace: dtem-prod
  labels:
    app: api-gateway
spec:
  replicas: 3
  selector:
    matchLabels:
      app: api-gateway
  template:
    metadata:
      labels:
        app: api-gateway
    spec:
      containers:
      - name: api-gateway
        image: dtem/api-gateway:latest
        ports:
        - containerPort: 3000
        envFrom:
        - configMapRef:
            name: dtem-config
        - secretRef:
            name: dtem-secrets
        resources:
          requests:
            memory: "256Mi"
            cpu: "250m"
          limits:
            memory: "512Mi"
            cpu: "500m"
        livenessProbe:
          httpGet:
            path: /health
            port: 3000
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /ready
            port: 3000
          initialDelaySeconds: 5
          periodSeconds: 5

---
# dte-service-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: dte-service
  namespace: dtem-prod
spec:
  replicas: 5
  selector:
    matchLabels:
      app: dte-service
  template:
    metadata:
      labels:
        app: dte-service
    spec:
      containers:
      - name: dte-service
        image: dtem/dte-service:latest
        envFrom:
        - configMapRef:
            name: dtem-config
        - secretRef:
            name: dtem-secrets
        resources:
          requests:
            memory: "512Mi"
            cpu: "500m"
          limits:
            memory: "1Gi"
            cpu: "1000m"

3.3.3. Services y Load Balancing

# api-gateway-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: api-gateway-service
  namespace: dtem-prod
spec:
  selector:
    app: api-gateway
  ports:
  - protocol: TCP
    port: 80
    targetPort: 3000
  type: ClusterIP

---
# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: dtem-ingress
  namespace: dtem-prod
  annotations:
    kubernetes.io/ingress.class: nginx
    cert-manager.io/cluster-issuer: letsencrypt-prod
    nginx.ingress.kubernetes.io/rate-limit: "100"
    nginx.ingress.kubernetes.io/rate-limit-window: "1m"
spec:
  tls:
  - hosts:
    - api.dtem.empresa.cl
    - dtem.empresa.cl
    secretName: dtem-tls
  rules:
  - host: api.dtem.empresa.cl
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: api-gateway-service
            port:
              number: 80
  - host: dtem.empresa.cl
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-frontend-service
            port:
              number: 80

3.4. CI/CD Pipeline

3.4.1. GitLab CI Configuration

# .gitlab-ci.yml
stages:
  - test
  - build
  - deploy-staging
  - deploy-production

variables:
  DOCKER_REGISTRY: registry.gitlab.com/empresa/dtem
  KUBERNETES_NAMESPACE_STAGING: dtem-staging
  KUBERNETES_NAMESPACE_PROD: dtem-prod

# Test Stage
test:unit:
  stage: test
  image: node:18-alpine
  script:
    - npm ci
    - npm run test:unit
  coverage: '/Lines\s*:\s*(\d+\.\d+)%/'
  artifacts:
    reports:
      junit: junit.xml
      coverage_report:
        coverage_format: cobertura
        path: coverage/cobertura-coverage.xml

test:integration:
  stage: test
  image: docker:20.10
  services:
    - docker:20.10-dind
  script:
    - docker-compose -f docker-compose.test.yml up -d
    - npm run test:integration
    - docker-compose -f docker-compose.test.yml down
  dependencies:
    - test:unit

# Build Stage
build:docker:
  stage: build
  image: docker:20.10
  services:
    - docker:20.10-dind
  script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - docker build -t $DOCKER_REGISTRY/api-gateway:$CI_COMMIT_SHA -f Dockerfile.gateway .
    - docker build -t $DOCKER_REGISTRY/dte-service:$CI_COMMIT_SHA -f Dockerfile.dte .
    - docker push $DOCKER_REGISTRY/api-gateway:$CI_COMMIT_SHA
    - docker push $DOCKER_REGISTRY/dte-service:$CI_COMMIT_SHA
  only:
    - main
    - develop

# Deploy Staging
deploy:staging:
  stage: deploy-staging
  image: bitnami/kubectl:latest
  script:
    - kubectl config use-context $KUBE_CONTEXT_STAGING
    - kubectl set image deployment/api-gateway api-gateway=$DOCKER_REGISTRY/api-gateway:$CI_COMMIT_SHA -n $KUBERNETES_NAMESPACE_STAGING
    - kubectl set image deployment/dte-service dte-service=$DOCKER_REGISTRY/dte-service:$CI_COMMIT_SHA -n $KUBERNETES_NAMESPACE_STAGING
    - kubectl rollout status deployment/api-gateway -n $KUBERNETES_NAMESPACE_STAGING
    - kubectl rollout status deployment/dte-service -n $KUBERNETES_NAMESPACE_STAGING
  environment:
    name: staging
    url: https://staging.dtem.empresa.cl
  only:
    - develop

# Deploy Production
deploy:production:
  stage: deploy-production
  image: bitnami/kubectl:latest
  script:
    - kubectl config use-context $KUBE_CONTEXT_PROD
    - kubectl set image deployment/api-gateway api-gateway=$DOCKER_REGISTRY/api-gateway:$CI_COMMIT_SHA -n $KUBERNETES_NAMESPACE_PROD
    - kubectl set image deployment/dte-service dte-service=$DOCKER_REGISTRY/dte-service:$CI_COMMIT_SHA -n $KUBERNETES_NAMESPACE_PROD
    - kubectl rollout status deployment/api-gateway -n $KUBERNETES_NAMESPACE_PROD
    - kubectl rollout status deployment/dte-service -n $KUBERNETES_NAMESPACE_PROD
  environment:
    name: production
    url: https://dtem.empresa.cl
  when: manual
  only:
    - main

3.4.2. Quality Gates

# quality-gate.yml
quality_gate:
  stage: test
  image: sonarsource/sonar-scanner-cli:latest
  script:
    - sonar-scanner
      -Dsonar.projectKey=dtem
      -Dsonar.sources=src
      -Dsonar.host.url=$SONAR_HOST_URL
      -Dsonar.login=$SONAR_TOKEN
      -Dsonar.qualitygate.wait=true
  allow_failure: false
  only:
    - merge_requests
    - main
    - develop

security:scan:
  stage: test
  image: owasp/zap2docker-stable
  script:
    - mkdir -p /zap/wrk/
    - /zap/zap-baseline.py -t http://api-gateway:3000 -J gl-sast-report.json || true
  artifacts:
    reports:
      sast: gl-sast-report.json
  only:
    - main
    - develop

3.5. Escalabilidad y Auto-scaling

3.5.1. Horizontal Pod Autoscaler (HPA)

# hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: api-gateway-hpa
  namespace: dtem-prod
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api-gateway
  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:
    scaleDown:
      stabilizationWindowSeconds: 300
      policies:
      - type: Percent
        value: 10
        periodSeconds: 60
    scaleUp:
      stabilizationWindowSeconds: 60
      policies:
      - type: Percent
        value: 50
        periodSeconds: 60

---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: dte-service-hpa
  namespace: dtem-prod
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: dte-service
  minReplicas: 5
  maxReplicas: 20
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 60
  - type: Pods
    pods:
      metric:
        name: dte_processing_rate
      target:
        type: AverageValue
        averageValue: "10"

3.5.2. Vertical Pod Autoscaler (VPA)

# vpa.yaml
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: api-gateway-vpa
  namespace: dtem-prod
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api-gateway
  updatePolicy:
    updateMode: "Auto"
  resourcePolicy:
    containerPolicies:
    - containerName: api-gateway
      maxAllowed:
        cpu: 2
        memory: 2Gi
      minAllowed:
        cpu: 100m
        memory: 128Mi

3.5.3. Cluster Autoscaler

# cluster-autoscaler.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: cluster-autoscaler
  namespace: kube-system
spec:
  replicas: 1
  selector:
    matchLabels:
      app: cluster-autoscaler
  template:
    metadata:
      labels:
        app: cluster-autoscaler
    spec:
      containers:
      - image: k8s.gcr.io/autoscaling/cluster-autoscaler:v1.21.0
        name: cluster-autoscaler
        resources:
          limits:
            cpu: 100m
            memory: 300Mi
          requests:
            cpu: 100m
            memory: 300Mi
        command:
        - ./cluster-autoscaler
        - --v=4
        - --stderrthreshold=info
        - --cloud-provider=aws
        - --skip-nodes-with-local-storage=false
        - --expander=least-waste
        - --node-group-auto-discovery=asg:tag=k8s.io/cluster-autoscaler/enabled,k8s.io/cluster-autoscaler/dtem-prod
        - --balance-similar-node-groups
        - --skip-nodes-with-system-pods=false

3.6. Gestión de Configuración

3.6.1. GitOps con ArgoCD

# argocd-application.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: dtem-prod
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://gitlab.com/empresa/dtem-k8s.git
    targetRevision: HEAD
    path: production
  destination:
    server: https://kubernetes.default.svc
    namespace: dtem-prod
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
    - CreateNamespace=true
    retry:
      limit: 5
      backoff:
        duration: 5s
        factor: 2
        maxDuration: 3m

3.6.2. Configuración con Helm

# Chart.yaml
apiVersion: v2
name: dtem
description: DTEM Helm Chart
type: application
version: 1.0.0
appVersion: "3.0.0"

# values.yaml
global:
  imageRegistry: registry.gitlab.com/empresa/dtem
  imageTag: "latest"
  namespace: dtem-prod

apiGateway:
  replicaCount: 3
  image:
    repository: api-gateway
  service:
    type: ClusterIP
    port: 80
  resources:
    requests:
      memory: "256Mi"
      cpu: "250m"
    limits:
      memory: "512Mi"
      cpu: "500m"

dteService:
  replicaCount: 5
  image:
    repository: dte-service
  resources:
    requests:
      memory: "512Mi"
      cpu: "500m"
    limits:
      memory: "1Gi"
      cpu: "1000m"

postgresql:
  enabled: true
  auth:
    postgresPassword: "secure-password"
    database: "dtem_prod"
  primary:
    persistence:
      enabled: true
      size: 100Gi

redis:
  enabled: true
  auth:
    enabled: true
    password: "redis-password"
  master:
    persistence:
      enabled: true
      size: 20Gi

3.7. Monitoreo de Infraestructura

3.7.1. Prometheus Monitoring

# servicemonitor.yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: dtem-metrics
  namespace: dtem-prod
  labels:
    app: dtem
spec:
  selector:
    matchLabels:
      app: api-gateway
  endpoints:
  - port: metrics
    interval: 30s
    path: /metrics

3.7.2. Grafana Dashboards

{
  "dashboard": {
    "title": "DTEM System Overview",
    "panels": [
      {
        "title": "Request Rate",
        "type": "graph",
        "targets": [
          {
            "expr": "rate(http_requests_total[5m])",
            "legendFormat": "{{method}} {{status}}"
          }
        ]
      },
      {
        "title": "Response Time",
        "type": "graph",
        "targets": [
          {
            "expr": "histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))",
            "legendFormat": "95th percentile"
          }
        ]
      },
      {
        "title": "Error Rate",
        "type": "singlestat",
        "targets": [
          {
            "expr": "rate(http_requests_total{status=~\"5..\"}[5m]) / rate(http_requests_total[5m])",
            "legendFormat": "Error Rate"
          }
        ]
      }
    ]
  }
}

3.8. Resiliencia y Alta Disponibilidad

3.8.1. Pod Disruption Budgets

# pdb.yaml
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: api-gateway-pdb
  namespace: dtem-prod
spec:
  minAvailable: 2
  selector:
    matchLabels:
      app: api-gateway

---
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: dte-service-pdb
  namespace: dtem-prod
spec:
  minAvailable: 3
  selector:
    matchLabels:
      app: dte-service

3.8.2. Circuit Breaker Pattern

# circuit-breaker.yaml
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: dte-service-circuit-breaker
  namespace: dtem-prod
spec:
  host: dte-service
  trafficPolicy:
    connectionPool:
      tcp:
        maxConnections: 100
      http:
        http1MaxPendingRequests: 50
        maxRequestsPerConnection: 10
    outlierDetection:
      consecutiveErrors: 3
      interval: 30s
      baseEjectionTime: 30s

Próxima sección: 4. Seguridad