Módulo 3: Configuration Secrets Health And Autoscaling

1. Introducción al módulo: lo que un Deployment solo no te da

Descripción

El Módulo 2 terminó con un checklist que se veía completo: un Deployment con tres réplicas, un ReplicaSet reponiendo Pods borrados a propósito, un Service balanceando tráfico real entre las tres — y una verificación honesta de que /shipments/4471 seguía respondiendo 500, porque andes-cargo-status-api todavía no tenía ninguna forma de hablarle a una base de datos. Este módulo empieza exactamente ahí, con una pregunta que ese checklist deja abierta a propósito: ¿tres réplicas corriendo es lo mismo que "listo para producción"? La respuesta corta, que el resto de este módulo demuestra con evidencia real, es no — y las tres razones exactas de por qué no son las tres piezas que vas a construir aquí.

Conexión con el módulo

Este módulo toma el mismo Deployment andes-cargo-status-api que dejó el Módulo 2 —sano, balanceado, con tres réplicas— y le agrega, en orden, las tres cosas que le faltan para dejar de ser un experimento de laboratorio y empezar a parecerse a un servicio de producción real: configuración externalizada (ConfigMap/Secret, lecciones 2-4), verificación de salud (liveness/readiness/startup probes, lecciones 5-6), y capacidad elástica (HorizontalPodAutoscaler, lecciones 7-8). Ninguna de las tres es opcional en un clúster real — las tres son, en conjunto, la diferencia entre "corre" y "está listo para que alguien más dependa de él".


Las tres preguntas que "3 réplicas corriendo" no responde

Vuelve al checklist final del Módulo 2 (kubectl get all -n andes-cargo): un Deployment en 3/3, un Service con tres Endpoints, todo Running. Esa foto responde una pregunta —"¿el número de Pods que declaré coincide con el número de Pods que existen?"— pero deja sin responder otras tres, cada una con consecuencias reales el día que este sistema tuviera que sostener tráfico de verdad:

Pregunta 1 — ¿De dónde saca su configuración este servicio, y qué pasa cuando esa configuración cambia? Hoy, andes-cargo-status-api no tiene ninguna variable de entorno configurada — es exactamente por eso que /shipments/<id> falla con NoCredentialsError (Módulo 2, lección 7). Pero incluso si tuviera esas variables, ¿dónde vivirían? La respuesta ingenua —"dentro del Dockerfile, como un ENV fijo"— crea un problema real: cada vez que el endpoint de LocalStack cambiara (de un entorno de prueba a otro, de kind a un clúster real), habría que reconstruir la imagen entera. Las lecciones 2-4 de este módulo resuelven esto con ConfigMap y Secret: la configuración vive fuera de la imagen, se monta al arrancar el Pod, y cambia sin ningún docker build.

Pregunta 2 — ¿Cómo sabe Kubernetes si un Pod "está corriendo" es lo mismo que "está listo para atender tráfico"? Hoy, la respuesta es: no lo sabe, ni se lo preguntas. kubectl get pods te dice STATUS: Running en cuanto el proceso dentro del contenedor arranca — pero "el proceso arrancó" y "el proceso puede atender una solicitud HTTP con sentido" no son lo mismo, y esta guía todavía no le ha dado a Kubernetes ninguna forma de distinguirlos. Si andes-cargo-status-api se colgara —sin crashear, solo dejando de responder— el Service seguiría enviándole tráfico indefinidamente, porque nada le avisa que dejó de estar sano. Las lecciones 5-6 resuelven esto con probes.

Pregunta 3 — ¿Qué pasa si el tráfico se multiplica por diez mañana? Hoy, la respuesta es: nada, hasta que alguien note el problema y edite deployment.yaml a mano para subir replicas. Tres réplicas es un número que decidiste, una vez, sin ninguna relación con la carga real que el sistema recibe en cada momento — puede sobrar toda la noche y faltar en la hora pico. Las lecciones 7-8 resuelven esto con el HorizontalPodAutoscaler, que ajusta el número de réplicas solo, según una métrica real.

                  LO QUE EL MÓDULO 2 DEJÓ, Y LO QUE ESTE MÓDULO AGREGA

  ┌─────────────────────────────────────────────────────────────────┐
  │  andes-cargo-status-api          3/3 réplicas, balanceado          │
  │  status-api-service (ClusterIP)  Endpoints correctos                │
  │  /health                         200 OK                             │
  │  /shipments/<id>                 500 (NoCredentialsError, honesto)  │
  └──────────────────────────────┬──────────────────────────────────┘
                                    │
        ┌───────────────────────────┼───────────────────────────┐
        ▼                           ▼                           ▼
  ConfigMap/Secret            probes                      HorizontalPodAutoscaler
  (lecciones 2-4)             (lecciones 5-6)              (lecciones 7-8)
  configuración fuera         Kubernetes distingue         réplicas ajustadas
  de la imagen                "corre" de "está listo"      por métrica real, no
                                                             por número fijo

