Módulo 3: Configuration Secrets Health And Autoscaling

6. Manos a la obra: `probes` reales sobre `status-api-service`

Descripción

Esta es la lección donde andes-cargo-status-api recibe sus tres sondas de salud, y donde vas a provocar —a propósito, de forma controlada y reversible— exactamente los dos fallos que la lección 5 describió en teoría: un Pod que sale del Service sin reiniciarse, y un Pod que se reinicia de verdad. Nada de esto se simula: vas a editar la configuración de las sondas para inducir cada fallo, observar la consecuencia real con kubectl get pods/kubectl describe, y revertir cada cambio antes de seguir. Todo lo que sigue corrió contra andes-cargo-cluster.

Conexión con el módulo

Esta lección cierra la segunda de las tres piezas de este módulo con evidencia real, exactamente como la lección 4 cerró la primera. La lección 7 agrega la tercera —capacidad elástica— sobre este mismo Deployment, ahora con configuración y salud resueltas.


Paso 1 — Agrega las tres sondas al Deployment

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: andes-cargo-status-api
  namespace: andes-cargo
  labels:
    app: andes-cargo-status-api
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  selector:
    matchLabels:
      app: andes-cargo-status-api
  template:
    metadata:
      labels:
        app: andes-cargo-status-api
    spec:
      containers:
        - name: andes-cargo-status-api
          image: andes-cargo-status-api:latest
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 8080
          envFrom:
            - configMapRef:
                name: andes-cargo-status-api-config
            - secretRef:
                name: andes-cargo-status-api-secrets
          startupProbe:
            httpGet:
              path: /health
              port: 8080
            periodSeconds: 5
            failureThreshold: 6
          readinessProbe:
            httpGet:
              path: /health
              port: 8080
            initialDelaySeconds: 2
            periodSeconds: 5
            timeoutSeconds: 3
            failureThreshold: 1
          livenessProbe:
            httpGet:
              path: /health
              port: 8080
            initialDelaySeconds: 5
            periodSeconds: 5
            timeoutSeconds: 3
            failureThreshold: 3

Dos cosas nuevas frente al deployment.yaml de la lección 4: las tres sondas (todas contra /health, como recomendó la lección 5), y strategy.rollingUpdate explícito, con maxSurge: 1/maxUnavailable: 0 — esto le dice a Kubernetes "nunca bajes de 3 réplicas disponibles durante un despliegue, y agrega como máximo 1 Pod extra a la vez". Vas a usar esta configuración a propósito en los siguientes pasos: te va a permitir inducir un fallo sobre un Pod nuevo, sin arriesgar ni un segundo de disponibilidad de los tres Pods existentes, que siguen atendiendo tráfico real todo el tiempo.

Aplica el cambio, con failureThreshold: 6 (startupProbe) dando margen de sobra para que Flask arranque —en la práctica, arranca en menos de un segundo, así que esta sonda nunca vas a verla fallar en esta guía—:

kubectl apply -f deployment.yaml
kubectl rollout status deployment/andes-cargo-status-api -n andes-cargo --timeout=60s

Qué esperar (literal, ejecutado):

deployment.apps/andes-cargo-status-api configured
Waiting for deployment "andes-cargo-status-api" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "andes-cargo-status-api" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "andes-cargo-status-api" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "andes-cargo-status-api" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "andes-cargo-status-api" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "andes-cargo-status-api" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "andes-cargo-status-api" rollout to finish: 1 old replicas are pending termination...
Waiting for deployment "andes-cargo-status-api" rollout to finish: 1 old replicas are pending termination...
deployment "andes-cargo-status-api" successfully rolled out

Confirma que las tres sondas quedaron configuradas exactamente como las declaraste:

kubectl describe pod <un-pod-tuyo> -n andes-cargo | grep -A3 "Liveness:\|Readiness:\|Startup:"

Qué esperar (literal — Kubernetes muestra los parámetros de cada sonda en una sola línea legible):

Liveness:       http-get http://:8080/health delay=5s timeout=3s period=5s #success=1 #failure=3
Readiness:      http-get http://:8080/health delay=2s timeout=3s period=5s #success=1 #failure=1
Startup:        http-get http://:8080/health delay=0s timeout=1s period=5s #success=1 #failure=6

Confirma también que los tres Pods están sanos y en la lista de Endpoints del Service:

kubectl get endpoints status-api-service -n andes-cargo

Qué esperar (tres IPs — las tuyas van a ser distintas):

Warning: v1 Endpoints is deprecated in v1.33+; use discovery.k8s.io/v1 EndpointSlice
NAME                 ENDPOINTS                                         AGE
status-api-service   10.244.1.7:8080,10.244.2.8:8080,10.244.2.9:8080   23m

Esta es tu línea base: tres Pods, tres Endpoints, cero RESTARTS. Todo lo que sigue se compara contra esta foto.


Paso 2 — Induce un fallo de readiness

Una readinessProbe no se puede editar en un Pod ya corriendo —es un campo inmutable del spec del contenedor—, así que para provocar un fallo real, vas a cambiar la ruta de la sonda en el Deployment. Con maxSurge: 1/maxUnavailable: 0, esto crea exactamente un Pod nuevo con la sonda rota, mientras tus tres Pods sanos siguen atendiendo tráfico sin ninguna interrupción:

kubectl patch deployment andes-cargo-status-api -n andes-cargo --type=json \
  -p '[{"op":"replace","path":"/spec/template/spec/containers/0/readinessProbe/httpGet/path","value":"/readyz-check"}]'

/readyz-check no existe en app.py —a propósito—, así que cualquier solicitud a esa ruta va a responder 404, y Kubernetes va a contar eso como un fallo de la sonda.

Qué esperar:

deployment.apps/andes-cargo-status-api patched

Observa lo que pasa en los siguientes segundos:

kubectl get pods -n andes-cargo -l app=andes-cargo-status-api -o wide

Qué esperar (literal, ejecutado ~20 segundos después del patch — los tres Pods viejos, sin tocar, siguen 1/1 Running; el Pod nuevo queda atascado en 0/1, Running, con RESTARTS: 0):

NAME                                      READY   STATUS    RESTARTS   AGE     IP            NODE                          NOMINATED NODE   READINESS GATES
andes-cargo-status-api-65fcd6f6c8-2bkht   1/1     Running   0          5m43s   10.244.1.7    andes-cargo-cluster-worker2   <none>           <none>
andes-cargo-status-api-65fcd6f6c8-cnbjw   1/1     Running   0          5m37s   10.244.2.9    andes-cargo-cluster-worker    <none>           <none>
andes-cargo-status-api-65fcd6f6c8-m7qf8   1/1     Running   0          5m49s   10.244.2.8    andes-cargo-cluster-worker    <none>           <none>
andes-cargo-status-api-d6cd4d46b-79hdq    0/1     Running   0          20s     10.244.2.10   andes-cargo-cluster-worker    <none>           <none>

Este es exactamente el comportamiento que la lección 5 describió: STATUS: Running (el proceso sigue vivo), READY: 0/1 (la sonda de readiness está fallando), RESTARTS: 0 (nadie reinició nada). Confirma que el Service lo notó, sin que nadie se lo dijera explícitamente:

kubectl get endpoints status-api-service -n andes-cargo

Qué esperar (literal — exactamente las mismas tres IPs de antes; el Pod nuevo, 10.244.2.10, no aparece):

Warning: v1 Endpoints is deprecated in v1.33+; use discovery.k8s.io/v1 EndpointSlice
NAME                 ENDPOINTS                                         AGE
status-api-service   10.244.1.7:8080,10.244.2.8:8080,10.244.2.9:8080   28m

El Pod con la sonda rota nunca llegó a la lista de Endpoints — el Service sigue enrutando tráfico únicamente hacia los tres Pods sanos, exactamente como prometió la lección 5. Confirma la causa exacta con kubectl describe:

kubectl describe pod andes-cargo-status-api-d6cd4d46b-79hdq -n andes-cargo

Qué esperar (la sección Events, literal — sustituye el nombre de Pod por el tuyo):

Events:
  Type     Reason     Age               From               Message
  ----     ------     ----              ----               -------
  Normal   Scheduled  29s               default-scheduler  Successfully assigned andes-cargo/andes-cargo-status-api-d6cd4d46b-79hdq to andes-cargo-cluster-worker
  Normal   Pulled     28s               kubelet            spec.containers{andes-cargo-status-api}: Container image "andes-cargo-status-api:latest" already present on machine and can be accessed by the pod
  Normal   Created    28s               kubelet            spec.containers{andes-cargo-status-api}: Container created
  Normal   Started    28s               kubelet            spec.containers{andes-cargo-status-api}: Container started
  Warning  Unhealthy  3s (x5 over 23s)  kubelet            spec.containers{andes-cargo-status-api}: Readiness probe failed: HTTP probe failed with statuscode: 404

