INFRA

Kubernetes: Orquestación de Contenedores Grado Producción

Guía práctica para ejecutar Kubernetes en producción — desde primitivas como Pods y Deployments hasta temas avanzados como HPA, RBAC, tuning de recursos y monitoreo con Prometheus. Basada en 26 microservicios corriendo en GKE con Istio mesh.

Por Jose Nobile | Actualizado 2026-04-24 | 18 min de lectura

Pods: La Unidad Atómica

Un Pod es la unidad desplegable más pequeña en Kubernetes. Envuelve uno o más contenedores que comparten namespace de red (misma IP, mismo localhost) y volúmenes de almacenamiento. En la práctica, la mayoría de los Pods corren un solo contenedor de aplicación, pero patrones sidecar — como el proxy Envoy de Istio — agregan un segundo contenedor para concerns transversales.

Los Pods son efímeros por diseño. Pueden ser eliminados, reprogramados o reemplazados en cualquier momento. Esto significa que tu aplicación debe ser stateless a nivel de Pod, almacenando datos persistentes en sistemas externos (bases de datos, object storage, PersistentVolumes). Los health checks vía livenessProbe y readinessProbe son críticos: el liveness probe reinicia un contenedor colgado, mientras el readiness probe lo remueve del tráfico del Service hasta que esté saludable.

Los lifecycle hooks del Pod (postStart, preStop) te permiten ejecutar comandos durante la creación y terminación. El hook preStop es especialmente importante para shutdown graceful: le da tiempo a tu aplicación para terminar requests en curso y cerrar conexiones de base de datos antes de que llegue el SIGTERM.

apiVersion: v1
kind: Pod
metadata:
  name: api-server
spec:
  containers:
  - name: api
    image: gcr.io/myproject/api:v2.4.1
    ports:
    - containerPort: 3000
    livenessProbe:
      httpGet:
        path: /healthz
        port: 3000
      initialDelaySeconds: 10
      periodSeconds: 15
    readinessProbe:
      httpGet:
        path: /ready
        port: 3000
      initialDelaySeconds: 5
      periodSeconds: 5

Deployments, StatefulSets y DaemonSets

Nunca creas Pods sueltos en producción. En cambio, declaras un Deployment que gestiona un ReplicaSet, que a su vez gestiona los Pods. El controlador del Deployment asegura que el número deseado de réplicas esté siempre corriendo, reemplazando cualquier Pod que crashee o sea desalojado. Cuando actualizas la imagen del contenedor, el Deployment crea un nuevo ReplicaSet y gradualmente mueve el tráfico, dándote updates sin downtime.

Los campos clave del Deployment incluyen replicas (cantidad deseada de Pods), strategy (RollingUpdate o Recreate), revisionHistoryLimit (cuántos ReplicaSets viejos mantener para rollback), y minReadySeconds (demora antes de considerar un Pod nuevo como disponible). En la plataforma, cada microservicio corre como Deployment con al menos 2 réplicas para alta disponibilidad, y el historial de revisiones se mantiene en 5 para rollback rápido.

Los parámetros maxUnavailable y maxSurge controlan la velocidad del rollout. Configurar maxUnavailable: 0 y maxSurge: 1 asegura que no se pierda capacidad durante las actualizaciones — los Pods nuevos arrancan antes de que los viejos terminen. Para servicios sensibles a latencia, esta es la configuración más segura.

Los StatefulSets gestionan workloads stateful que necesitan identidades de red estables y almacenamiento persistente. A diferencia de los Deployments, los StatefulSets garantizan despliegue y escalado ordenado y graceful. Cada Pod recibe un identificador persistente (ej: mysql-0, mysql-1) que sobrevive al rescheduling. Combinado con un Service headless, los Pods obtienen nombres DNS estables. Los StatefulSets también soportan volumeClaimTemplates para provisionar un PersistentVolumeClaim dedicado por réplica. Usa StatefulSets para bases de datos, message brokers y cualquier workload donde la identidad del Pod importa.

Los DaemonSets aseguran que una copia de un Pod corra en cada nodo (o un subconjunto seleccionado). Son el controlador correcto para agentes a nivel de nodo: recolectores de logs (Fluentd/Fluent Bit), exporters de monitoreo (node-exporter), plugins de red (Calico, Cilium) y drivers de almacenamiento. Cuando un nuevo nodo se une al cluster, el DaemonSet automáticamente agenda un Pod en él. En producción, los DaemonSets corren Fluent Bit para reenvío de logs a Cloud Logging y node-exporter para métricas de host en Prometheus.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: payment-service
spec:
  replicas: 3
  revisionHistoryLimit: 5
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 0
      maxSurge: 1
  selector:
    matchLabels:
      app: payment-service
  template:
    metadata:
      labels:
        app: payment-service
    spec:
      containers:
      - name: payment
        image: gcr.io/myproject/payment:v3.1.0