Analogía: el hotel que ya recibe huéspedes, pero no pasó la inspección

El Módulo 2 dejó al hotel de Andes Cargo con tres habitaciones ocupadas y una recepción (Deployment) que garantiza que ese número nunca baje. Eso es real, y es un logro — pero cualquier hotel sabe que "tener huéspedes" no es lo mismo que "estar certificado para operar". Faltan tres cosas, exactamente las tres de este módulo: un manual de operación separado de la estructura del edificio —el menú de servicio a la habitación no está pintado en la pared, vive en una carpeta que se actualiza sin romper ni un ladrillo (ConfigMap/Secret)—; una rutina de inspección de salud, no solo "hay alguien registrado en la habitación", sino "esa persona responde si tocas la puerta, y si no responde después de varios intentos, hay que reemplazarla" (probes); y una política de personal que se ajusta a la ocupación real, no un número de recepcionistas fijo decidido una vez y nunca revisado, sino uno que sube en fin de semana largo y baja entre semana, según la demanda real (HorizontalPodAutoscaler). Ningún hotel real opera sin las tres — y ningún clúster de Kubernetes en producción tampoco.


Mapa de este módulo

#LecciónQué resuelve
2ConfigMap: separar configuración de imagenPor qué el endpoint de LocalStack no vive en el Dockerfile
3Secret: por qué una credencial nunca vive en la imagenEl mismo problema que el ConfigMap, con la capa adicional de que es sensible
4Manos a la obra: ConfigMap + Secret realesMontados en andes-cargo-status-api, sin rebuild de imagen
5liveness, readiness y startup probesQué pregunta cada sonda, y qué hace Kubernetes con la respuesta
6Manos a la obra: probes reales, con fallos inducidosUn fallo de readiness (sale del Service) y uno de liveness (se reinicia), observados de verdad
7HorizontalPodAutoscaler: escalar por métricasmetrics-server en kind, y el HPA sobre CPU
8Proyecto: andes-cargo-status-api bajo cargaCarga real que dispara el HPA, réplicas subiendo y bajando solas

Al cerrar este módulo, andes-cargo-status-api va a tener las tres piezas que le faltaban — y el Módulo 4 va a exponer ese mismo servicio, ya más maduro, al tráfico externo del clúster con Ingress.


Errores comunes

Pensar que este módulo "arregla" /shipments/<id> por completo (de expectativa, el más importante de prevenir antes de empezar). Qué pasa: alguien llega a este módulo esperando que, al terminar la lección 4 (ConfigMap/Secret), el endpoint /shipments/<id> finalmente responda 200 con datos reales. Por qué pasa: es fácil asumir que "agregar la configuración que faltaba" resuelve el problema completo de un tirón. Cómo detectarlo: si te sorprende que la lección 4 siga mostrando un error después de montar ConfigMap/Secret. Cómo corregirlo: recuerda la honestidad explícita del diseño de esta guía — el ConfigMap/Secret de este módulo le dan a andes-cargo-status-api las credenciales y la dirección donde buscar, pero ningún módulo de esta guía instala LocalStack dentro del clúster (la capa de datos queda fuera de su alcance $0). El error va a cambiar de forma —de NoCredentialsError a un error de conexión— pero seguir existiendo es el comportamiento correcto, y se mantiene así hasta el capstone.

Asumir que las tres piezas de este módulo son independientes entre sí (conceptual). Qué pasa: alguien trata ConfigMap, probes y HPA como tres temas sin relación, en vez de ver que las tres construyen, en conjunto, la misma idea: un servicio que Kubernetes puede administrar sin intervención humana constante. Por qué pasa: cada lección se enseña por separado, con su propio ejemplo. Cómo detectarlo: si no puedes explicar, en una frase, por qué las tres piezas pertenecen al mismo módulo. Cómo corregirlo: piensa en el diagrama de esta lección — configuración externalizada, verificación de salud y capacidad elástica son las tres condiciones que, juntas, hacen posible que Kubernetes reconcilie el estado del sistema sin que nadie edite un YAML a mano cada vez que algo cambia. Es la misma idea del bucle de control del Módulo 2 (lección 3), aplicada a tres dimensiones nuevas.