Readiness probe failed: HTTP probe failed with statuscode: 404 — el mensaje exacto de Kubernetes, sin ambigüedad sobre la causa. También confirma que, mientras tanto, el rollout está genuinamente estancado —Kubernetes está esperando, sin límite de tiempo, a que este Pod nuevo pase su readinessProbe antes de continuar reemplazando los Pods viejos:

kubectl rollout status deployment/andes-cargo-status-api -n andes-cargo --timeout=5s

Qué esperar (el comando agota su propio timeout de 5 segundos — el rollout en sí sigue detenido indefinidamente hasta que intervengas):

Waiting for deployment "andes-cargo-status-api" rollout to finish: 1 out of 3 new replicas have been updated...
error: timed out waiting for the condition

Paso 3 — Corrige la ruta, y confirma la recuperación

kubectl patch deployment andes-cargo-status-api -n andes-cargo --type=json \
  -p '[{"op":"replace","path":"/spec/template/spec/containers/0/readinessProbe/httpGet/path","value":"/health"}]'
kubectl rollout status deployment/andes-cargo-status-api -n andes-cargo --timeout=60s

Qué esperar:

deployment.apps/andes-cargo-status-api patched
deployment "andes-cargo-status-api" successfully rolled out
kubectl get pods -n andes-cargo -l app=andes-cargo-status-api -o wide

Qué esperar (algo notable: al revertir la ruta, la plantilla vuelve a coincidir exactamente con la del ReplicaSet original —mismo hash 65fcd6f6c8—, así que Kubernetes no crea Pods nuevos: simplemente termina el Pod con la sonda rota y confirma que tus tres Pods originales, que nunca dejaron de correr, siguen exactamente igual):

NAME                                      READY   STATUS    RESTARTS   AGE
andes-cargo-status-api-65fcd6f6c8-2bkht   1/1     Running   0          6m11s
andes-cargo-status-api-65fcd6f6c8-cnbjw   1/1     Running   0          6m5s
andes-cargo-status-api-65fcd6f6c8-m7qf8   1/1     Running   0          6m17s

Cero RESTARTS, en los tres — exactamente como predijo la lección 5: un fallo de readiness nunca reinicia nada, solo retira temporalmente del tráfico. Ese Pod estuvo fuera del Service durante todo el experimento, y ninguno de los tres Pods "de verdad" se enteró de que algo andaba mal.


Paso 4 — Induce un fallo de liveness

Ahora el segundo experimento: rompe la ruta de livenessProbe (dejando readinessProbe correcta) para ver la otra consecuencia.

kubectl patch deployment andes-cargo-status-api -n andes-cargo --type=json \
  -p '[{"op":"replace","path":"/spec/template/spec/containers/0/livenessProbe/httpGet/path","value":"/livez-check"}]'

Qué esperar:

deployment.apps/andes-cargo-status-api patched

Esta vez, como la sonda de readiness sí es correcta, el Pod nuevo se vuelve Ready y entra al Service casi de inmediato — el RollingUpdate avanza con normalidad, reemplazando los tres Pods viejos por tres Pods nuevos con la sonda de liveness rota. Observa la secuencia completa con kubectl get pods:

kubectl get pods -n andes-cargo -l app=andes-cargo-status-api -o wide

Qué esperar (unos segundos después del patch — el rollout ya avanzó, tres Pods nuevos 1/1 Ready, RESTARTS: 0 todavía, porque el livenessProbe recién empieza a evaluarse):

NAME                                      READY   STATUS    RESTARTS   AGE   IP            NODE                          NOMINATED NODE   READINESS GATES
andes-cargo-status-api-7d56987475-7pxhd   1/1     Running   0          21s   10.244.2.12   andes-cargo-cluster-worker    <none>           <none>
andes-cargo-status-api-7d56987475-kn5tb   1/1     Running   0          27s   10.244.1.9    andes-cargo-cluster-worker2   <none>           <none>
andes-cargo-status-api-7d56987475-z4f5p   1/1     Running   0          32s   10.244.2.11   andes-cargo-cluster-worker    <none>           <none>