WORKLOAD

Deployment

Workloads stateless. Gestiona ReplicaSets para rolling updates y rollbacks. La opción por defecto para microservicios, APIs y frontends web.

WORKLOAD

StatefulSet

Workloads stateful que necesitan identidades estables y almacenamiento persistente. Creación/eliminación ordenada de Pods. Usa para bases de datos, Kafka, Elasticsearch y clusters Redis.

WORKLOAD

DaemonSet

Corre un Pod por nodo. Usa para recolectores de logs, agentes de monitoreo, plugins de red y drivers de almacenamiento. Maneja automáticamente nodos nuevos.

Services e Ingress

Un Service provee un endpoint de red estable para un conjunto de Pods. Como las IPs de los Pods cambian en cada reinicio, los Services abstraen la capa de ruteo vía selectores de labels. ClusterIP (por defecto) expone el Service internamente, NodePort mapea un puerto estático en cada nodo, y LoadBalancer provisiona un balanceador de carga en la nube. En GKE, los Services LoadBalancer crean automáticamente un Network Load Balancer de Google Cloud con IP pública.

Para tráfico HTTP/HTTPS, los objetos Ingress definen reglas de ruteo que mapean hostnames y rutas URL a Services backend. Un Ingress controller (NGINX, Traefik o Istio Gateway) observa los recursos Ingress y configura el reverse proxy real. En el cluster de producción, el Gateway de Istio reemplaza al Ingress controller tradicional, proveyendo mTLS, traffic splitting y ruteo avanzado en una sola capa.

Los Headless Services (clusterIP: None) retornan IPs individuales de Pods vía DNS en vez de una sola IP virtual. Esto es esencial para workloads stateful como bases de datos o caches donde los clientes necesitan conectarse a instancias específicas. Combinado con un StatefulSet, los headless Services habilitan identidades DNS estables como mysql-0.mysql.default.svc.cluster.local.

CORE

ClusterIP

Tipo por defecto. IP virtual solo interna. Otros Pods llegan al Service vía service-name.namespace.svc.cluster.local. Usado para toda la comunicación interna entre microservicios en producción.

CORE

NodePort

Expone el Service en un puerto estático (30000-32767) en la IP de cada nodo. Útil para desarrollo, clusters on-prem o cuando no hay LB en la nube disponible. Se construye sobre ClusterIP automáticamente.

CORE

LoadBalancer

Provisiona un LB en la nube con IP pública. Usa para servicios que necesitan acceso externo sin capa de Ingress. Costo: un LB por Service, así que prefiere Ingress para workloads HTTP.

CORE

Ingress / Gateway

Punto de entrada único para todo el tráfico HTTP. Rutea por hostname y path. Terminación TLS, rate limiting y headers CORS. El cluster usa Istio Gateway para gestión unificada de tráfico.

Namespaces y RBAC

Los Namespaces particionan un cluster en sub-clusters virtuales. Proveen alcance para nombres (dos Deployments pueden compartir el mismo nombre en diferentes namespaces), cuotas de recursos y políticas de red. Un cluster de producción típicamente tiene namespaces para production, staging, monitoring e istio-system. El cluster de producción corre 6 namespaces separando workloads por ambiente y función.

RBAC (Control de Acceso Basado en Roles) restringe quién puede hacer qué en el cluster. Un Role define permisos dentro de un namespace (ej: "puede listar Pods y leer logs"), y un RoleBinding asigna ese Role a un usuario o ServiceAccount. Para permisos a nivel de cluster, usa ClusterRole y ClusterRoleBinding. Nunca le des cluster-admin a los desarrolladores — acota permisos a los recursos y verbos exactos que necesitan.

Los ServiceAccounts son el mecanismo de identidad para Pods. Cada namespace tiene un ServiceAccount default, pero deberías crear ServiceAccounts dedicados para cada workload y asignar roles RBAC mínimos. Esto sigue el principio de menor privilegio y limita el radio de explosión si un Pod es comprometido. En producción, cada microservicio corre bajo su propio ServiceAccount con permisos acotados solo a los Secrets y ConfigMaps que necesita.

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: production
  name: pod-reader