Saltarse el checklist final del Módulo 2 antes de empezar aquí (de flujo). Qué pasa: alguien empieza este módulo sin confirmar que su clúster sigue en el estado exacto que dejó el Módulo 2 —tres réplicas sanas, Service balanceando— y se encuentra, más adelante, con errores que en realidad vienen de un estado de partida distinto. Cómo detectarlo: si kubectl get all -n andes-cargo no muestra exactamente un Deployment andes-cargo-status-api en 3/3 y un Service status-api-service. Cómo corregirlo: antes de la lección 2, corre kubectl get all -n andes-cargo y compara contra el checklist final del Módulo 2, lección 8. Si algo no coincide, vuelve ahí antes de seguir.


Ejercicios

Ejercicio 1 — Nombra las tres preguntas sin volver a leer la lección. Sin volver a la sección correspondiente, escribe las tres preguntas que "3 réplicas corriendo" no responde, y qué pieza de este módulo resuelve cada una.

Ver solución
  1. ¿De dónde saca su configuración este servicio, y qué pasa cuando cambia? — resuelto por ConfigMap/Secret (lecciones 2-4).
  2. ¿Cómo sabe Kubernetes si un Pod que corre está listo para atender tráfico? — resuelto por liveness/readiness/startup probes (lecciones 5-6).
  3. ¿Qué pasa si el tráfico se multiplica de golpe? — resuelto por el HorizontalPodAutoscaler (lecciones 7-8).

Ejercicio 2 — Explica la analogía del hotel a un colega que no la leyó. En dos o tres frases, sin usar la palabra "Kubernetes", explica por qué un hotel con habitaciones ocupadas todavía podría no estar listo para operar, usando los mismos tres huecos de esta lección.

Ver solución

Una explicación razonable: "Tener huéspedes no es lo mismo que estar certificado para operar. Falta un manual de servicio que se pueda actualizar sin remodelar el edificio, una rutina que confirme que cada huésped sigue realmente ahí (no solo que se registró alguna vez), y una política de personal que suba y baje según cuánta gente hay hoy, no un número fijo decidido una vez y nunca revisado."

Ejercicio 3 — Predice qué error vas a seguir viendo en la lección 4. Con la honestidad de esta lección delante, predice: después de que la lección 4 monte ConfigMap y Secret en andes-cargo-status-api, ¿vas a poder confirmar /shipments/4471 con un 200 real? Justifica tu respuesta.

Ver solución

No — vas a seguir viendo un error, aunque de un tipo distinto al NoCredentialsError del Módulo 2. Con las credenciales y el endpoint configurados, boto3 ya no va a fallar por falta de credenciales, pero va a fallar al intentar conectarse: DYNAMODB_ENDPOINT_URL va a apuntar a un nombre DNS (localstack.localstack.svc.cluster.local) que no existe dentro del clúster, porque ningún módulo de esta guía instala LocalStack ahí. El error cambia de forma, pero el resultado —una respuesta que no es 200— sigue siendo el comportamiento correcto en toda la guía: /health es la señal real, /shipments/<id> queda representativo.


Resumen y siguiente paso

Esta lección abrió el Módulo 3 con una pregunta honesta: el checklist "verde" que dejó el Módulo 2 —tres réplicas, balanceado, Service estable— no responde tres preguntas reales de producción: de dónde sale la configuración, cómo se distingue "corre" de "está sano", y qué pasa si el tráfico cambia. Las tres piezas de este módulo —ConfigMap/Secret, probes, HorizontalPodAutoscaler— existen exactamente para responder esas tres preguntas, en ese orden, sobre el mismo Deployment andes-cargo-status-api que ya conoces.

Antes de avanzar deberías poder: nombrar las tres preguntas que este módulo resuelve, y confirmar que tu clúster sigue en el mismo estado exacto que dejó el Módulo 2.

Siguiente lección: ConfigMap, separar configuración de imagen. Ahí empieza la primera de las tres piezas — por qué el endpoint de LocalStack nunca debería haber vivido, ni va a vivir, dentro del Dockerfile.

Recursos

  1. Kubernetes — Configuration Best Practices — la guía oficial de por qué separar configuración de imagen, el hilo que abre este módulo.
  2. aws-serverless-and-containers-guide (NIEVA), Módulo 6, lección 5 — el app.py original que lee DYNAMODB_ENDPOINT_URL/AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY/SHIPMENTS_TABLE_NAME de variables de entorno, sin ningún cambio en este módulo.
  3. kubernetes-and-eks-in-production-guide (NIEVA), Módulo 2, lección 8 — el checklist final exacto del que parte este módulo.