Espera unos segundos más —initialDelaySeconds: 5 más failureThreshold: 3 con periodSeconds: 5 significan que el primer reinicio llega alrededor de los 20 segundos de vida del Pod— y repite el mismo comando:

kubectl get pods -n andes-cargo -l app=andes-cargo-status-api -o wide

Qué esperar (RESTARTS empieza a subir — cada Pod, uno por uno según su propio reloj, cruza el umbral de livenessProbe):

NAME                                      READY   STATUS    RESTARTS      AGE   IP            NODE                          NOMINATED NODE   READINESS GATES
andes-cargo-status-api-7d56987475-7pxhd   1/1     Running   1 (11s ago)   62s   10.244.2.12   andes-cargo-cluster-worker    <none>           <none>
andes-cargo-status-api-7d56987475-kn5tb   1/1     Running   1 (17s ago)   68s   10.244.1.9    andes-cargo-cluster-worker2   <none>           <none>
andes-cargo-status-api-7d56987475-z4f5p   1/1     Running   1 (23s ago)   73s   10.244.2.11   andes-cargo-cluster-worker    <none>           <none>

RESTARTS: 1 en los tres — el kubelet mató y volvió a arrancar cada contenedor, sin que el Pod en sí desapareciera (mismo nombre, misma IP, mismo AGE acumulado). Confirma la causa exacta con kubectl describe:

kubectl describe pod andes-cargo-status-api-7d56987475-z4f5p -n andes-cargo

Qué esperar (la sección Events, literal — sustituye el nombre de Pod por el tuyo):

Events:
  Type     Reason     Age                From               Message
  ----     ------     ----               ----               -------
  Normal   Scheduled  79s                default-scheduler  Successfully assigned andes-cargo/andes-cargo-status-api-7d56987475-z4f5p to andes-cargo-cluster-worker
  Normal   Pulled     29s (x2 over 79s)  kubelet            spec.containers{andes-cargo-status-api}: Container image "andes-cargo-status-api:latest" already present on machine and can be accessed by the pod
  Normal   Created    29s (x2 over 79s)  kubelet            spec.containers{andes-cargo-status-api}: Container created
  Normal   Started    29s (x2 over 79s)  kubelet            spec.containers{andes-cargo-status-api}: Container started
  Warning  Unhealthy  4s (x6 over 69s)   kubelet            spec.containers{andes-cargo-status-api}: Liveness probe failed: HTTP probe failed with statuscode: 404
  Normal   Killing    4s (x2 over 59s)   kubelet            spec.containers{andes-cargo-status-api}: Container andes-cargo-status-api failed liveness probe, will be restarted

Dos mensajes literales, sin ambigüedad: Liveness probe failed: HTTP probe failed with statuscode: 404, seguido de Container andes-cargo-status-api failed liveness probe, will be restarted. Fíjate en el (x2 over 59s) de Pulled/Created/Started: este Pod específico ya llevaba dos arranques del contenedor —el original, y uno de reemplazo tras el primer fallo de liveness— con la sonda todavía rota, camino a un segundo reinicio si el problema persistiera. Este es, exactamente, el mecanismo detrás de un CrashLoopBackOff: si la causa del fallo nunca se corrige, Kubernetes sigue reiniciando, con un intervalo de espera que crece entre intento e intento.


Paso 5 — Corrige la ruta, y confirma la recuperación final

kubectl patch deployment andes-cargo-status-api -n andes-cargo --type=json \
  -p '[{"op":"replace","path":"/spec/template/spec/containers/0/livenessProbe/httpGet/path","value":"/health"}]'
kubectl rollout status deployment/andes-cargo-status-api -n andes-cargo --timeout=90s

Qué esperar:

deployment.apps/andes-cargo-status-api patched
Waiting for deployment "andes-cargo-status-api" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "andes-cargo-status-api" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "andes-cargo-status-api" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "andes-cargo-status-api" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "andes-cargo-status-api" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "andes-cargo-status-api" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "andes-cargo-status-api" rollout to finish: 1 old replicas are pending termination...
Waiting for deployment "andes-cargo-status-api" rollout to finish: 1 old replicas are pending termination...
deployment "andes-cargo-status-api" successfully rolled out
kubectl get deployment andes-cargo-status-api -n andes-cargo
kubectl get endpoints status-api-service -n andes-cargo