rules:
- apiGroups: [""]
  resources: ["pods", "pods/log"]
  verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  namespace: production
  name: dev-pod-reader
subjects:
- kind: User
  name: [email protected]
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

ConfigMaps y Secrets

Los ConfigMaps almacenan datos de configuración no sensibles como pares clave-valor. Desacoplan la configuración de las imágenes de contenedor, permitiéndote cambiar settings sin rebuild. Los ConfigMaps pueden montarse como archivos o inyectarse como variables de entorno. Para config estructurada (YAML, JSON, archivos .env), monta el ConfigMap entero como directorio de volumen.

Los Secrets almacenan datos sensibles (API keys, credenciales de base de datos, certificados TLS) con codificación base64. Si bien base64 no es encriptación, el etcd de Kubernetes puede configurarse con encryption-at-rest (habilitado por defecto en GKE). Para mayor seguridad, usa secret managers externos como Google Secret Manager o HashiCorp Vault con el External Secrets Operator, que sincroniza secrets externos en objetos Secret de Kubernetes automáticamente.

Los ConfigMaps y Secrets inmutables (configurar immutable: true) previenen cambios accidentales y mejoran el rendimiento del cluster al eliminar la necesidad de que el kubelet vigile actualizaciones. En producción, todos los ConfigMaps de producción son inmutables — los cambios de config requieren crear un nuevo ConfigMap con nombre versionado y actualizar la referencia del Deployment, asegurando un rollout limpio.

Nunca hagas commit de Secrets a Git. Usa sealed-secrets, External Secrets Operator, o el flag --set de Helm con variables de CI/CD para inyectar valores sensibles en tiempo de deploy. En producción, todos los secrets fluyen desde Google Secret Manager a través de External Secrets Operator — cero secrets en el repositorio Git.

Autoescalado HPA y VPA

El Horizontal Pod Autoscaler (HPA) escala automáticamente la cantidad de réplicas de Pod basado en métricas observadas. La métrica más común es utilización de CPU, pero HPA v2 soporta memoria, métricas custom (desde Prometheus vía la API de métricas custom), y métricas externas (como profundidad de cola de Cloud Pub/Sub). HPA evalúa métricas cada 15 segundos por defecto y ajusta réplicas para mantener la métrica objetivo cerca del umbral especificado.

Configurar la utilización objetivo correcta es crítico. Muy baja (ej: 30% CPU) desperdicia recursos manteniendo demasiadas réplicas. Muy alta (ej: 90%) no deja margen para picos de tráfico. Un objetivo de 60-70% CPU es un punto de partida seguro para la mayoría de servicios HTTP. Para workloads batch, escala por métricas custom como longitud de cola en vez de CPU.

HPA requiere que los resource requests estén configurados en los contenedores — sin requests, no hay línea base para calcular porcentajes de utilización. El campo behavior te permite controlar la velocidad de scale-up y scale-down. En producción, el scale-down es conservador (ventana de estabilización de 300 segundos) para evitar flapping durante fluctuaciones de tráfico, mientras el scale-up es agresivo (0 segundos de estabilización) para manejar picos repentinos.

El Vertical Pod Autoscaler (VPA) complementa al HPA ajustando automáticamente los requests/limits de CPU y memoria en contenedores individuales. VPA observa el uso real de recursos a lo largo del tiempo y recomienda (o aplica) valores correctamente dimensionados. Opera en tres modos: Off (solo recomendación), Initial (configura requests en la creación del Pod), y Auto (desaloja y recrea Pods con requests actualizados). VPA es invaluable para workloads donde las necesidades de recursos son impredecibles o cambian con el tiempo. En GKE, VPA está disponible como add-on del cluster.

No uses HPA y VPA sobre la misma métrica (ej: ambos escalando por CPU). Van a entrar en conflicto. Un patrón común es HPA para escalado horizontal por CPU/métricas custom y VPA en modo recomendación para dimensionar correctamente los requests de memoria. En producción, VPA corre en modo Off en todos los namespaces, alimentando recomendaciones en una revisión semanal de tuning de recursos que previene tanto el sobreaprovisionamiento como los OOM kills.

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: api-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api-server
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 65
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 300
    scaleUp:
      stabilizationWindowSeconds: 0

Requests y Limits de Recursos

Los resource requests y limits son los settings de Kubernetes más incomprendidos y de mayor impacto. Los requests definen los recursos mínimos que un contenedor necesita — el scheduler los usa para colocar Pods en nodos con capacidad suficiente. Los limits definen el máximo — el kubelet los aplica con cgroups. Si un contenedor excede su límite de memoria, recibe OOM-kill. Si excede su límite de CPU, se le aplica throttling (no se lo mata).

