Desplegar un cluster de Kubernetes en un entorno de laboratorio es relativamente sencillo. Operarlo en producción con cargas reales, requisitos de disponibilidad y presion del negocio es un desafio completamente diferente. Un cluster productivo exige configuraciones especificas de recursos, autoescalado, health checks, políticas de red, seguridad y estrategias de actualización que no son necesarias en desarrollo. Esta guía cubre los aspectos críticos que separan un cluster de pruebas de uno listo para producción.

Diseño de un cluster production-ready

Alta disponibilidad del control plane

Un cluster productivo requiere un control plane redundante. Esto significa ejecutar multiples replicas de los componentes críticos:

  • API Server: Minimo 3 instancias detras de un load balancer. Cada instancia debe estar en una zona de disponibilidad diferente.
  • etcd: Cluster de 3 o 5 nodos (siempre impar para mantener quorum). Usa SSDs dedicadas para etcd, ya que es sensible a la latencia de disco.
  • Scheduler y Controller Manager: Corren en modo active-standby con leader election automático.

En servicios gestionados como EKS, AKS o GKE, el control plane es administrado por el proveedor. Aun así, debes configurar correctamente los node groups distribuidos en multiples zonas.

Configuración de node groups

Separa los nodos segun tipo de carga:

# Node group para workloads generales
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
  name: produccion-cluster
  region: us-east-1
managedNodeGroups:
  - name: general
    instanceType: m6i.xlarge
    minSize: 3
    maxSize: 10
    desiredCapacity: 5
    availabilityZones: ["us-east-1a", "us-east-1b", "us-east-1c"]
    labels:
      workload-type: general
  - name: compute-intensive
    instanceType: c6i.2xlarge
    minSize: 0
    maxSize: 8
    labels:
      workload-type: compute
    taints:
      - key: dedicated
        value: compute
        effect: NoSchedule

Resource requests y limits

Uno de los errores mas comunes en producción es no configurar correctamente los recursos. Sin requests, el scheduler no puede tomar decisiones informadas. Sin limits, un pod puede consumir todos los recursos del nodo y afectar a los demas.

Configuración recomendada

apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-pedidos
spec:
  replicas: 3
  template:
    spec:
      containers:
      - name: api
        image: mi-api:v2.1.0
        resources:
          requests:
            cpu: 250m
            memory: 256Mi
          limits:
            cpu: 500m
            memory: 512Mi

La regla general es: establece requests basandote en el consumo real observado (percentil 95) y limits como el doble de los requests o segun el máximo aceptable. Usa herramientas como Vertical Pod Autoscaler en modo recomendación para obtener datos reales.

LimitRange por namespace

Aplica valores por defecto para prevenir deployments sin recursos configurados:

apiVersion: v1
kind: LimitRange
metadata:
  name: default-limits
  namespace: production
spec:
  limits:
  - default:
      cpu: 500m
      memory: 512Mi
    defaultRequest:
      cpu: 100m
      memory: 128Mi
    type: Container

Autoescalado: HPA, VPA y Cluster Autoscaler

Horizontal Pod Autoscaler (HPA)

HPA ajusta el número de replicas basandose en métricas observadas:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: api-pedidos-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api-pedidos
  minReplicas: 3
  maxReplicas: 20
  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

El campo behavior es clave en producción: evita scale-down agresivos que pueden causar inestabilidad durante fluctuaciones de tráfico.

Vertical Pod Autoscaler (VPA)

VPA ajusta requests y limits automáticamente. En producción, usalo en modo Off (solo recomendaciones) inicialmente:

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: api-pedidos-vpa
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api-pedidos
  updatePolicy:
    updateMode: "Off"

Revisa las recomendaciones periódicamente y aplica los ajustes manualmente hasta tener confianza en el componente.

Cluster Autoscaler

Escala los nodos del cluster cuando hay pods pendientes por falta de capacidad. Asegurate de configurar los límites del node group y los priority expanders si tienes multiples node groups.

Health checks: liveness, readiness y startup probes

Los probes son fundamentales para que Kubernetes sepa el estado real de tus aplicaciones:

containers:
- name: api
  livenessProbe:
    httpGet:
      path: /healthz
      port: 8080
    initialDelaySeconds: 15
    periodSeconds: 10
    failureThreshold: 3
  readinessProbe:
    httpGet:
      path: /ready
      port: 8080
    initialDelaySeconds: 5
    periodSeconds: 5
    failureThreshold: 3
  startupProbe:
    httpGet:
      path: /healthz
      port: 8080
    failureThreshold: 30
    periodSeconds: 10
  • livenessProbe: Reinicia el contenedor si falla. Usalo para detectar deadlocks.
  • readinessProbe: Remueve el pod del servicio si falla. Usalo durante cargas elevadas o inicialización.
  • startupProbe: Protege contenedores con arranque lento. Mientras esta activo, los otros probes se desactivan.

Network policies

Por defecto, todos los pods pueden comunicarse entre si. En producción, aplica el principio de mínimo privilegio:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all-ingress
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Ingress

---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-api-to-db
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: database
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: api
    ports:
    - protocol: TCP
      port: 5432

Comienza con una política deny-all y luego abre solo las comunicaciones necesarias.

RBAC: control de acceso basado en roles

Nunca uses el usuario admin del cluster para operaciones regulares. Crea roles específicos:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: production
  name: deployment-manager
rules:
- apiGroups: ["apps"]
  resources: ["deployments", "replicasets"]
  verbs: ["get", "list", "watch", "update", "patch"]
- apiGroups: [""]
  resources: ["pods", "pods/log"]
  verbs: ["get", "list", "watch"]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: dev-team-binding
  namespace: production
subjects:
- kind: Group
  name: dev-team
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: deployment-manager
  apiGroup: rbac.authorization.k8s.io

Monitoreo y observabilidad

Un cluster sin monitoreo es un cluster a ciegas. La stack mínima recomendada:

  • Prometheus: Métricas del cluster, nodos, pods y aplicaciones. Usa kube-prometheus-stack que incluye alertas preconfiguradas.
  • Grafana: Dashboards para visualizar métricas. Los dashboards de la comunidad para Kubernetes son un buen punto de partida.
  • Alertmanager: Notificaciones cuando métricas criticas cruzan umbrales. Configura alertas para CPU, memoria, pods en CrashLoopBackOff y certificados proximos a expirar.
  • Logs centralizados: Loki o ELK stack para agregar logs de todos los pods en un solo lugar.

Backup, disaster recovery y estrategias de upgrade

Backup de etcd

etcd contiene todo el estado del cluster. Automatiza snapshots periodicos:

ETCDCTL_API=3 etcdctl snapshot save /backup/etcd-snapshot-$(date +%Y%m%d).db \
  --endpoints=https://127.0.0.1:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key

Almacena los snapshots en un bucket S3 con versionado habilitado.

Estrategias de upgrade del cluster

Actualiza siempre primero el control plane y luego los nodos worker. Sigue estos pasos:

  1. Lee las release notes de la versión destino para identificar breaking changes.
  2. Actualiza un cluster de staging primero y ejecuta pruebas.
  3. Actualiza el control plane (en EKS/GKE esto se hace desde la consola o API).
  4. Actualiza los nodos worker con rolling update: cordon, drain, upgrade, uncordon.
  5. Verifica que todos los workloads estan corriendo correctamente post-upgrade.

PodDisruptionBudgets

Protege tus aplicaciones durante mantenimiento de nodos:

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: api-pedidos-pdb
spec:
  minAvailable: 2
  selector:
    matchLabels:
      app: api-pedidos

Conclusion

Llevar Kubernetes a producción requiere atención deliberada a cada capa: desde la arquitectura del cluster y la gestión de recursos, hasta el autoescalado, los health checks, la seguridad de red y las estrategias de recuperación. Ninguno de estos componentes es opcional en un entorno productivo real. La clave esta en implementar cada práctica de forma incremental, validar con monitoreo y mantener la disciplina operativa que un orquestador tan potente como Kubernetes demanda.

Recursos adicionales