Qué esperar (de vuelta a 3/3 sano, con tres Endpoints — nombres de Pod e IPs nuevos frente a los del inicio de esta lección, porque esta vez sí hubo un RollingUpdate completo, no una simple terminación como en el Paso 3):

NAME                     READY   UP-TO-DATE   AVAILABLE   AGE
andes-cargo-status-api   3/3     3            3           32m
Warning: v1 Endpoints is deprecated in v1.33+; use discovery.k8s.io/v1 EndpointSlice
NAME                 ENDPOINTS                                            AGE
status-api-service   10.244.1.10:8080,10.244.2.13:8080,10.244.2.14:8080   31m

El contraste completo, en una tabla

Fallo de readiness (Paso 2)Fallo de liveness (Paso 4)
STATUSRunning, sin cambioRunning, sin cambio
READY0/11/1 (el reinicio es tan rápido que rara vez lo capturas en 0/1)
RESTARTS0, siempreSube con cada ciclo de fallo
Endpoints del ServiceEl Pod sale, sin reiniciarseEl Pod nunca sale (mientras readiness siga pasando)
Mensaje de kubectl describeReadiness probe failedLiveness probe failed + Killing... will be restarted
Consecuencia sobre tráfico existenteNinguna — el Service ya lo excluyóNinguna, mientras el Pod se recupere entre reinicios

Errores comunes

Dejar una sonda rota corriendo demasiado tiempo, y terminar en un CrashLoopBackOff real de difícil salida (de flujo, el riesgo más directo de este experimento). Qué pasa: alguien repite el Paso 4 sin revertir la sonda de inmediato después de confirmar el primer reinicio, y dos o tres ciclos de fallo después, el intervalo de espera entre reinicios (backoff) ya es de varios minutos, haciendo que la corrección tarde en reflejarse. Por qué pasa: Kubernetes usa un backoff exponencial para reinicios repetidos —cada fallo espera más que el anterior— precisamente para no saturar el sistema con reinicios constantes, pero eso significa que revertir tarde alarga la recuperación. Cómo detectarlo: si RESTARTS ya muestra 3 o más antes de que hayas corregido la ruta. Cómo corregirlo: en cuanto confirmes el mensaje Liveness probe failed en los Events (como en el Paso 4 de esta lección), revierte de inmediato — no hace falta dejar que el ciclo se repita varias veces para confirmar el mecanismo.

Confundir el Pod "atascado en 0/1" del Paso 2 con un Pod fallado o en error (de expectativa). Qué pasa: alguien ve READY: 0/1 y asume que algo se rompió gravemente, cuando en realidad el contenedor está perfectamente sano —solo que su sonda de readiness está configurada para preguntar algo que nunca va a responder que sí. Cómo detectarlo: STATUS sigue en Running, RESTARTS sigue en 0 — ninguna de las dos señales de un problema grave está presente. Cómo corregirlo: READY: 0/1 con STATUS: Running y RESTARTS: 0 es, específicamente, la firma de un fallo de readiness — revisa la sonda, no el contenedor.

Olvidar que strategy.rollingUpdate con maxUnavailable: 0 es lo que protegió a los Pods originales durante todo este experimento (conceptual). Qué pasa: alguien repite este mismo experimento en un Deployment sin esa configuración explícita (usando el valor por defecto, maxUnavailable: 25%) y se sorprende al ver que, durante el fallo de readiness, la capacidad disponible del Service sí bajó momentáneamente. Cómo detectarlo: compara maxSurge/maxUnavailable de tu deployment.yaml contra el valor por defecto de Kubernetes. Cómo corregirlo: maxUnavailable: 0 (usado en esta lección) le exige a Kubernetes mantener el 100% de las réplicas existentes disponibles durante cualquier despliegue, incluso uno que termina fallando —es una decisión deliberada de esta guía para que el experimento del Paso 2 fuera seguro de repetir sin arriesgar disponibilidad real.


Ejercicios

Ejercicio 1 — Reconstruye el contraste sin la tabla. Sin volver a la tabla de esta lección, describe, en tus propias palabras, la diferencia completa entre lo que viste en el Paso 2 y lo que viste en el Paso 4.