La brecha entre request y limit importa. Configurarlos iguales (clase QoS Guaranteed) da rendimiento predecible pero desperdicia recursos. Configurar requests más bajos que limits (QoS Burstable) permite overcommit pero arriesga problemas de noisy-neighbor. Nunca omitas requests completamente (QoS BestEffort) — estos Pods son los primeros en ser desalojados bajo presión de memoria.

Para encontrar los valores correctos, observa el uso real con kubectl top pods y métricas de Prometheus por al menos una semana bajo tráfico de producción. Empieza con limits generosos y ajusta iterativamente. Patrón común: request al p50 de uso y limit al p99 + 20% de margen. En producción, cada microservicio tiene requests y limits tuneados basados en datos reales de producción, previniendo OOM kills que antes causaban fallas en cascada.

Los OOM kills son asesinos silenciosos de aplicaciones. Un contenedor que toca su límite de memoria es terminado con exit code 137 — sin shutdown graceful, sin entrada de log antes de morir. Monitorea kube_pod_container_status_last_terminated_reason{reason="OOMKilled"} en Prometheus y alerta sobre eso. En producción, resolver los problemas de OOM en el servicio de pagos (subiendo limits de 256Mi a 512Mi después de profiling) eliminó el 98% de las fallas intermitentes del servicio.

resources:
  requests:
    cpu: 250m
    memory: 256Mi
  limits:
    cpu: 500m
    memory: 512Mi

Rolling Updates y Rollbacks

Los Deployments de Kubernetes usan rolling updates por defecto. Cuando cambias el template del Pod (generalmente el tag de la imagen del contenedor), el controlador del Deployment crea un nuevo ReplicaSet y lo escala incrementalmente mientras reduce el viejo. Los parámetros maxSurge y maxUnavailable controlan el ritmo. Combinado con readiness probes, esto asegura que el tráfico solo llegue a Pods nuevos saludables.

Los rollbacks son instantáneos. Cada update del Deployment crea una nueva revisión almacenada como ReplicaSet. kubectl rollout undo deployment/api-server revierte a la revisión anterior. kubectl rollout undo deployment/api-server --to-revision=3 salta a una versión específica. El revisionHistoryLimit controla cuántos ReplicaSets viejos se retienen — configura al menos 3 en producción por seguridad.

Para servicios críticos, agrega un valor de minReadySeconds (ej: 30 segundos) para frenar los rollouts. Esto te da tiempo para observar tasas de error antes de que el siguiente lote de Pods sea reemplazado. Combina con alertas de Prometheus: si la tasa de error sube durante un rollout, dispara un rollback automático vía CI/CD. En producción, Helm + GitLab CI orquestan deployments estilo canary chequeando tasas de error de Prometheus entre pasos del rollout.

# Check rollout status
kubectl rollout status deployment/api-server

# View revision history
kubectl rollout history deployment/api-server

# Rollback to previous version
kubectl rollout undo deployment/api-server

# Rollback to specific revision
kubectl rollout undo deployment/api-server --to-revision=3

Monitoreo con Prometheus/Grafana

Prometheus es el estándar de facto para monitoreo de Kubernetes. Scrapea métricas del API server de Kubernetes, kubelet, node-exporter, y el endpoint /metrics de tu aplicación. El Helm chart kube-prometheus-stack despliega Prometheus, Grafana, Alertmanager y dashboards preconfigurados en un solo comando. En GKE, Google Cloud Managed Service for Prometheus (GMP) ofrece una alternativa totalmente gestionada.

Métricas esenciales a monitorear: container_cpu_usage_seconds_total y container_memory_working_set_bytes para consumo de recursos, kube_pod_status_phase para salud de Pods, apiserver_request_duration_seconds para latencia del control plane, y métricas custom de aplicación (tasa de requests, tasa de errores, percentiles de latencia — el método RED). Alerta sobre: loops de reinicio de Pods (CrashLoopBackOff), OOM kills, nodo NotReady, umbrales de capacidad de PVC, y expiración de certificados.

Los dashboards de Grafana visualizan datos de Prometheus. Usa los dashboards de la comunidad para overview del cluster (ID 315), métricas de nodo (ID 1860), y uso de recursos por namespace (ID 12740). Construye dashboards custom para las métricas de negocio de tu aplicación. En producción, un solo dashboard de Grafana por microservicio muestra tasa de requests, tasa de errores, latencia p99, CPU/memoria y utilización del pool de conexiones de base de datos — permitiendo a los ingenieros diagnosticar problemas en menos de 60 segundos.

METRIC

Método RED

Rate (requests/seg), Errors (requests fallidos/seg), Duration (histograma de latencia). La triada esencial para monitorear cualquier microservicio. Expón vía endpoint /metrics.

METRIC

Método USE

Utilización, Saturación, Errores — para recursos de infraestructura (CPU, memoria, disco, red). Detecta cuellos de botella de recursos antes de que causen outages.

METRIC

Alertas basadas en SLO

Alerta sobre tasa de consumo de error budget, no fallas individuales. Alertas multi-ventana multi-burn-rate reducen falsos positivos mientras detectan degradación real temprano.

Técnicas de Debugging

El debugging en Kubernetes sigue un patrón sistemático: chequea estado del Pod, lee eventos, inspecciona logs y entra al contenedor con exec. Empieza con kubectl get pods -n production para ver estado. CrashLoopBackOff significa que el contenedor sigue crasheando — chequea logs. ImagePullBackOff significa que no se puede bajar la imagen — verifica el tag de la imagen y credenciales del registry. Pending significa que ningún nodo tiene suficientes recursos — chequea capacidad del nodo con kubectl describe node.

kubectl describe pod muestra eventos, condiciones y asignación de recursos. Mira la sección Events al final para fallas de scheduling, fallas de probes y OOM kills. kubectl logs pod-name -c container-name --previous muestra logs de la instancia anterior (crasheada) del contenedor. Para Pods multi-contenedor, siempre especifica el nombre del contenedor con -c.

Para debugging en vivo, kubectl exec -it pod-name -- /bin/sh abre un shell dentro del contenedor. Usa kubectl port-forward pod-name 3000:3000 para acceder al puerto de un Pod desde tu máquina local sin Ingress. kubectl debug crea un contenedor de debug efímero con herramientas (curl, dig, strace) conectado a un Pod en ejecución — invaluable para imágenes distroless que no tienen shell.

# Pod overview with wide output
kubectl get pods -n production -o wide

# Detailed Pod information and events
kubectl describe pod api-server-7d8f6b5c4-xk2mn -n production

# Logs from current and previous container
kubectl logs api-server-7d8f6b5c4-xk2mn -n production
kubectl logs api-server-7d8f6b5c4-xk2mn -n production --previous

# Interactive shell
kubectl exec -it api-server-7d8f6b5c4-xk2mn -n production -- /bin/sh

# Port-forward for local access
kubectl port-forward pod/api-server-7d8f6b5c4-xk2mn 3000:3000 -n production

# Ephemeral debug container
kubectl debug -it api-server-7d8f6b5c4-xk2mn --image=busybox --target=api

CRDs y Operators

Las Custom Resource Definitions (CRDs) extienden la API de Kubernetes con tus propios tipos de recursos. Una vez registrada una CRD, puedes crear, leer, actualizar y eliminar instancias de ese recurso custom usando kubectl igual que los recursos built-in. Las CRDs son la base del modelo de extensión de Kubernetes — el VirtualService de Istio, el Certificate de Cert-Manager y el ServiceMonitor del Prometheus Operator son todos CRDs.

Un Operator es un controlador custom que observa CRDs y automatiza la gestión del ciclo de vida de aplicaciones complejas. En vez de correr manualmente backups de base de datos, failovers o upgrades, un Operator codifica ese conocimiento operacional en código. El patrón Operator sigue un loop de reconciliación: observar el estado deseado (el spec del recurso custom), compararlo con el estado real y tomar acción para converger. Operators populares incluyen Prometheus Operator, PostgreSQL Operator (Zalando) y Redis Operator.

En producción, las CRDs de Cert-Manager automatizan el aprovisionamiento de certificados TLS desde Let's Encrypt. El External Secrets Operator sincroniza secrets desde Google Secret Manager hacia Kubernetes. La CRD ServiceMonitor del Prometheus Operator autodescubre targets de scraping para cada microservicio — no se necesita config manual de Prometheus cuando se despliega un nuevo servicio.

# Example: Cert-Manager Certificate CRD
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: api-tls
  namespace: production
spec:
  secretName: api-tls-secret
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer
  dnsNames:
  - api.example.com
  - api.example.com

Políticas de Red