Ver solución

En el Paso 2 (fallo de readiness), el Pod nuevo nunca llegó a los Endpoints del Service — quedó Running con READY: 0/1, RESTARTS: 0, sin ninguna consecuencia para los tres Pods sanos que ya atendían tráfico. En el Paso 4 (fallo de liveness), como la sonda de readiness sí pasaba, los Pods nuevos sí entraron al Service con normalidad — pero después de varios fallos consecutivos de liveness, el kubelet los reinició, uno por uno, incrementando su contador de RESTARTS sin que el Pod cambiara de nombre ni de IP.

Ejercicio 2 — Explica por qué el Paso 3 no creó Pods nuevos, pero el Paso 5 sí. Ambos pasos revierten una sonda rota a /health. Explica, en dos o tres frases, por qué el Paso 3 solo terminó un Pod existente mientras que el Paso 5 disparó un RollingUpdate completo con Pods nuevos.

Ver solución

En el Paso 3, al revertir readinessProbe a /health, la plantilla completa del Deployment volvió a coincidir exactamente con el hash del ReplicaSet original (el de los tres Pods que nunca se tocaron durante el experimento) — Kubernetes reconoció que ya existían suficientes réplicas de esa plantilla exacta, así que solo terminó el Pod sobrante con la sonda rota. En el Paso 5, en cambio, los tres Pods "sanos" en ese momento ya pertenecían a un ReplicaSet nuevo (creado durante el fallo de liveness, con la sonda rota en su plantilla) — revertir la sonda creó un hash de plantilla distinto al de esos tres Pods, así que Kubernetes tuvo que reemplazarlos, uno por uno, con un RollingUpdate completo.

Ejercicio 3 — Diseña una probe para un tercer escenario. andes-cargo-status-api en un futuro módulo va a depender de una conexión persistente a una base de datos que tarda hasta 10 segundos en establecerse al arrancar. ¿Qué sonda usarías para evitar que Kubernetes mate el contenedor durante esos 10 segundos iniciales, y con qué parámetro clave?

Ver solución

Un startupProbe con failureThreshold × periodSeconds mayor a 10 segundos —por ejemplo, periodSeconds: 2 con failureThreshold: 8 (16 segundos de margen)—, apuntando al mismo /health o a un endpoint específico que confirme la conexión establecida. Mientras el startupProbe no tenga éxito, ni readinessProbe ni livenessProbe se evalúan — evitando exactamente el escenario descrito: un livenessProbe demasiado impaciente matando un contenedor que solo está tardando en establecer su conexión inicial, no roto.


Resumen y siguiente paso

Esta lección agregó las tres sondas de la lección 5 al Deployment real, y confirmó con evidencia real —no solo en teoría— las dos consecuencias centrales: un fallo de readiness induce READY: 0/1 con RESTARTS: 0, sacando al Pod de los Endpoints del Service sin ninguna interrupción para el resto; un fallo de liveness induce reinicios reales del contenedor, confirmados con RESTARTS incrementando y los mensajes exactos Liveness probe failed/Killing... will be restarted en los Events. Ambos experimentos se hicieron de forma segura, protegiendo la disponibilidad real gracias a maxUnavailable: 0, y se revirtieron por completo antes de seguir.

Antes de avanzar deberías poder: distinguir, con solo kubectl get pods, si un Pod está fallando readiness o liveness; leer los Events de kubectl describe pod para confirmar la causa exacta de cualquiera de los dos; y explicar por qué proteger maxUnavailable: 0 durante un experimento de sondas es una práctica segura y reversible.

Siguiente lección: HorizontalPodAutoscaler, escalar por métricas, no por corazonada. Con configuración y salud resueltas, el módulo cierra con la tercera pregunta de la lección 1: ¿qué pasa si el tráfico se multiplica de golpe?

Recursos

  1. Kubernetes — Configure Liveness, Readiness and Startup Probes — la misma referencia de la lección 5, ahora confirmada con evidencia real.
  2. Kubernetes — Deployments: Rolling Update Deployment — referencia oficial de maxSurge/maxUnavailable, el mecanismo que hizo seguros los experimentos de esta lección.
  3. Kubernetes — Debug Running Pods — referencia oficial de kubectl describe pod y la lectura de Events, la técnica central de diagnóstico de esta lección.