Por defecto, todos los Pods en un cluster Kubernetes pueden comunicarse con cualquier otro Pod. Las Network Policies son reglas de firewall a nivel de Pod que controlan tráfico ingress y egress usando selectores de labels, selectores de namespace y bloques IP. Siguen un modelo de whitelist: una vez que una NetworkPolicy selecciona un Pod, solo el tráfico explícitamente permitido lo alcanza. Se requiere un plugin CNI que soporte NetworkPolicy (Calico, Cilium, Weave Net) — GKE usa Dataplane V2 (basado en Cilium) para soporte nativo.

Empieza con una política default-deny por namespace y después agrega reglas específicas de permitir. Este enfoque zero-trust asegura que un Pod comprometido no pueda alcanzar servicios no relacionados. Por ejemplo, el servicio de pagos solo debería aceptar ingress del API gateway y solo tener egress hacia la base de datos y la API de Stripe. Las Network Policies hacen esto aplicable a nivel de infraestructura.

En producción, cada namespace de producción tiene una política default-deny de ingress. El Helm chart de cada microservicio incluye una NetworkPolicy que permite ingress solo desde sus consumidores conocidos y egress solo hacia sus dependencias. Esta segmentación contuvo un incidente de seguridad donde un sidecar de logging comprometido no pudo alcanzar la base de datos de pagos gracias a la política aplicada.

# Default deny all ingress in a namespace
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-ingress
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Ingress
---
# Allow API gateway to reach payment service
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-gateway-to-payment
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: payment-service
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: api-gateway
    ports:
    - port: 3000
      protocol: TCP

Storage: PersistentVolumes y PVCs

Los contenedores pierden todos los datos cuando se reinician. Para workloads stateful, Kubernetes provee la abstracción PersistentVolume (PV) y PersistentVolumeClaim (PVC). Un PV representa una pieza de almacenamiento en el cluster (un disco en la nube, NFS share o SSD local). Un PVC es una solicitud de almacenamiento por un Pod. Cuando se crea un PVC, Kubernetes lo vincula a un PV disponible que satisfaga el tamaño y modo de acceso solicitados. El aprovisionamiento dinámico vía StorageClasses elimina la necesidad de pre-crear PVs — el proveedor de nube crea el disco on demand.

Los modos de acceso definen cómo se puede montar un volumen: ReadWriteOnce (lectura-escritura en un solo nodo, el más común), ReadOnlyMany (solo lectura en múltiples nodos), y ReadWriteMany (lectura-escritura en múltiples nodos, requiere NFS o un filesystem distribuido como GlusterFS). Las políticas de reclamo controlan qué pasa cuando se elimina un PVC: Retain mantiene los datos para recuperación manual, Delete elimina el almacenamiento subyacente. Siempre usa Retain para bases de datos de producción.

Los StatefulSets usan volumeClaimTemplates para crear automáticamente un PVC por réplica. Esto asegura que cada instancia de base de datos tenga su propio disco dedicado que persiste a través del rescheduling de Pods. En producción, MySQL corre como StatefulSet con StorageClass pd-ssd en GKE, aprovisionando PersistentDisks SSD de 100Gi por réplica. Prometheus usa un PVC de 500Gi para retención de métricas, monitoreado con alertas al 80% de capacidad para prevenir pérdida de datos.

# StorageClass for GKE SSD
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast-ssd
provisioner: pd.csi.storage.gke.io
parameters:
  type: pd-ssd
reclaimPolicy: Retain
volumeBindingMode: WaitForFirstConsumer
---
# PVC requesting 100Gi SSD
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-data
spec:
  accessModes: ["ReadWriteOnce"]
  storageClassName: fast-ssd
  resources:
    requests:
      storage: 100Gi

Caso Real: Cluster GKE en Producción

La plataforma corre 26 microservicios en un cluster GKE con service mesh Istio, sirviendo negocios fitness en múltiples países. Este ambiente de producción demuestra cada concepto de esta guía a escala — desde tuning de recursos que eliminó cascadas de OOM hasta configuraciones de HPA que manejan picos de tráfico de 10x durante horas pico del gym.

20+ Microservicios

Cada servicio corre como Deployment con requests/limits tuneados, escalado HPA y sidecar Istio. Los servicios se comunican vía gRPC y REST sobre el mesh con mTLS automático.

Victoria en Debugging de OOM

El servicio de pagos sufría fallas intermitentes rastreadas a OOM kills. Métricas de memoria de Prometheus + profiling de heap revelaron un leak en el pool de conexiones. Se corrigió el leak y se subieron limits de 256Mi a 512Mi — 98% menos incidentes.

Service Mesh Istio

Mesh Istio completo con mTLS, gestión de tráfico y distributed tracing vía Jaeger. Circuit breakers protegen servicios downstream. Deployments canary rutean 5% del tráfico a nuevas versiones antes del rollout completo.

Gateway API: El Sucesor de Ingress

La Gateway API de Kubernetes es la sucesora oficial del recurso Ingress, diseñada por SIG Network para abordar las limitaciones de Ingress. Gateway, GatewayClass y HTTPRoute graduaron a GA (v1.0) en octubre 2023 y siguen evolucionando -- v1.4.0 (octubre 2025) agregó BackendTLSPolicy al canal Standard, TLSRoute GA y mejoró las pruebas de conformidad. Gateway API es el camino recomendado para todos los nuevos despliegues de Kubernetes.

Esto es especialmente urgente porque el Ingress NGINX Controller fue retirado en marzo de 2026. El mantenimiento cesó sin más releases, bugfixes ni parches de seguridad. Dado que ~50% de los entornos cloud-native dependían de Ingress NGINX, el Comité Directivo de Kubernetes y el Comité de Respuesta de Seguridad recomiendan migración inmediata a Gateway API u otro ingress controller soportado (Envoy Gateway, Istio, Traefik, Contour).

Gateway API introduce un modelo orientado a roles con separación clara de responsabilidades: GatewayClass (el proveedor de infraestructura define tipos de gateway disponibles), Gateway (el operador del cluster configura listeners, puertos y TLS), y HTTPRoute/TLSRoute/GRPCRoute (el desarrollador de aplicación define reglas de ruteo). Esta separación permite a los equipos de plataforma gestionar infraestructura mientras los desarrolladores controlan su propio ruteo sin permisos elevados.

Ventajas Clave Sobre Ingress

# Gateway API: GatewayClass + Gateway + HTTPRoute
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: istio
spec:
  controllerName: istio.io/gateway-controller
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: app-gateway
  namespace: infra
spec:
  gatewayClassName: istio
  listeners:
  - name: https
    protocol: HTTPS
    port: 443
    tls:
      mode: Terminate
      certificateRefs:
      - name: app-tls-cert
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: api-routes
  namespace: app
spec:
  parentRefs:
  - name: app-gateway
    namespace: infra
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /api/v2
    backendRefs:
    - name: api-v2
      port: 8080
      weight: 90
    - name: api-v2-canary
      port: 8080
      weight: 10
Si estás corriendo Ingress NGINX, empieza a migrar a Gateway API ahora. El Ingress NGINX Controller recibió su release final en marzo de 2026 -- no se emitirán más parches de seguridad. Gateway API es soportada por todos los ingress controllers principales y es el estándar recomendado por Kubernetes SIG Network.

Últimas Características de Kubernetes (2025-2026)

In-Place Pod Resize (GA en 1.35): Ahora puedes cambiar recursos de CPU y memoria en Pods en ejecución sin reiniciarlos. Las disminuciones de límite de memoria ahora están permitidas, no solo los aumentos. Esta es una capacidad mayor de producción -- antes, cualquier cambio de recursos requería un reinicio del Pod, causando breve downtime. Para workloads stateful y batch jobs de larga duración, in-place resize elimina disrupciones innecesarias. Combinado con VPA en modo Auto, los clusters pueden redimensionar contenedores continuamente sin el ciclo de desalojar y recrear.

Native Sidecar Containers (GA en 1.33): Kubernetes ahora tiene soporte de primera clase para contenedores sidecar vía restartPolicy: Always en init containers. Los sidecars nativos arrancan antes que los contenedores regulares y corren durante todo el ciclo de vida del Pod, resolviendo el problema de larga data del ordenamiento y shutdown de sidecars. Istio, agentes de logging y otros workloads sidecar se benefician de una gestión apropiada del ciclo de vida -- los sidecars ahora terminan después de que el contenedor principal sale, y los Jobs con sidecars se completan correctamente en vez de colgarse indefinidamente.

Dynamic Resource Allocation (DRA) (GA en 1.34): DRA provee una API estandarizada de Kubernetes para solicitar y gestionar GPUs, FPGAs y otro hardware especializado. En vez de depender de device plugins con inteligencia de scheduling limitada, DRA habilita asignación granular de recursos con parámetros específicos del vendor. Esto es crítico para workloads AI/ML: los equipos reportan 20-35% de reducción de costos de GPU a través de mejor scheduling y sharing. DRA soporta parámetros estructurados para matching preciso de recursos y gestión de claims entre reinicios de Pod.

Pod-Level Resources (Beta en 1.35): Un nuevo campo spec.resources a nivel de Pod te permite establecer límites agregados de CPU y memoria para todos los contenedores en un Pod. En vez de especificar recursos por contenedor y esperar que la suma funcione, defines un presupuesto a nivel de Pod. El kubelet aplica el límite agregado vía un cgroup compartido. Esto simplifica la gestión de recursos para Pods multi-contenedor y sidecars, asegurando que el consumo total del Pod se mantenga dentro de los límites sin importar qué contenedor esté activo.

Kubernetes v1.36 "Haru" (lanzado 22 de abril de 2026) incluye 70 mejoras rastreadas: 18 graduando a stable, 25 a beta y 25 nuevas alpha features. Las promociones GA destacadas incluyen User Namespaces en Pods para contenedores verdaderamente rootless, OCI VolumeSource para ejecutar imágenes OCI como volúmenes, MutatingAdmissionPolicy para control de admisión sin webhooks, SELinux volume mounting (reemplazando re-etiquetado recursivo con etiquetas en tiempo de montaje) y autorización granular de API de kubelet para seguridad a nivel de nodo. HPAScaleToZero ahora está habilitado por defecto, permitiendo al Horizontal Pod Autoscaler escalar Deployments a cero réplicas cuando no hay demanda -- una feature introducida en v1.16 (2019). Las nuevas alpha features apuntan a workloads AI/ML con preemption consciente de workload para jobs de entrenamiento y streams de API fragmentados para clusters a gran escala. El plugin de volumen gitRepo y el modo IPVS en kube-proxy se eliminan en este release.

Ingress NGINX oficialmente retirado: Kubernetes SIG Network y el Comité de Respuesta de Seguridad retiraron el Ingress NGINX Controller en marzo de 2026. No habrá más releases, bugfixes ni parches de seguridad. Dado que aproximadamente el 50% de los entornos cloud-native dependían de Ingress NGINX, todos los equipos deben migrar a Gateway API u otro ingress controller soportado (Envoy Gateway, Istio, Traefik, Contour) inmediatamente. Gateway API es el estándar recomendado en adelante, soportado por todos los controllers principales.

CRI List Streaming (Alpha en 1.36): En nodos a gran escala ejecutando cientos de contenedores, las requests List monolíticas tradicionales del kubelet al runtime de contenedores causaban presión de memoria y picos de latencia. CRI list streaming reemplaza estas con RPC de streaming server-side, reduciendo significativamente la asignación de memoria durante operaciones de listado de contenedores. Esto es crítico para nodos AI/ML con muchos contenedores sidecar e init containers.

GA 1.35

In-Place Pod Resize

Cambia CPU/memoria en Pods en ejecución sin reinicio. Disminuciones de límite de memoria ahora permitidas. Elimina disrupciones innecesarias para workloads stateful.

GA 1.33

Native Sidecar Containers

Sidecars de primera clase con restartPolicy: Always en init containers. Ordenamiento apropiado de arranque/shutdown. Jobs con sidecars ahora se completan correctamente.

GA 1.34

Dynamic Resource Allocation

API estandarizada para GPUs y hardware especializado. 20-35% de reducción de costos de GPU con mejor scheduling. Crítico para workloads AI/ML en Kubernetes.

BETA 1.35

Pod-Level Resources

Límites de recursos agregados para todos los contenedores en un Pod vía spec.resources. Simplifica la gestión de recursos multi-contenedor y sidecar.

v1.36

Highlights de Kubernetes v1.36

Lanzado 22 de abril de 2026. User Namespaces GA (contenedores rootless), OCI VolumeSource GA, HPAScaleToZero activo por defecto, MutatingAdmissionPolicy GA. Ingress NGINX retirado -- migrar a Gateway API.

# In-Place Pod Resize: patch resources without restart
kubectl patch pod api-server -p '{
  "spec": {"containers": [{"name": "api",
    "resources": {"requests": {"memory": "512Mi"},
      "limits": {"memory": "1Gi", "cpu": "500m"}}}]}
}'

# Native Sidecar Container
apiVersion: v1
kind: Pod
spec:
  initContainers:
  - name: log-collector
    image: fluent-bit:3.2
    restartPolicy: Always # makes it a native sidecar
  containers:
  - name: app
    image: myapp:v2

# Pod-Level Resources (Beta 1.35)
apiVersion: v1
kind: Pod
spec:
  resources:
    limits:
      cpu: "2"
      memory: 2Gi
  containers:
  - name: app
    image: myapp:v2
  - name: sidecar
    image: envoy:1.32

Más Guías