CKA · Módulo 11 K8s v1.34 Troubleshooting 30%

Red rota: bisecar el camino en vez de adivinar

Broken network: bisect the path instead of guessing

Rete rotta: bisecare il percorso invece di indovinare

«No conecta» puede ser DNS, un selector con un typo, una probe, una NetworkPolicy o el CNI. Son cinco lugares, y hay un orden para descartarlos que convierte el problema en mecánica pura.

"It does not connect" can be DNS, a typo in a selector, a probe, a NetworkPolicy or the CNI. Five places, and there is an order for ruling them out that turns the problem into pure mechanics.

«Non si connette» può essere il DNS, un selector con un refuso, una probe, una NetworkPolicy o il CNI. Cinque posti, e c'è un ordine per escluderli che trasforma il problema in pura meccanica.

Duración60 min
Duration60 min
Durata60 min
DominioTroubleshooting
DomainTroubleshooting
DominioTroubleshooting
Peso30% (3 de 3)
Weight30% (3 of 3)
Peso30% (3 di 3)
RequiereM6 · M7 · M9
RequiresM6 · M7 · M9
RichiedeM6 · M7 · M9
Último módulo de la Fase 1, y el que cierra los dos dominios más pesados: junta el Services & Networking del M6/M7 con el método del M9. La particularidad de la red es que el síntoma siempre es el mismo — un curl que no vuelve — mientras que las causas están repartidas en cinco capas distintas. Adivinar no escala: lo que funciona es partir la ruta al medio y preguntar en cada corte si el tráfico llegó hasta ahí. Dos o tres cortes bien puestos y solo queda una explicación posible.
The last module of Phase 1, and the one that closes the two heaviest domains: it joins M6/M7's Services & Networking with M9's method. What is peculiar about networking is that the symptom is always the same — a curl that never returns — while the causes are spread across five different layers. Guessing does not scale: what works is cutting the path in half and asking at each cut whether traffic got that far. Two or three well-placed cuts and only one explanation is left standing.
Ultimo modulo della Fase 1, e quello che chiude i due domini più pesanti: unisce Services & Networking di M6/M7 con il metodo di M9. La particolarità della rete è che il sintomo è sempre lo stesso — un curl che non torna — mentre le cause sono distribuite su cinque livelli diversi. Indovinare non scala: ciò che funziona è tagliare il percorso a metà e chiedere a ogni taglio se il traffico è arrivato fin lì. Due o tre tagli ben piazzati e resta una sola spiegazione possibile.
Modelo mental del módulo
Module's mental model
Modello mentale del modulo
DNS → ENDPOINTS → POLICY → POD
La ruta completa de una request interna: resolver el nombre, encontrar los endpoints del Service, atravesar las NetworkPolicies, llegar al pod y que la app conteste. Se prueba en ese orden porque cada paso depende del anterior — y porque el atajo más rápido del módulo es saltear el Service y pegarle a la IP del pod directo: si eso anda, el problema está arriba; si no anda, está abajo.
The full path of an internal request: resolve the name, find the Service's endpoints, cross the NetworkPolicies, reach the pod and have the app answer. You test it in that order because each step depends on the previous one — and because the module's fastest shortcut is to skip the Service and hit the pod IP directly: if that works, the problem is above; if it does not, it is below.
Il percorso completo di una richiesta interna: risolvere il nome, trovare gli endpoint del Service, attraversare le NetworkPolicy, raggiungere il pod e far rispondere l'app. Si prova in quest'ordine perché ogni passo dipende dal precedente — e perché la scorciatoia più rapida del modulo è saltare il Service e colpire direttamente l'IP del pod: se funziona, il problema è sopra; se non funziona, è sotto.
11.1
El método: bisecar
The method: bisect
Il metodo: bisecare
Los cortes, el pod de debug, el orden fijo.
The cuts, the debug pod, the fixed order.
I tagli, il pod di debug, l'ordine fisso.
11.2
DNS roto
Broken DNS
DNS rotto
CoreDNS, /etc/resolv.conf, FQDN, ndots.
11.3
Service sin endpoints
Service with no endpoints
Service senza endpoint
Selector, labels, puertos, readiness.
Selector, labels, ports, readiness.
Selector, label, porte, readiness.
11.4
NetworkPolicy que bloquea
NetworkPolicy that blocks
NetworkPolicy che blocca
Bloqueos silenciosos, egress y DNS.
Silent blocks, egress and DNS.
Blocchi silenziosi, egress e DNS.
11.5
kube-proxy y pod-to-pod
kube-proxy and pod-to-pod
kube-proxy e pod-to-pod
Cuando falla la capa de abajo.
When the layer below fails.
Quando cede lo strato sottostante.
★
Práctica · 8 ejercicios
Practice · 8 exercises
Pratica · 8 esercizi
Los cuatro cortes contra fallas reales, con manifest listo para aplicar.
The four cuts against real failures, each with a ready-to-apply manifest.
I quattro tagli contro guasti reali, ognuno con un manifest pronto da applicare.
11.1
La disciplina · 10 min
The discipline · 10 min
La disciplina · 10 min

Bisecar el camino

Bisecting the path

Bisecare il percorso

Cada prueba tiene que descartar la mitad de las causas.
Each test must rule out half the causes.
Ogni prova deve escludere metà delle cause.
Práctica · La secuencia
Practice · The sequence
Pratica · La sequenza

El pod de debug (ténelo a mano)

The debug pod (keep it handy)

Il pod di debug (tienilo a portata)

# Efímero, con herramientas de red# Ephemeral, with network tools# Effimero, con strumenti di rete
k run net --rm -it --image=nicolaka/netshoot -- bash

# Si no hay netshoot: busybox 1.28 (su nslookup FUNCIONA)# No netshoot? busybox 1.28 (its nslookup WORKS)# Niente netshoot? busybox 1.28 (il suo nslookup FUNZIONA)
k run t --rm -it --image=busybox:1.28 -- sh

# Dentro del pod que YA existe, sin shell propia (M9)# Inside a pod that ALREADY exists, with no shell of its own (M9)# Dentro un pod che ESISTE già, senza shell propria (M9)
k debug -it app --image=nicolaka/netshoot --target=web

Los cuatro cortes, en orden

The four cuts, in order

I quattro tagli, in ordine

# CORTE 1 — ¿resuelve el nombre?# CUT 1 — does the name resolve?# TAGLIO 1 — il nome si risolve?
nslookup web
# falla → 11.2 (DNS)    anda → seguir# fails → 11.2 (DNS)    works → carry on# fallisce → 11.2 (DNS)    funziona → prosegui

# CORTE 2 — ¿el Service tiene backends?# CUT 2 — does the Service have backends?# TAGLIO 2 — il Service ha backend?
k get endpointslices -l kubernetes.io/service-name=web
# vacío → 11.3 (selector/readiness)    hay IPs → seguir# empty → 11.3 (selector/readiness)    IPs there → carry on# vuoto → 11.3 (selector/readiness)    ci sono IP → prosegui

# CORTE 3 — ¿responde la IP del POD directo?# CUT 3 — does the POD IP answer directly?# TAGLIO 3 — l'IP del POD risponde direttamente?
curl -s --max-time 3 <IP-POD>:8080
# anda → el problema es Service/kube-proxy (11.5)# works → the problem is Service/kube-proxy (11.5)# funziona → il problema è Service/kube-proxy (11.5)
# NO anda → policy (11.4), la app, o el CNI# does NOT work → policy (11.4), the app, or the CNI# NON funziona → policy (11.4), l'app, o il CNI

# CORTE 4 — ¿la app escucha de verdad?# CUT 4 — is the app really listening?# TAGLIO 4 — l'app ascolta davvero?
k exec app -- curl -s localhost:8080
# anda desde adentro pero no desde afuera → policy o bind a 127.0.0.1# works from inside but not outside → policy, or a bind to 127.0.0.1# funziona da dentro ma non da fuori → policy, o un bind a 127.0.0.1

Distinguir los tipos de fallo

Telling failure types apart

Distinguere i tipi di guasto

curl -sv --max-time 3 web:80

# "could not resolve host"    → DNS# "could not resolve host"    → DNS# "could not resolve host"    → DNS
# "connection refused"        → LLEGÓ, nadie escucha ese puerto# "connection refused"        → IT ARRIVED, nobody listens on that port# "connection refused"        → È ARRIVATO, nessuno ascolta su quella porta
# timeout / "no route to host" → NO LLEGÓ: policy, CNI o ruteo# timeout / "no route to host" → IT DID NOT ARRIVE: policy, CNI or routing# timeout / "no route to host" → NON È ARRIVATO: policy, CNI o routing
★
«Refused» y «timeout» no son lo mismo y el examen lo aprovecha. Refused significa que el paquete llegó a destino y el kernel contestó que nadie escucha: puerto equivocado, app caída. Timeout significa que el paquete se perdió en el camino: NetworkPolicy, CNI o un Service sin endpoints. Leer bien ese mensaje te ahorra la mitad del trabajo.
"Refused" and "timeout" are not the same and the exam exploits that. Refused means the packet reached its destination and the kernel answered that nobody is listening: wrong port, app down. Timeout means the packet was lost on the way: NetworkPolicy, CNI or a Service with no endpoints. Reading that message properly saves you half the work.
«Refused» e «timeout» non sono la stessa cosa e l'esame ne approfitta. Refused significa che il pacchetto è arrivato a destinazione e il kernel ha risposto che nessuno ascolta: porta sbagliata, app caduta. Timeout significa che il pacchetto si è perso per strada: NetworkPolicy, CNI o un Service senza endpoint. Leggere bene quel messaggio ti risparmia metà del lavoro.
Teoría · Las cinco capas
Theory · The five layers
Teoria · I cinque strati

La ruta completa de una request

The full path of a request

Il percorso completo di una richiesta

#CapaSe rompe por
#LayerBreaks because of
#StratoSi rompe per
1DNSCoreDNS caído, FQDN malCoreDNS down, wrong FQDNCoreDNS caduto, FQDN errato
2ServiceSelector, puertosSelector, portsSelector, porte
3EndpointsPods no ReadyPods not ReadyPod non Ready
4PolicyNetworkPolicy que niegaA NetworkPolicy denying itUna NetworkPolicy che nega
5Pod / CNIApp caída, red del nodoApp down, node networkingApp caduta, rete del nodo

Por qué el orden importa

Why the order matters

Perché l'ordine conta

Cada capa depende de la anterior. Si el DNS no resuelve, no tenés forma de saber si el Service anda: el error tapa todo lo demás. Por eso se prueba de arriba hacia abajo, y por eso el primer comando siempre es un nslookup.

Each layer depends on the one before. If DNS does not resolve, you have no way of knowing whether the Service works: the error masks everything else. That is why you test top-down, and why the first command is always an nslookup.

Ogni strato dipende dal precedente. Se il DNS non risolve, non hai modo di sapere se il Service funziona: l'errore copre tutto il resto. Per questo si prova dall'alto verso il basso, e per questo il primo comando è sempre un nslookup.

El corte que más rinde

The highest-yield cut

Il taglio che rende di più

Pegarle a la IP del pod directo (corte 3) parte el problema exactamente al medio: descarta de un saque DNS, Service, endpoints y kube-proxy, o los confirma a todos. Si tenés tiempo para una sola prueba, es esa.

Hitting the pod IP directly (cut 3) splits the problem exactly in half: in one go it rules out DNS, Service, endpoints and kube-proxy, or confirms them all. If you have time for a single test, that is the one.

Colpire direttamente l'IP del pod (taglio 3) divide il problema esattamente a metà: in un colpo esclude DNS, Service, endpoint e kube-proxy, oppure li conferma tutti. Se hai tempo per una sola prova, è quella.

Los tres síntomas y su significado

The three symptoms and what they mean

I tre sintomi e cosa significano

  • No resuelve → capa 1, y solo capa 1.
  • Resuelve pero timeout → capas 3, 4 o 5: el paquete no llega.
  • Conecta y da error HTTP → llegó: el problema es la app o el targetPort.
  • Does not resolve → layer 1, and only layer 1.
  • Resolves but times out → layers 3, 4 or 5: the packet does not arrive.
  • Connects and returns an HTTP error → it arrived: the problem is the app or the targetPort.
  • Non risolve → strato 1, e solo strato 1.
  • Risolve ma va in timeout → strati 3, 4 o 5: il pacchetto non arriva.
  • Si connette e dà un errore HTTP → è arrivato: il problema è l'app o il targetPort.
★
Usá busybox:1.28 y no busybox a secas: las versiones posteriores tienen un nslookup roto para DNS de cluster y te van a hacer perseguir un fantasma. Es un clásico de los labs y aparece hasta en la doc oficial.
Use busybox:1.28, not plain busybox: later versions have a broken nslookup for cluster DNS and will send you chasing a ghost. It is a lab classic and even shows up in the official docs.
Usa busybox:1.28, non busybox secco: le versioni successive hanno un nslookup rotto per il DNS del cluster e ti faranno inseguire un fantasma. È un classico dei lab e compare persino nella documentazione ufficiale.
Visor · el mismo síntoma, cinco causas: dónde corta cada una· the same symptom, five causes: where each one cuts· lo stesso sintomo, cinque cause: dove taglia ciascuna

Desde afuera todos se ven igual: curl web:80 no vuelve. Los cortes los separan.

From outside they all look the same: curl web:80 never returns. The cuts tell them apart.

Da fuori sembrano tutti uguali: curl web:80 non torna. I tagli li distinguono.

11.2
Capa 1 · 20 min
Layer 1 · 20 min
Strato 1 · 20 min

DNS roto

Broken DNS

DNS rotto

Si CoreDNS cae, todo el cluster parece roto a la vez.
If CoreDNS goes down, the whole cluster looks broken at once.
Se CoreDNS cade, l'intero cluster sembra rotto tutto insieme.
Práctica · De adentro hacia afuera
Practice · From the inside out
Pratica · Da dentro verso fuori

Paso 1 — probar desde un pod

Step 1 — test from a pod

Passo 1 — provare da un pod

k run t --rm -it --image=busybox:1.28 -- sh

nslookup kubernetes.default        # el que SIEMPRE existe# the one that ALWAYS exists# quello che esiste SEMPRE
nslookup web
nslookup web.default.svc.cluster.local
nslookup web.otro-ns.svc.cluster.local

Paso 2 — la config del cliente

Step 2 — the client's config

Passo 2 — la config del client

k exec app -- cat /etc/resolv.conf
# nameserver 10.96.0.10          <- la ClusterIP del Service kube-dns# nameserver 10.96.0.10          <- the ClusterIP of the kube-dns Service# nameserver 10.96.0.10          <- la ClusterIP del Service kube-dns
# search default.svc.cluster.local svc.cluster.local cluster.local
# options ndots:5

# ¿Coincide con el Service real?# Does it match the real Service?# Coincide col Service reale?
k get svc -n kube-system kube-dns

Paso 3 — CoreDNS

Step 3 — CoreDNS

Passo 3 — CoreDNS

k get pods -n kube-system -l k8s-app=kube-dns
# 2 pods, deberían estar Running 1/1# 2 pods, they should be Running 1/1# 2 pod, dovrebbero essere Running 1/1

k logs -n kube-system -l k8s-app=kube-dns --tail=50
k describe pod -n kube-system -l k8s-app=kube-dns

# ¿El Service de DNS tiene endpoints? (¡el mismo chequeo de siempre!)# Does the DNS Service have endpoints? (the same check as always!)# Il Service del DNS ha endpoint? (lo stesso controllo di sempre!)
k get endpointslices -n kube-system -l kubernetes.io/service-name=kube-dns

Paso 4 — el Corefile

Step 4 — the Corefile

Passo 4 — il Corefile

k get cm -n kube-system coredns -o yaml
# errors / health / kubernetes cluster.local / forward . /etc/resolv.conf

k edit cm -n kube-system coredns
# Editar el CM NO reinicia CoreDNS: forzalo# Editing the CM does NOT restart CoreDNS: force it# Modificare la CM NON riavvia CoreDNS: forzalo
k rollout restart deploy -n kube-system coredns
k rollout status deploy -n kube-system coredns

Probar el servidor sin intermediarios

Testing the server with no middlemen

Provare il server senza intermediari

# Consultar directo a la IP de un pod de CoreDNS# Query a CoreDNS pod's IP directly# Interrogare direttamente l'IP di un pod di CoreDNS
k get pods -n kube-system -l k8s-app=kube-dns -o wide
nslookup web 10.244.0.5

# Si el pod responde pero el Service no → problema del Service kube-dns# If the pod answers but the Service does not → the kube-dns Service is the problem# Se il pod risponde ma il Service no → il problema è il Service kube-dns
⚠
Un deny-all de egress (M7) rompe el DNS de todos los pods del namespace y el síntoma es «nada resuelve», idéntico a CoreDNS caído. Si CoreDNS está Running y sano pero un namespace puntual no resuelve, mirá k get netpol -n <ns> antes que cualquier otra cosa.
An egress deny-all (M7) breaks DNS for every pod in the namespace and the symptom is "nothing resolves", identical to CoreDNS being down. If CoreDNS is Running and healthy but one particular namespace does not resolve, check k get netpol -n <ns> before anything else.
Un deny-all di egress (M7) rompe il DNS di tutti i pod del namespace e il sintomo è «non risolve nulla», identico a CoreDNS caduto. Se CoreDNS è Running e sano ma un namespace specifico non risolve, guarda k get netpol -n <ns> prima di ogni altra cosa.
Teoría · Cómo resuelve un pod
Theory · How a pod resolves
Teoria · Come risolve un pod

La cadena del DNS

The DNS chain

La catena del DNS

El kubelet escribe /etc/resolv.conf en cada pod apuntando a la ClusterIP del Service kube-dns (típicamente 10.96.0.10). Ese Service enruta a los pods de CoreDNS, que corren como Deployment en kube-system y responden consultando la API de Kubernetes.

The kubelet writes /etc/resolv.conf in every pod pointing at the kube-dns Service's ClusterIP (typically 10.96.0.10). That Service routes to the CoreDNS pods, which run as a Deployment in kube-system and answer by querying the Kubernetes API.

Il kubelet scrive /etc/resolv.conf in ogni pod puntando alla ClusterIP del Service kube-dns (tipicamente 10.96.0.10). Quel Service instrada ai pod di CoreDNS, che girano come Deployment in kube-system e rispondono interrogando l'API di Kubernetes.

El nombre completo

The full name

Il nome completo

<servicio>.<namespace>.svc.cluster.local. Desde el mismo namespace alcanza con el nombre corto; desde otro hace falta al menos servicio.namespace. Los pods headless (M6) agregan un nivel: <pod>.<servicio>.<namespace>.svc.cluster.local.

<service>.<namespace>.svc.cluster.local. From the same namespace the short name is enough; from another you need at least service.namespace. Headless pods (M6) add a level: <pod>.<service>.<namespace>.svc.cluster.local.

<servizio>.<namespace>.svc.cluster.local. Dallo stesso namespace basta il nome breve; da un altro serve almeno servizio.namespace. I pod headless (M6) aggiungono un livello: <pod>.<servizio>.<namespace>.svc.cluster.local.

ndots:5, el detalle raro

ndots:5, the odd detail

ndots:5, il dettaglio strano

Significa: «si el nombre tiene menos de 5 puntos, probá primero con los sufijos de search». Por eso web se intenta como web.default.svc.cluster.local antes que como dominio externo — y por eso resolver nombres de internet desde un pod genera varias consultas fallidas antes de acertar. Es lento pero correcto; no lo «arregles».

It means: "if the name has fewer than 5 dots, try the search suffixes first". That is why web is tried as web.default.svc.cluster.local before being treated as an external domain — and why resolving internet names from a pod produces several failed queries before hitting. It is slow but correct; do not "fix" it.

Significa: «se il nome ha meno di 5 punti, prova prima i suffissi di search». Per questo web viene tentato come web.default.svc.cluster.local prima che come dominio esterno — e per questo risolvere nomi di internet da un pod genera diverse query fallite prima di azzeccarci. È lento ma corretto; non «aggiustarlo».

busybox miente con los nombres con punto

busybox lies about dotted names

busybox mente sui nomi con punto

musl (la libc de busybox y alpine) no implementa ndots. Si el nombre trae aunque sea un punto, lo consulta como absoluto antes de probar los search. Con glibc (nginx, debian) pasa lo contrario: ndots:5 manda y los sufijos del cluster van primero.

Casi siempre da igual… salvo cuando el segundo tramo del nombre es un TLD real. Un namespace llamado red o net hace que web.red o web.net se resuelvan en internet y te devuelvan una IP pública que existe y hasta contesta. El diagnóstico se va al demonio persiguiendo un pod que nunca fue tuyo. Verificalo siempre con el FQDN completo (web.red.svc.cluster.local) o desde una imagen glibc.

musl (busybox's and alpine's libc) does not implement ndots. If the name carries even one dot, it queries it as absolute before trying the search suffixes. With glibc (nginx, debian) it is the opposite: ndots:5 rules and the cluster suffixes go first.

It almost never matters… except when the name's second label is a real TLD. A namespace called red or net makes web.red or web.net resolve on the internet and hand you a public IP that exists and even answers. The diagnosis then goes to pieces chasing a pod that was never yours. Always confirm with the full FQDN (web.red.svc.cluster.local) or from a glibc image.

musl (la libc di busybox e alpine) non implementa ndots. Se il nome contiene anche un solo punto, lo interroga come assoluto prima di provare i suffissi search. Con glibc (nginx, debian) è il contrario: comanda ndots:5 e i suffissi del cluster vengono per primi.

Quasi sempre è indifferente… tranne quando la seconda etichetta del nome è un TLD reale. Un namespace chiamato red o net fa sì che web.red o web.net si risolvano su internet e ti restituiscano un IP pubblico che esiste e magari risponde pure. La diagnosi va a rotoli inseguendo un pod che non è mai stato tuo. Conferma sempre col FQDN completo (web.red.svc.cluster.local) o da un'immagine glibc.

Las causas, en orden

The causes, in order

Le cause, in ordine

SíntomaCausa probable
SymptomLikely cause
SintomoCausa probabile
Nada resuelve, en todo el clusterNothing resolves, cluster-wideNon risolve nulla, in tutto il clusterCoreDNS caído o sin endpointsCoreDNS down or with no endpointsCoreDNS caduto o senza endpoint
Nada resuelve, un solo nsNothing resolves, one ns onlyNon risolve nulla, un solo nsNetworkPolicy de egressAn egress NetworkPolicyUna NetworkPolicy di egress
Resuelve interno, no externoInternal resolves, external does notRisolve interno, non esternoforward del CorefileThe Corefile's forwardIl forward del Corefile
Un servicio puntual no resuelveOne particular service does not resolveUn servizio specifico non risolveEl Service no existe / typo / nsThe Service does not exist / typo / nsIl Service non esiste / refuso / ns
Resuelve a una IP viejaResolves to a stale IPRisolve a un IP vecchioCache: TTL de 30s por defectoCache: 30s TTL by defaultCache: TTL di 30s di default

CoreDNS Pending es CNI

CoreDNS Pending means CNI

CoreDNS Pending significa CNI

Si los pods de CoreDNS están en Pending o ContainerCreating recién instalado el cluster, no es un problema de DNS: es que falta el CNI (M7/M10). Arreglá eso y el DNS aparece solo.

If the CoreDNS pods are Pending or ContainerCreating on a freshly installed cluster, it is not a DNS problem: the CNI is missing (M7/M10). Fix that and DNS shows up on its own.

Se i pod di CoreDNS sono in Pending o ContainerCreating su un cluster appena installato, non è un problema di DNS: manca il CNI (M7/M10). Sistemalo e il DNS compare da solo.

★
nslookup kubernetes.default es tu canario: ese Service existe en todos los clusters, siempre. Si eso no resuelve, el problema es el DNS mismo y no el servicio que estabas buscando. Un comando, cero ambigüedad.
nslookup kubernetes.default is your canary: that Service exists in every cluster, always. If that does not resolve, the problem is DNS itself and not the service you were after. One command, zero ambiguity.
nslookup kubernetes.default è il tuo canarino: quel Service esiste in ogni cluster, sempre. Se quello non risolve, il problema è il DNS stesso e non il servizio che cercavi. Un comando, zero ambiguità.
11.3
Capa 2 y 3 · 15 min
Layers 2 and 3 · 15 min
Strati 2 e 3 · 15 min

Service sin endpoints

Service with no endpoints

Service senza endpoint

El fallo silencioso más común de todo Kubernetes.
The most common silent failure in all of Kubernetes.
Il guasto silenzioso più comune di tutto Kubernetes.
Práctica · Comparar labels
Practice · Comparing labels
Pratica · Confrontare le label

La verificación de siempre

The usual check

La verifica di sempre

k get endpointslices -l kubernetes.io/service-name=web
k describe svc web | grep -i endpoints
# Endpoints:  <none>    <- acá está el problema# Endpoints:  <none>    <- there is the problem# Endpoints:  <none>    <- ecco il problema

El diagnóstico: comparar los dos lados

The diagnosis: compare both sides

La diagnosi: confrontare i due lati

# Lado A: ¿qué busca el Service?# Side A: what is the Service looking for?# Lato A: cosa cerca il Service?
k get svc web -o wide          # columna SELECTOR# SELECTOR column# colonna SELECTOR
k get svc web -o jsonpath='{.spec.selector}'
# {"app":"web"}

# Lado B: ¿qué labels tienen los pods?# Side B: what labels do the pods carry?# Lato B: che label hanno i pod?
k get pods --show-labels
# web-abc  Running  app=webapp   <- NO matchea: "webapp" != "web"# web-abc  Running  app=webapp   <- NO match: "webapp" != "web"# web-abc  Running  app=webapp   <- NON corrisponde: "webapp" != "web"

# La prueba definitiva: usar el selector del Service como filtro# The decisive test: use the Service's selector as a filter# La prova decisiva: usare il selector del Service come filtro
k get pods -l app=web
# "No resources found" → confirmado, el selector no matchea nada# "No resources found" → confirmed, the selector matches nothing# "No resources found" → confermato, il selector non corrisponde a nulla

Las cuatro causas

The four causes

Le quattro cause

# 1. Selector que no matchea (typo, o label del Deploy en vez del pod)# 1. A selector that matches nothing (typo, or the Deploy's label instead of the pod's)# 1. Un selector che non corrisponde (refuso, o la label del Deploy invece del pod)
k get pods -l <selector-del-service>

# 2. Pods no Ready: solo los Ready entran al endpoint (M9)# 2. Pods not Ready: only Ready ones enter the endpoint (M9)# 2. Pod non Ready: solo i Ready entrano nell'endpoint (M9)
k get pods -l app=web
# web-abc  Running  0/1   <- READY 0/1 = fuera del Service# web-abc  Running  0/1   <- READY 0/1 = out of the Service# web-abc  Running  0/1   <- READY 0/1 = fuori dal Service

# 3. Namespace equivocado: el Service solo ve pods de SU namespace# 3. Wrong namespace: a Service only sees pods in ITS namespace# 3. Namespace sbagliato: un Service vede solo i pod del SUO namespace
k get svc,pods -n prod

# 4. targetPort != puerto real del container# 4. targetPort != the container's real port# 4. targetPort != porta reale del container
k get svc web -o jsonpath='{.spec.ports[*].targetPort}'
k get pod web-abc -o jsonpath='{.spec.containers[*].ports[*].containerPort}'

Arreglar

Fixing

Sistemare

# Corregir el selector del Service# Correct the Service's selector# Correggere il selector del Service
k patch svc web -p '{"spec":{"selector":{"app":"webapp"}}}'

# O poner el label correcto en los pods# Or put the right label on the pods# O mettere la label giusta sui pod
k label pod web-abc app=web --overwrite

# Recrear el Service desde el deploy (toma el selector correcto)# Recreate the Service from the deploy (it picks the right selector)# Ricreare il Service dal deploy (prende il selector giusto)
k delete svc web
k expose deploy web --port=80 --target-port=8080

# Verificar que ahora SÍ hay endpoints# Verify there ARE endpoints now# Verificare che ORA ci siano endpoint
k describe svc web | grep -i endpoints
★
El comando que resuelve este ejercicio en diez segundos es k get pods -l <selector-del-service>. Si devuelve pods, el selector está bien y el problema es readiness o puertos. Si no devuelve nada, es el selector. Una sola pregunta, dos ramas.
The command that cracks this in ten seconds is k get pods -l <service-selector>. If it returns pods, the selector is fine and the problem is readiness or ports. If it returns nothing, it is the selector. One question, two branches.
Il comando che risolve questo esercizio in dieci secondi è k get pods -l <selector-del-service>. Se restituisce pod, il selector è a posto e il problema è la readiness o le porte. Se non restituisce nulla, è il selector. Una sola domanda, due rami.
Teoría · Por qué falla en silencio
Theory · Why it fails silently
Teoria · Perché fallisce in silenzio

Nadie te avisa

Nobody warns you

Nessuno ti avvisa

Un Service con un selector que no matchea nada es un objeto perfectamente válido: la API lo acepta, tiene ClusterIP, resuelve por DNS. Simplemente su lista de endpoints está vacía y las conexiones mueren por timeout. No hay evento, no hay warning, no hay log. Por eso el describe svc es un reflejo obligatorio.

A Service whose selector matches nothing is a perfectly valid object: the API accepts it, it has a ClusterIP, it resolves via DNS. Its endpoint list is simply empty and connections die on timeout. No event, no warning, no log. That is why describe svc is a mandatory reflex.

Un Service con un selector che non corrisponde a nulla è un oggetto perfettamente valido: l'API lo accetta, ha un ClusterIP, risolve via DNS. Semplicemente la sua lista di endpoint è vuota e le connessioni muoiono in timeout. Nessun evento, nessun warning, nessun log. Per questo il describe svc è un riflesso obbligatorio.

Los dos requisitos para entrar al endpoint

The two requirements to enter the endpoint

I due requisiti per entrare nell'endpoint

  • El pod matchea el selector del Service.
  • El pod está Ready (pasó su readinessProbe).
  • The pod matches the Service's selector.
  • The pod is Ready (it passed its readinessProbe).
  • Il pod corrisponde al selector del Service.
  • Il pod è Ready (ha superato la sua readinessProbe).

Los dos, siempre. Un pod Running pero 0/1 no recibe tráfico — y ahí el problema no es de red sino de probe (M9).

Both, always. A pod that is Running but 0/1 receives no traffic — and there the problem is not networking but the probe (M9).

Entrambi, sempre. Un pod Running ma 0/1 non riceve traffico — e lì il problema non è di rete ma della probe (M9).

El error conceptual de fondo

The underlying conceptual error

L'errore concettuale di fondo

El selector del Service apunta a labels de pods, no del Deployment. Se ven parecidos porque el Deployment suele propagar sus labels al template, pero son cosas distintas: si editás el template y no el Service, se desincronizan sin que nada se queje.

The Service's selector points at pod labels, not the Deployment's. They look alike because a Deployment usually propagates its labels to the template, but they are different things: edit the template and not the Service and they drift apart without anything complaining.

Il selector del Service punta alle label dei pod, non del Deployment. Si somigliano perché il Deployment di solito propaga le sue label al template, ma sono cose diverse: modifichi il template e non il Service e si disallineano senza che nulla protesti.

Conecta pero da error

It connects but errors out

Si connette ma dà errore

Si hay endpoints y el curl conecta pero responde mal, ya no es un problema de descubrimiento: mirá targetPort (M6) — el Service reenvía a un puerto donde el container no escucha — o directamente la app.

If there are endpoints and curl connects but answers badly, it is no longer a discovery problem: look at targetPort (M6) — the Service forwards to a port where the container is not listening — or at the app itself.

Se ci sono endpoint e il curl si connette ma risponde male, non è più un problema di discovery: guarda il targetPort (M6) — il Service inoltra a una porta dove il container non ascolta — o direttamente l'app.

★
Mantra del M6, que acá se cobra: Service sin endpoints = selector que no matchea, o pods no Ready. Es el 90% de los «el service no responde» del examen, y se descarta con dos comandos.
M6's mantra, cashed in here: a Service with no endpoints = a selector that does not match, or pods that are not Ready. It is 90% of the "the service does not answer" cases in the exam, and two commands rule it out.
Il mantra del M6, che qui si riscuote: Service senza endpoint = selector che non corrisponde, o pod non Ready. È il 90% dei «il service non risponde» dell'esame, e si esclude con due comandi.
11.4
Capa 4 · 15 min
Layer 4 · 15 min
Strato 4 · 15 min

NetworkPolicy bloqueando tráfico

A NetworkPolicy blocking traffic

NetworkPolicy che blocca traffico

Timeout perfecto, sin un solo log. El bloqueo más difícil de ver.
A perfect timeout, with not one log line. The hardest block to see.
Timeout perfetto, senza una sola riga di log. Il blocco più difficile da vedere.
Práctica · Encontrar la culpable
Practice · Finding the culprit
Pratica · Trovare la colpevole

Paso 1 — ¿hay policies?

Step 1 — are there any policies?

Passo 1 — ci sono policy?

k get netpol -A
k get netpol -n prod
k describe netpol -n prod

Paso 2 — ¿alguna selecciona a mis pods?

Step 2 — does any of them select my pods?

Passo 2 — qualcuna seleziona i miei pod?

# El podSelector de la policy, aplicado como filtro# The policy's podSelector, used as a filter# Il podSelector della policy, usato come filtro
k get netpol deny-all -n prod -o jsonpath='{.spec.podSelector}'
k get pods -n prod -l app=db --show-labels

# ¿Y qué policyTypes declara? (Ingress, Egress o ambos)# And which policyTypes does it declare? (Ingress, Egress or both)# E quali policyTypes dichiara? (Ingress, Egress o entrambi)
k get netpol deny-all -n prod -o jsonpath='{.spec.policyTypes}'

Paso 3 — el test A/B

Step 3 — the A/B test

Passo 3 — il test A/B

# Desde un pod que SÍ debería poder# From a pod that SHOULD be allowed# Da un pod che DOVREBBE poter passare
k exec -n prod web-abc -- curl -s --max-time 3 db:5432

# Desde un pod SIN los labels permitidos (control negativo)# From a pod WITHOUT the allowed labels (negative control)# Da un pod SENZA le label permesse (controllo negativo)
k run t --rm -it -n prod --image=busybox:1.28 -- \
  wget -qO- --timeout=2 db:5432

# Los dos fallan → la policy está de más o mal escrita# Both fail → the policy is superfluous or badly written# Falliscono entrambi → la policy è di troppo o scritta male
# Solo falla el segundo → la policy funciona como se diseñó# Only the second fails → the policy works as designed# Fallisce solo il secondo → la policy funziona come progettata

Paso 4 — confirmar sacándola (en lab, no en prod)

Step 4 — confirm by removing it (in a lab, not in prod)

Passo 4 — confermare rimuovendola (in lab, non in prod)

k get netpol deny-all -n prod -o yaml > /tmp/np.yaml
k delete netpol deny-all -n prod
# ¿anda ahora? → era esa. Volvela a poner y corregila.# does it work now? → that was it. Put it back and fix it.# funziona ora? → era quella. Rimettila e correggila.
k apply -f /tmp/np.yaml

Los tres errores de escritura

The three writing mistakes

I tre errori di scrittura

# 1. El guión: AND vs OR (M7)# 1. The dash: AND vs OR (M7)# 1. Il trattino: AND vs OR (M7)
  from:
  - namespaceSelector: {...}
    podSelector: {...}      # AND: pod X en ns Y# AND: pod X in ns Y# AND: pod X nel ns Y
  #- podSelector: {...}    # con guión sería OR#- podSelector: {...}    # with a dash it would be OR#- podSelector: {...}    # col trattino sarebbe OR

# 2. Egress sin DNS: rompe TODO# 2. Egress with no DNS: breaks EVERYTHING# 2. Egress senza DNS: rompe TUTTO
  egress:
  - ports: [{protocol: UDP, port: 53}, {protocol: TCP, port: 53}]

# 3. El puerto es el del CONTAINER, no el del Service# 3. The port is the CONTAINER's, not the Service's# 3. La porta è quella del CONTAINER, non del Service
    ports:
    - {protocol: TCP, port: 8080}   # targetPort, no port# targetPort, not port# targetPort, non port
⚠
Las NetworkPolicies no generan ningún log ni evento: el paquete se descarta y el cliente ve un timeout, indistinguible de un pod caído. Si el pod destino está Running, Ready, en los endpoints, y aun así no responde, mirá las policies antes de dudar de la app.
NetworkPolicies produce no log and no event: the packet is dropped and the client sees a timeout, indistinguishable from a dead pod. If the destination pod is Running, Ready, in the endpoints, and still does not answer, check the policies before doubting the app.
Le NetworkPolicy non generano alcun log né evento: il pacchetto viene scartato e il client vede un timeout, indistinguibile da un pod morto. Se il pod di destinazione è Running, Ready, negli endpoint, e comunque non risponde, guarda le policy prima di dubitare dell'app.
Teoría · Cómo razonar el bloqueo
Theory · How to reason about the block
Teoria · Come ragionare il blocco

Hay que mirar las DOS puntas

You must look at BOTH ends

Bisogna guardare ENTRAMBI i capi

Una conexión A→B tiene que pasar dos filtros: el egress de A y el ingress de B. Si cualquiera de los dos la niega, no hay conexión. Es el error de análisis más común: revisar solo las policies del namespace destino y no ver que el origen tiene un egress restrictivo.

A connection A→B must pass two filters: A's egress and B's ingress. If either denies it, there is no connection. It is the most common analysis mistake: checking only the destination namespace's policies and missing that the source has a restrictive egress.

Una connessione A→B deve passare due filtri: l'egress di A e l'ingress di B. Se uno dei due la nega, non c'è connessione. È l'errore di analisi più comune: controllare solo le policy del namespace di destinazione e non vedere che l'origine ha un egress restrittivo.

Recordatorio del M7

A reminder from M7

Promemoria dal M7

  • Sin policies que lo seleccionen, un pod acepta todo.
  • Con una sola policy que lo seleccione, queda aislado para esos policyTypes: solo pasa lo explícitamente permitido.
  • Las policies se suman: nunca se niegan entre sí, no hay reglas «deny».
  • With no policy selecting it, a pod accepts everything.
  • With a single policy selecting it, it becomes isolated for those policyTypes: only what is explicitly allowed gets through.
  • Policies add up: they never deny each other, there are no "deny" rules.
  • Senza policy che lo selezionino, un pod accetta tutto.
  • Con una sola policy che lo selezioni, resta isolato per quei policyTypes: passa solo ciò che è esplicitamente permesso.
  • Le policy si sommano: non si negano mai a vicenda, non esistono regole «deny».

Lo que las policies NO bloquean

What policies do NOT block

Cosa le policy NON bloccano

  • Las probes del kubelet: vienen del nodo, no de un pod.
  • El tráfico dentro del mismo pod (localhost entre containers).
  • Nada, si el CNI no las implementa (Flannel puro). Entonces tu policy es decorativa — y el síntoma es el opuesto: tráfico que debería estar bloqueado y pasa igual.
  • The kubelet's probes: they come from the node, not from a pod.
  • Traffic inside the same pod (localhost between containers).
  • Nothing at all, if the CNI does not implement them (plain Flannel). Then your policy is decorative — and the symptom is the opposite: traffic that should be blocked flows anyway.
  • Le probe del kubelet: vengono dal nodo, non da un pod.
  • Il traffico dentro lo stesso pod (localhost fra container).
  • Nulla, se il CNI non le implementa (Flannel puro). Allora la tua policy è decorativa — e il sintomo è opposto: traffico che dovrebbe essere bloccato e passa lo stesso.

Filtran por IP, no por Service

They filter by IP, not by Service

Filtrano per IP, non per Service

Las reglas se evalúan contra la IP del pod destino ya resuelta por kube-proxy, no contra la ClusterIP. Por eso el puerto que va en ports es el del container (targetPort) y no el del Service — una confusión que produce policies que parecen correctas y bloquean todo.

Rules are evaluated against the destination pod's IP already resolved by kube-proxy, not against the ClusterIP. That is why the port in ports is the container's (targetPort) and not the Service's — a confusion that produces policies that look right and block everything.

Le regole si valutano contro l'IP del pod di destinazione già risolto da kube-proxy, non contro il ClusterIP. Per questo la porta in ports è quella del container (targetPort) e non del Service — una confusione che produce policy che sembrano corrette e bloccano tutto.

★
Si un namespace «dejó de funcionar entero» de golpe — nada resuelve, nada conecta — el sospechoso número uno es una NetworkPolicy de egress sin excepción para el puerto 53. Es el bloqueo autoinfligido clásico y explica los dos síntomas de una sola vez.
If a whole namespace "stopped working" at once — nothing resolves, nothing connects — suspect number one is an egress NetworkPolicy with no exception for port 53. It is the classic self-inflicted block and it explains both symptoms in one go.
Se un intero namespace «ha smesso di funzionare» di colpo — non risolve nulla, non si connette nulla — il sospettato numero uno è una NetworkPolicy di egress senza eccezione per la porta 53. È il blocco autoinflitto classico e spiega entrambi i sintomi in un colpo solo.
11.5
Capa 5 · 10 min
Layer 5 · 10 min
Strato 5 · 10 min

kube-proxy y conectividad pod-to-pod

kube-proxy and pod-to-pod connectivity

kube-proxy e connettività pod-to-pod

Lo último que se sospecha, y con razón.
The last thing to suspect, and rightly so.
L'ultima cosa da sospettare, e a ragione.
Práctica · La capa de abajo
Practice · The layer below
Pratica · Lo strato sottostante

kube-proxy

k get ds -n kube-system kube-proxy
# DESIRED=CURRENT=READY: uno por nodo# DESIRED=CURRENT=READY: one per node# DESIRED=CURRENT=READY: uno per nodo

k get pods -n kube-system -l k8s-app=kube-proxy -o wide
k logs -n kube-system -l k8s-app=kube-proxy --tail=50

# Su configuración (modo iptables/nftables/ipvs)# Its configuration (iptables/nftables/ipvs mode)# La sua configurazione (modalità iptables/nftables/ipvs)
k get cm -n kube-system kube-proxy -o yaml | grep -i mode

Pod-to-pod directo

Pod-to-pod directly

Pod-to-pod diretto

# Dos pods, idealmente en NODOS DISTINTOS# Two pods, ideally on DIFFERENT NODES# Due pod, idealmente su NODI DIVERSI
k get pods -o wide

# Mismo nodo: si esto falla, el CNI local está roto# Same node: if this fails, the local CNI is broken# Stesso nodo: se questo fallisce, il CNI locale è rotto
k exec p1 -- ping -c 2 <IP-P2-MISMO-NODO>

# Nodos distintos: si SOLO esto falla, es el overlay/ruteo entre nodos# Different nodes: if ONLY this fails, it is the overlay/routing between nodes# Nodi diversi: se fallisce SOLO questo, è l'overlay/routing fra nodi
k exec p1 -- ping -c 2 <IP-P3-OTRO-NODO>

Desde el nodo

From the node

Dal nodo

ssh worker1
sudo iptables -t nat -L KUBE-SERVICES -n | head -20
sudo iptables -t nat -L -n | grep <CLUSTER-IP>

ip route
ip addr | grep -E 'cali|flannel|cni'

# El CNI (M7/M10)# The CNI (M7/M10)# Il CNI (M7/M10)
k get pods -n kube-system -o wide | grep -Ei 'calico|cilium|flannel'

Puentes de debug (no arreglan, pero aislan)

Debug bridges (they do not fix, but they isolate)

Ponti di debug (non risolvono, ma isolano)

k port-forward svc/web 8080:80    # saltea el ingreso externo# skips the external ingress# salta l'ingresso esterno
k port-forward pod/web-abc 8080:80 # saltea Service y kube-proxy# skips Service and kube-proxy# salta Service e kube-proxy
# Si por port-forward anda y por el Service no → Service/kube-proxy# If port-forward works and the Service does not → Service/kube-proxy# Se il port-forward funziona e il Service no → Service/kube-proxy
★
No pierdas tiempo con ping a una ClusterIP: nunca responde, ni con todo sano. No existe ninguna interfaz con esa IP — es una regla de NAT en el kernel (M6). Para probar un Service usá curl o wget contra su puerto.
Do not waste time pinging a ClusterIP: it never answers, not even when everything is healthy. No interface holds that IP — it is a NAT rule in the kernel (M6). To test a Service use curl or wget against its port.
Non perdere tempo a fare ping a un ClusterIP: non risponde mai, nemmeno con tutto sano. Nessuna interfaccia ha quell'IP — è una regola di NAT nel kernel (M6). Per provare un Service usa curl o wget sulla sua porta.
Teoría · Quién hace qué
Theory · Who does what
Teoria · Chi fa cosa

División de trabajo

Division of labour

Divisione del lavoro

ComponenteResponsable deSi falla
ComponentResponsible forIf it fails
ComponenteResponsabile diSe fallisce
CNIIPs y red pod-a-podIPs and pod-to-pod networkingIP e rete pod-a-podNada conecta, pods PendingNothing connects, pods PendingNon si connette nulla, pod Pending
kube-proxyClusterIP → podServices no responden, pods síServices do not answer, pods doI Service non rispondono, i pod sì
CoreDNSNombres → IPsNames → IPsNomi → IPNo resuelve, IPs sí andanNo resolution, IPs still workNon risolve, gli IP funzionano

Cada uno falla con una firma distinta, y esa firma es el diagnóstico. Si las IPs de pod andan pero las ClusterIP no, es kube-proxy. Si ni las IPs de pod andan, es el CNI.

Each fails with a distinct signature, and that signature is the diagnosis. If pod IPs work but ClusterIPs do not, it is kube-proxy. If not even pod IPs work, it is the CNI.

Ciascuno fallisce con una firma distinta, e quella firma è la diagnosi. Se gli IP dei pod funzionano ma i ClusterIP no, è kube-proxy. Se non funzionano nemmeno gli IP dei pod, è il CNI.

Por qué kube-proxy rara vez es el culpable

Why kube-proxy is rarely the culprit

Perché kube-proxy è raramente il colpevole

No procesa tráfico: programa reglas en el kernel y se aparta (M6). Si muere, lo ya programado sigue funcionando — lo que se rompe son los Services nuevos o los cambios de endpoints. Síntoma típico: los Services viejos andan, los recién creados no.

It does not process traffic: it programs rules into the kernel and steps aside (M6). If it dies, what is already programmed keeps working — what breaks are new Services or endpoint changes. Typical symptom: old Services work, freshly created ones do not.

Non elabora traffico: programma regole nel kernel e si fa da parte (M6). Se muore, ciò che è già programmato continua a funzionare — a rompersi sono i Service nuovi o i cambi di endpoint. Sintomo tipico: i Service vecchi funzionano, quelli appena creati no.

Ping funciona, curl no

Ping works, curl does not

Il ping funziona, curl no

Significa que la red está sana (ICMP llega) y el problema está en la capa de transporte o en la app: puerto equivocado, proceso caído, o una policy que filtra por puerto. Es un corte útil: separa «red» de «servicio».

It means the network is healthy (ICMP arrives) and the problem is at the transport layer or in the app: wrong port, dead process, or a policy filtering by port. It is a useful cut: it separates "network" from "service".

Significa che la rete è sana (l'ICMP arriva) e il problema è al livello di trasporto o nell'app: porta sbagliata, processo morto, o una policy che filtra per porta. È un taglio utile: separa «rete» da «servizio».

Escuchar en localhost

Listening on localhost

Ascoltare su localhost

Una app que hace bind a 127.0.0.1 en vez de 0.0.0.0 funciona con kubectl exec ... curl localhost pero es inalcanzable desde cualquier otro pod. Todo Kubernetes parece roto y el problema es una línea de configuración de la app.

An app that binds to 127.0.0.1 instead of 0.0.0.0 works with kubectl exec ... curl localhost but is unreachable from any other pod. All of Kubernetes looks broken and the problem is one line of the app's configuration.

Un'app che fa bind su 127.0.0.1 invece che su 0.0.0.0 funziona con kubectl exec ... curl localhost ma è irraggiungibile da qualsiasi altro pod. Tutto Kubernetes sembra rotto e il problema è una riga di configurazione dell'app.

★
Orden de sospecha, de más a menos probable: selector/labels > readiness > DNS > NetworkPolicy > kube-proxy > CNI. Empezá siempre por arriba. Que un examen te rompa kube-proxy es raro; que te rompa un selector es la norma.
Order of suspicion, most to least likely: selector/labels > readiness > DNS > NetworkPolicy > kube-proxy > CNI. Always start at the top. An exam breaking kube-proxy on you is rare; breaking a selector is the norm.
Ordine di sospetto, dal più al meno probabile: selector/label > readiness > DNS > NetworkPolicy > kube-proxy > CNI. Parti sempre dall'alto. Che un esame ti rompa kube-proxy è raro; che ti rompa un selector è la norma.
★
Cierre del módulo · y de la Fase 1
Module wrap-up · and of Phase 1
Chiusura del modulo · e della Fase 1

Lo que te llevás del Módulo 11

What you take away from Module 11

Cosa ti porti dal Modulo 11

Resumen · Comandos clave
Summary · Key commands
Riepilogo · Comandi chiave

Para tu agenda

For your notebook

Per la tua agenda

# El pod de debug# The debug pod# Il pod di debug
k run t --rm -it --image=busybox:1.28 -- sh
k run net --rm -it --image=nicolaka/netshoot -- bash

# 1. DNS
nslookup kubernetes.default
nslookup web.default.svc.cluster.local
k exec app -- cat /etc/resolv.conf
k get pods -n kube-system -l k8s-app=kube-dns
k logs -n kube-system -l k8s-app=kube-dns --tail=50
k rollout restart deploy -n kube-system coredns

# 2. Service y endpoints# 2. Service and endpoints# 2. Service ed endpoint
k describe svc web | grep -i endpoints
k get endpointslices -l kubernetes.io/service-name=web
k get svc web -o jsonpath='{.spec.selector}'
k get pods -l app=web --show-labels

# 3. Policies# 3. Policies# 3. Policy
k get netpol -A
k describe netpol -n prod

# 4. Capa de abajo# 4. The layer below# 4. Lo strato sottostante
k get ds -n kube-system kube-proxy
k exec p1 -- ping -c 2 <IP-POD>
k port-forward pod/web-abc 8080:80

# El corte que más rinde: pegarle al POD directo# The highest-yield cut: hit the POD directly# Il taglio che rende di più: colpire il POD diretto
k run t --rm -it --image=busybox:1.28 -- \
  wget -qO- --timeout=2 <IP-POD>:8080
Teoría · Lo esencial
Theory · The essentials
Teoria · L'essenziale

Las 6 ideas que no se negocian

The 6 non-negotiable ideas

Le 6 idee non negoziabili

  • Se prueba en orden: DNS → endpoints → policy → pod. Cada capa tapa a las de abajo.
  • Refused ≠ timeout. Refused = llegó, nadie escucha. Timeout = no llegó: policy, CNI o Service vacío.
  • Service sin endpoints = selector que no matchea o pods no Ready. Es la causa número uno.
  • nslookup kubernetes.default es el canario del DNS; busybox:1.28 y no otra.
  • Las NetworkPolicies no loguean nada, y hay que mirar las dos puntas: egress del origen + ingress del destino.
  • Cada componente falla con firma propia: CNI (nada conecta), kube-proxy (pods sí, Services no), CoreDNS (IPs sí, nombres no).
  • Test in order: DNS → endpoints → policy → pod. Each layer masks the ones below.
  • Refused ≠ timeout. Refused = it arrived, nobody listening. Timeout = it never arrived: policy, CNI or an empty Service.
  • A Service with no endpoints = a selector that does not match, or pods not Ready. It is cause number one.
  • nslookup kubernetes.default is the DNS canary; busybox:1.28 and no other.
  • NetworkPolicies log nothing, and you must look at both ends: the source's egress + the destination's ingress.
  • Each component fails with its own signature: CNI (nothing connects), kube-proxy (pods yes, Services no), CoreDNS (IPs yes, names no).
  • Si prova in ordine: DNS → endpoint → policy → pod. Ogni strato copre quelli sotto.
  • Refused ≠ timeout. Refused = è arrivato, nessuno ascolta. Timeout = non è arrivato: policy, CNI o Service vuoto.
  • Service senza endpoint = selector che non corrisponde o pod non Ready. È la causa numero uno.
  • nslookup kubernetes.default è il canarino del DNS; busybox:1.28 e nessun'altra.
  • Le NetworkPolicy non loggano nulla, e bisogna guardare entrambi i capi: egress dell'origine + ingress della destinazione.
  • Ogni componente fallisce con la sua firma: CNI (non si connette nulla), kube-proxy (pod sì, Service no), CoreDNS (IP sì, nomi no).
★
El hilo de los tres módulos de Troubleshooting: no memorices causas, memorizá cortes. En el M9 el corte era «¿arrancó o no?»; en el M10, «¿responde kubectl?»; acá, «¿resuelve? ¿hay endpoints? ¿responde el pod directo?». Tres preguntas por módulo, y cada una parte el problema al medio.
The thread across the three Troubleshooting modules: do not memorise causes, memorise cuts. In M9 the cut was "did it start or not?"; in M10, "does kubectl answer?"; here, "does it resolve? are there endpoints? does the pod answer directly?". Three questions per module, and each one splits the problem in half.
Il filo dei tre moduli di Troubleshooting: non memorizzare le cause, memorizza i tagli. Nel M9 il taglio era «è partito o no?»; nel M10, «risponde kubectl?»; qui, «risolve? ci sono endpoint? il pod risponde diretto?». Tre domande per modulo, e ciascuna divide il problema a metà.
Checkpoint Módulo 11: el método de bisección, DNS y CoreDNS, services sin endpoints, NetworkPolicies que bloquean en silencio y la capa kube-proxy/CNI. Dominio Troubleshooting (30%) completo — y con él, toda la Fase 1: los cinco dominios del examen cubiertos. Siguiente: Fase 2, labs cronometradas y simuladores.
Module 11 checkpoint: the bisection method, DNS and CoreDNS, services with no endpoints, NetworkPolicies that block silently, and the kube-proxy/CNI layer. The Troubleshooting domain (30%) is complete — and with it all of Phase 1: the exam's five domains covered. Next: Phase 2, timed labs and simulators.
Checkpoint Modulo 11: il metodo della bisezione, DNS e CoreDNS, service senza endpoint, NetworkPolicy che bloccano in silenzio e lo strato kube-proxy/CNI. Dominio Troubleshooting (30%) completo — e con esso tutta la Fase 1: i cinque domini dell'esame coperti. Prossimo: Fase 2, lab cronometrati e simulatori.
★
Fase 2 · resolver en vivo
Phase 2 · solve it live
Fase 2 · risolvere dal vivo

Práctica — 8 ejercicios

Practice — 8 exercises

Pratica — 8 esercizi

Un solo síntoma, seis causas. Lo que se entrena son los cortes.
One symptom, six causes. What you train are the cuts.
Un solo sintomo, sei cause. Ciò che si allena sono i tagli.
0 / 8
🧠
Modelo mental. DNS → endpoints → policy → pod. Cada ejercicio se resuelve con la misma secuencia de cuatro cortes, y el objetivo no es adivinar la causa sino llegar a ella descartando mitades. Si te encontrás editando YAML antes del corte 2, parás y volvés.
Mental model. DNS → endpoints → policy → pod. Every exercise is solved by the same four-cut sequence, and the goal is not to guess the cause but to reach it by ruling out halves. If you catch yourself editing YAML before cut 2, stop and go back.
Modello mentale. DNS → endpoint → policy → pod. Ogni esercizio si risolve con la stessa sequenza di quattro tagli, e l'obiettivo non è indovinare la causa ma arrivarci escludendo metà alla volta. Se ti accorgi di modificare YAML prima del taglio 2, fermati e torna indietro.
◆
Manifests publicados. Cada ejercicio tiene su YAML servido por este mismo sitio: k apply -f <url>/manifests/m11e1.yaml. Los E son la solución de referencia; los T plantan el problema — aplicalos y diagnosticá sin leerlos. Todos usan el namespace m11 y k delete -f <misma-url> limpia. Las policies necesitan un CNI que las aplique (Calico sí). T4 es la excepción: toca CoreDNS en kube-system, así que la rotura va a mano.
Published manifests. Every exercise has its YAML served by this very site: k apply -f <url>/manifests/m11e1.yaml. The E ones are the reference solution; the T ones plant the problem — apply them and diagnose without reading them. All use namespace m11 and k delete -f <same-url> cleans up. The policies need a CNI that enforces them (Calico does). T4 is the exception: it touches CoreDNS in kube-system, so the break is done by hand.
Manifest pubblicati. Ogni esercizio ha il suo YAML servito da questo stesso sito: k apply -f <url>/manifests/m11e1.yaml. Gli E sono la soluzione di riferimento; i T piantano il problema — applicali e diagnostica senza leggerli. Tutti usano il namespace m11 e k delete -f <stessa-url> pulisce. Le policy richiedono un CNI che le applichi (Calico sì). Il T4 è l'eccezione: tocca CoreDNS in kube-system, quindi la rottura si fa a mano.
E1

Los cuatro cortes sobre una ruta sana

The four cuts on a healthy path

I quattro tagli su un percorso sano

~5 min

Antes de romper nada, aprendé cómo se ve lo sano. Corré los cuatro cortes sobre este stack y anotá la salida exacta de cada uno. Después vas a comparar contra eso.

Before breaking anything, learn what healthy looks like. Run the four cuts on this stack and note the exact output of each. You will compare against it later.

Prima di rompere qualsiasi cosa, impara com'è fatto il sano. Esegui i quattro tagli su questo stack e annota l'output esatto di ciascuno. Poi confronterai con quello.

manifest · soluciónmanifest · solutionmanifest · soluzione
Ver soluciónShow solutionMostra soluzione
k run t -n m11 --rm -it --image=busybox:1.28 -- sh

# corte 1# cut 1# taglio 1
nslookup web                 # Address: 10.x.x.x
# corte 2# cut 2# taglio 2
exit
k get endpointslices -n m11 -l kubernetes.io/service-name=web
# corte 3 — la IP del pod, salteando el Service# cut 3 — the pod IP, skipping the Service# taglio 3 — l'IP del pod, saltando il Service
k get pods -n m11 -o wide
k exec -n m11 cliente -- wget -qO- --timeout=2 <IP-POD>:5678
# corte 4 — desde adentro del propio pod# cut 4 — from inside the pod itself# taglio 4 — da dentro il pod stesso
k exec -n m11 deploy/web -- wget -qO- localhost:5678
Claves
Key points
Punti chiave
  • Conocer la salida sana es la mitad del diagnóstico. No podés reconocer un ENDPOINTS <none> como anomalía si nunca miraste uno poblado.
  • El corte 3 es el que más rinde: si la IP del pod responde, descartaste DNS, Service, endpoints y kube-proxy de una.
  • Guardá las cuatro salidas en un archivo. Los siete ejercicios que siguen son "encontrá cuál de estas cuatro cambió".
  • Knowing the healthy output is half the diagnosis. You cannot recognise an ENDPOINTS <none> as an anomaly if you have never looked at a populated one.
  • Cut 3 yields the most: if the pod IP answers, you have ruled out DNS, Service, endpoints and kube-proxy in one shot.
  • Save the four outputs to a file. The seven exercises that follow are all "find which of these four changed".
  • Conoscere l'output sano è metà della diagnosi. Non puoi riconoscere un ENDPOINTS <none> come anomalia se non ne hai mai visto uno popolato.
  • Il taglio 3 rende di più: se l'IP del pod risponde, hai escluso DNS, Service, endpoint e kube-proxy in un colpo.
  • Salva i quattro output in un file. I sette esercizi che seguono sono tutti "trova quale di questi quattro è cambiato".
E2

Leer el error: refused, timeout o no resuelve

Reading the error: refused, timeout or no resolution

Leggere l'errore: refused, timeout o non risolve

~6 min

Provocá los tres errores a propósito sobre el stack sano y anotá el mensaje exacto de cada uno: (a) un nombre que no existe; (b) un puerto donde nadie escucha; (c) una IP que no rutea. Después decí, para cada mensaje, a qué capa te manda.

Trigger the three errors deliberately on the healthy stack and note each exact message: (a) a name that does not exist; (b) a port where nobody listens; (c) an IP that does not route. Then say, for each message, which layer it sends you to.

Provoca deliberatamente i tre errori sullo stack sano e annota il messaggio esatto di ciascuno: (a) un nome che non esiste; (b) una porta dove nessuno ascolta; (c) un IP che non instrada. Poi di', per ogni messaggio, a quale strato ti manda.

manifest · soluciónmanifest · solutionmanifest · soluzione
Ver soluciónShow solutionMostra soluzione
k exec -n m11 cliente -- nc -zvw2 noexiste 5678
#   nc: bad address 'noexiste'            → DNS (capa 1)

k exec -n m11 cliente -- nc -zvw2 web 9999
#   nc: web (10.x.x.x:9999): Connection refused
#   → LLEGÓ. Nadie escucha ese puerto: app o targetPort#   → IT ARRIVED. Nobody listens there: app or targetPort#   → È ARRIVATO. Nessuno ascolta lì: app o targetPort

k exec -n m11 cliente -- nc -zvw2 10.244.99.99 5678
#   nc: ... Connection timed out
#   → NO LLEGÓ: policy, CNI o ruteo#   → IT DID NOT ARRIVE: policy, CNI or routing#   → NON È ARRIVATO: policy, CNI o routing
Claves
Key points
Punti chiave
  • El mensaje ya es el diagnóstico. Estos tres textos aparecen en casi todos los ejercicios de red del examen, y cada uno descarta dos capas de un saque.
  • Refused es buena noticia: significa que la red funciona de punta a punta y el kernel destino contestó. El problema está en el puerto o en la app, no en la red.
  • Timeout es la peor: el paquete desapareció y nadie te va a decir dónde. Ahí es donde entran las NetworkPolicies, que no loguean.
  • Usá siempre un timeout corto (-w2, --max-time 3): sin eso te quedás mirando la pantalla 30 segundos por prueba.
  • The message is already the diagnosis. These three texts show up in nearly every networking exercise in the exam, and each rules out two layers at once.
  • Refused is good news: it means the network works end to end and the destination kernel answered. The problem is the port or the app, not the network.
  • Timeout is the worst: the packet vanished and nobody will tell you where. That is where NetworkPolicies come in, and they do not log.
  • Always use a short timeout (-w2, --max-time 3): without it you stare at the screen for 30 seconds per test.
  • Il messaggio è già la diagnosi. Questi tre testi compaiono in quasi tutti gli esercizi di rete dell'esame, e ciascuno esclude due strati in un colpo.
  • Refused è una buona notizia: significa che la rete funziona da un capo all'altro e il kernel di destinazione ha risposto. Il problema è la porta o l'app, non la rete.
  • Timeout è il peggiore: il pacchetto è sparito e nessuno ti dirà dove. È lì che entrano le NetworkPolicy, che non loggano.
  • Usa sempre un timeout breve (-w2, --max-time 3): senza, resti a fissare lo schermo 30 secondi per prova.
E3

DNS: el canario y el nombre completo

DNS: the canary and the full name

DNS: il canarino e il nome completo

~6 min

Con el stack sano, recorré la cadena completa del DNS: el canario, el resolv.conf del pod, los pods de CoreDNS, y los endpoints del Service kube-dns. Después resolvé web desde otro namespace y explicá por qué el nombre corto falla.

On the healthy stack, walk the full DNS chain: the canary, the pod's resolv.conf, the CoreDNS pods, and the kube-dns Service's endpoints. Then resolve web from another namespace and explain why the short name fails.

Sullo stack sano, percorri l'intera catena del DNS: il canarino, il resolv.conf del pod, i pod di CoreDNS, e gli endpoint del Service kube-dns. Poi risolvi web da un altro namespace e spiega perché il nome breve fallisce.

manifest · soluciónmanifest · solutionmanifest · soluzione
Ver soluciónShow solutionMostra soluzione
k exec -n m11 cliente -- cat /etc/resolv.conf
#   nameserver 10.96.0.10   search m11.svc.cluster.local ...   ndots:5

k get svc -n kube-system kube-dns
k get pods -n kube-system -l k8s-app=kube-dns
k get endpointslices -n kube-system -l kubernetes.io/service-name=kube-dns

k run t -n m11 --rm -it --image=busybox:1.28 -- \
  nslookup kubernetes.default            # el canario# the canary# il canarino

# desde OTRO namespace, el nombre corto no alcanza# from ANOTHER namespace, the short name is not enough# da UN ALTRO namespace, il nome breve non basta
k exec -n afuera cliente -- nc -zvw2 web 80           # bad address
k exec -n afuera cliente -- nc -zvw2 web.m11 80       # open
Claves
Key points
Punti chiave
  • Los search del pod empiezan por SU propio namespace. Por eso web desde afuera se busca como web.afuera.svc... y no existe. Cross-namespace exige mínimo servicio.namespace.
  • El canario kubernetes.default separa "el DNS está roto" de "tu servicio no existe". Existe en todos los clusters, siempre.
  • El Service kube-dns también puede quedarse sin endpoints: es un Service como cualquier otro, y se diagnostica igual.
  • A pod's search list starts with ITS own namespace. That is why web from afuera is looked up as web.afuera.svc... and does not exist. Cross-namespace needs at least service.namespace.
  • The kubernetes.default canary separates "DNS is broken" from "your service does not exist". It exists in every cluster, always.
  • The kube-dns Service can also end up with no endpoints: it is a Service like any other, and is diagnosed the same way.
  • La lista search di un pod inizia dal SUO namespace. Per questo web da afuera viene cercato come web.afuera.svc... e non esiste. Il cross-namespace richiede almeno servizio.namespace.
  • Il canarino kubernetes.default separa «il DNS è rotto» da «il tuo servizio non esiste». Esiste in ogni cluster, sempre.
  • Anche il Service kube-dns può restare senza endpoint: è un Service come gli altri, e si diagnostica allo stesso modo.
E4

port-forward y el pod directo como bisección

port-forward and the direct pod as bisection

port-forward e il pod diretto come bisezione

~5 min

Sin romper nada, practicá los dos atajos que aíslan capas: pegarle a la IP del pod (saltea Service y kube-proxy) y port-forward contra el pod y contra el Service. Decí qué descarta cada uno. Extra: probá ping contra la ClusterIP y explicá el resultado.

Without breaking anything, practise the two shortcuts that isolate layers: hitting the pod IP (skips Service and kube-proxy) and port-forward against the pod and against the Service. Say what each rules out. Extra: try ping against the ClusterIP and explain the result.

Senza rompere nulla, esercita le due scorciatoie che isolano gli strati: colpire l'IP del pod (salta Service e kube-proxy) e port-forward sul pod e sul Service. Di' cosa esclude ciascuna. Extra: prova il ping sul ClusterIP e spiega il risultato.

manifest · soluciónmanifest · solutionmanifest · soluzione
Ver soluciónShow solutionMostra soluzione
IP=$(k get pod -n m11 -l app=web -o jsonpath='{.items[0].status.podIP}')

# IP del pod: saltea DNS, Service, endpoints y kube-proxy# pod IP: skips DNS, Service, endpoints and kube-proxy# IP del pod: salta DNS, Service, endpoint e kube-proxy
k exec -n m11 cliente -- wget -qO- --timeout=2 $IP:5678

# port-forward al POD: saltea Service y kube-proxy# port-forward to the POD: skips Service and kube-proxy# port-forward al POD: salta Service e kube-proxy
k port-forward -n m11 pod/<POD> 8080:5678
# port-forward al SERVICE: pasa por el Service, no por kube-proxy del nodo# port-forward to the SERVICE: goes through the Service, not the node's kube-proxy# port-forward al SERVICE: passa dal Service, non dal kube-proxy del nodo
k port-forward -n m11 svc/web 8081:80

# ping a la ClusterIP: NUNCA responde, aunque todo esté sano# ping to the ClusterIP: NEVER answers, even when all is healthy# ping al ClusterIP: NON risponde MAI, anche se tutto è sano
k exec -n m11 cliente -- ping -c 2 <CLUSTER-IP>
Claves
Key points
Punti chiave
  • La ClusterIP no es de nadie. No hay interfaz con esa IP: es una regla de NAT en el kernel. Un ping que no vuelve NO significa que el Service esté roto — es el resultado normal, y perseguir ese fantasma cuesta minutos.
  • port-forward habla con el apiserver, no con el Service: por eso funciona incluso con kube-proxy caído. Si por ahí anda y por el Service no, ya sabés dónde mirar.
  • La IP del pod es tu corte 3, el que parte el problema exactamente al medio.
  • The ClusterIP belongs to nobody. No interface holds it: it is a NAT rule in the kernel. A ping that never returns does NOT mean the Service is broken — it is the normal result, and chasing that ghost costs minutes.
  • port-forward talks to the apiserver, not to the Service: that is why it works even with kube-proxy down. If it works there and not through the Service, you know where to look.
  • The pod IP is your cut 3, the one that splits the problem exactly in half.
  • Il ClusterIP non è di nessuno. Nessuna interfaccia lo possiede: è una regola di NAT nel kernel. Un ping che non torna NON significa che il Service sia rotto — è il risultato normale, e inseguire quel fantasma costa minuti.
  • Il port-forward parla con l'apiserver, non col Service: per questo funziona anche con kube-proxy caduto. Se lì funziona e dal Service no, sai dove guardare.
  • L'IP del pod è il tuo taglio 3, quello che divide il problema esattamente a metà.
T1

Troubleshooting — cero endpoints

Troubleshooting — zero endpoints

Troubleshooting — zero endpoint

~6 min

El nombre resuelve pero el curl muere por timeout. Aplicá los cortes en orden y llegá a la causa. Hay dos Services rotos acá y fallan por motivos distintos: encontrá los dos y decí en qué se diferencian mirando un solo comando.

The name resolves but curl dies on timeout. Apply the cuts in order and reach the cause. There are two broken Services here failing for different reasons: find both and say what tells them apart from a single command.

Il nome risolve ma il curl muore in timeout. Applica i tagli in ordine e arriva alla causa. Qui ci sono due Service rotti che falliscono per motivi diversi: trovali entrambi e di' cosa li distingue guardando un solo comando.

manifest · plantar el problemamanifest · plant the problemmanifest · piantare il problema
Ver soluciónShow solutionMostra soluzione
k describe svc -n m11 tienda | grep -iE 'selector|endpoints'
k describe svc -n m11 portal | grep -iE 'selector|endpoints'
#   los dos: Endpoints <none>#   both: Endpoints <none>#   entrambi: Endpoints <none>

# EL comando que los separa: filtrar por el selector del Service# THE command that separates them: filter by the Service's selector# IL comando che li separa: filtrare per il selector del Service
k get pods -n m11 -l app=tienda
#   No resources found  → SELECTOR: no matchea nada#   No resources found  → SELECTOR: matches nothing#   No resources found  → SELECTOR: non corrisponde a nulla
k get pods -n m11 -l app=portal
#   portal-xxx  Running  0/1  → READINESS: matchea pero no está Ready#   portal-xxx  Running  0/1  → READINESS: matches but is not Ready#   portal-xxx  Running  0/1  → READINESS: corrisponde ma non è Ready

k get pods -n m11 --show-labels
k set selector svc tienda -n m11 app=shop
k describe pod -n m11 -l app=portal | grep -A3 -i readiness
k edit deploy portal -n m11      # path: /healthz → /# path: /healthz → /# path: /healthz → /
Claves
Key points
Punti chiave
  • Mismo síntoma, dos causas, un comando para separarlas: k get pods -l <selector>. Sin pods → selector. Con pods en 0/1 → readiness. No hay tercera opción.
  • Es la causa número uno de todo el dominio de red, y falla sin dejar ni un evento: el Service existe, tiene IP y resuelve.
  • --show-labels te muestra el otro lado de la comparación en un renglón.
  • Same symptom, two causes, one command to separate them: k get pods -l <selector>. No pods → selector. Pods at 0/1 → readiness. There is no third option.
  • It is the number-one cause in the whole networking domain, and it fails without leaving a single event: the Service exists, has an IP and resolves.
  • --show-labels shows you the other side of the comparison in one line.
  • Stesso sintomo, due cause, un comando per separarle: k get pods -l <selector>. Nessun pod → selector. Pod a 0/1 → readiness. Non c'è una terza opzione.
  • È la causa numero uno di tutto il dominio di rete, e fallisce senza lasciare un solo evento: il Service esiste, ha un IP e risolve.
  • --show-labels ti mostra l'altro lato del confronto in una riga.
T2

Troubleshooting — timeout sin log

Troubleshooting — a timeout with no log

Troubleshooting — timeout senza log

~7 min

El Service tiene endpoints, el pod está Running 1/1 y sus logs no dicen nada raro. Aun así, desde cliente el curl muere por timeout — pero desde adentro del propio pod la app responde. Encontrá qué descarta el paquete.

The Service has endpoints, the pod is Running 1/1 and its logs say nothing odd. Still, from cliente the curl dies on timeout — yet from inside the pod itself the app answers. Find what is dropping the packet.

Il Service ha endpoint, il pod è Running 1/1 e i suoi log non dicono nulla di strano. Eppure da cliente il curl muore in timeout — ma da dentro il pod stesso l'app risponde. Trova cosa sta scartando il pacchetto.

manifest · plantar el problemamanifest · plant the problemmanifest · piantare il problema
Ver soluciónShow solutionMostra soluzione
# corte 2: hay endpoints → no es el selector# cut 2: there are endpoints → not the selector# taglio 2: ci sono endpoint → non è il selector
k describe svc -n m11 web | grep -i endpoints

# corte 3: por IP tampoco, y es TIMEOUT (no refused)# cut 3: not by IP either, and it is a TIMEOUT (not refused)# taglio 3: nemmeno per IP, ed è TIMEOUT (non refused)
k exec -n m11 cliente -- nc -zvw3 <IP-POD> 5678

# corte 4: desde adentro SÍ anda → la app está bien# cut 4: from inside it DOES work → the app is fine# taglio 4: da dentro funziona → l'app è a posto
k exec -n m11 deploy/web -- wget -qO- localhost:5678

# timeout + app sana = algo descarta en el camino, y no loguea# timeout + healthy app = something drops it on the way, and does not log# timeout + app sana = qualcosa lo scarta per strada, e non logga
k get netpol -A
k describe netpol -n m11

k delete netpol -n m11 <NOMBRE>      # confirmar en lab# confirm in the lab# confermare in lab
Claves
Key points
Punti chiave
  • "Timeout de afuera + anda por dentro" es la firma de una policy. Si el paquete hubiera llegado al pod, el kernel habría dicho refused. Timeout = nunca llegó.
  • Las NetworkPolicies no dejan ni un log. No hay evento, no hay warning, no hay nada en los logs de la app. k get netpol -A es el único modo de enterarte de que existen.
  • Mirá las dos puntas: el egress del origen y el ingress del destino. Un deny en cualquiera de las dos corta igual.
  • Antes de culpar a la app, hacé el corte 4. Cuesta un comando y descarta la mitad del universo.
  • "Timeout from outside + works inside" is a policy's signature. Had the packet reached the pod, the kernel would have said refused. Timeout = it never arrived.
  • NetworkPolicies leave no log at all. No event, no warning, nothing in the app's logs. k get netpol -A is the only way to learn they exist.
  • Look at both ends: the source's egress and the destination's ingress. A deny on either cuts it just the same.
  • Before blaming the app, do cut 4. It costs one command and rules out half the universe.
  • «Timeout da fuori + funziona dentro» è la firma di una policy. Se il pacchetto fosse arrivato al pod, il kernel avrebbe detto refused. Timeout = non è mai arrivato.
  • Le NetworkPolicy non lasciano alcun log. Nessun evento, nessun warning, nulla nei log dell'app. k get netpol -A è l'unico modo per sapere che esistono.
  • Guarda entrambi i capi: l'egress dell'origine e l'ingress della destinazione. Un deny su uno dei due taglia uguale.
  • Prima di incolpare l'app, fai il taglio 4. Costa un comando ed esclude metà universo.
T3

Troubleshooting — refused, no timeout

Troubleshooting — refused, not timeout

Troubleshooting — refused, non timeout

~6 min

Otro Service que no responde, pero el error no es el mismo que en T2. Leé el mensaje antes de hacer nada: te está diciendo que el paquete sí llegó. Encontrá la causa y arreglala.

Hay dos fallas posibles con este síntoma. Distinguilas comparando el targetPort del Service con el puerto donde la app realmente escucha.

Another Service that does not answer, but the error is not the same as in T2. Read the message before doing anything: it is telling you the packet did arrive. Find the cause and fix it.

There are two possible faults with this symptom. Tell them apart by comparing the Service's targetPort with the port the app actually listens on.

Un altro Service che non risponde, ma l'errore non è lo stesso del T2. Leggi il messaggio prima di fare qualsiasi cosa: ti sta dicendo che il pacchetto è arrivato. Trova la causa e sistemala.

Ci sono due guasti possibili con questo sintomo. Distinguili confrontando il targetPort del Service con la porta su cui l'app ascolta davvero.

manifest · plantar el problemamanifest · plant the problemmanifest · piantare il problema
Ver soluciónShow solutionMostra soluzione
k exec -n m11 cliente -- nc -zvw3 api 80
#   Connection refused
#   → llegó al pod: NO es policy ni CNI#   → it reached the pod: NOT a policy, NOT the CNI#   → è arrivato al pod: NON è policy né CNI

# comparar los dos lados del puerto# compare both sides of the port# confrontare i due lati della porta
k get svc api -n m11 -o jsonpath='{.spec.ports[*].targetPort}'; echo
k get pod -n m11 -l app=api -o jsonpath='{.items[0].spec.containers[*].ports[*].containerPort}'; echo
#   targetPort 8080 vs containerPort 5678 → no coinciden#   targetPort 8080 vs containerPort 5678 → they do not match#   targetPort 8080 vs containerPort 5678 → non coincidono

k patch svc api -n m11 -p '{"spec":{"ports":[{"port":80,"targetPort":5678}]}}'
k exec -n m11 cliente -- wget -qO- api:80
Claves
Key points
Punti chiave
  • Refused descarta media lista de sospechosos. Policy, CNI y ruteo quedan afuera de entrada: el paquete llegó y el kernel del destino contestó.
  • Este Service SÍ tiene endpoints. Es la diferencia con T1: el selector está bien, el pod está Ready, y aun así no anda. Cuando hay endpoints y falla, mirá los puertos.
  • La otra causa con el mismo síntoma es una app que hace bind a 127.0.0.1. Se distinguen con el corte 4: si desde adentro anda pero desde otro pod no, es el bind.
  • Nombrar el containerPort y usar targetPort: <nombre> hace este error imposible.
  • Refused rules out half the suspect list. Policy, CNI and routing are out from the start: the packet arrived and the destination kernel answered.
  • This Service DOES have endpoints. That is the difference from T1: the selector is fine, the pod is Ready, and it still does not work. When there are endpoints and it fails, look at the ports.
  • The other cause with this same symptom is an app binding to 127.0.0.1. Cut 4 separates them: if it works from inside but not from another pod, it is the bind.
  • Naming the containerPort and using targetPort: <name> makes this error impossible.
  • Refused esclude metà della lista dei sospetti. Policy, CNI e routing escono subito: il pacchetto è arrivato e il kernel di destinazione ha risposto.
  • Questo Service HA endpoint. È la differenza col T1: il selector è a posto, il pod è Ready, e comunque non va. Quando ci sono endpoint e fallisce, guarda le porte.
  • L'altra causa con lo stesso sintomo è un'app che fa bind su 127.0.0.1. Il taglio 4 le separa: se da dentro funziona ma da un altro pod no, è il bind.
  • Dare un nome al containerPort e usare targetPort: <nome> rende questo errore impossibile.
T4

Troubleshooting — el cluster entero dejó de resolver

Troubleshooting — the whole cluster stopped resolving

Troubleshooting — l'intero cluster ha smesso di risolvere

~7 min

Ningún pod de ningún namespace resuelve nombres, pero por IP todo anda perfecto. Recorré la cadena del DNS de punta a punta y arreglá. Después distinguí este caso del de un namespace con egress cerrado: ¿qué prueba los separa?

El manifest solo arma el blanco. La rotura toca kube-system y va a mano: k -n kube-system scale deploy coredns --replicas=0. Snapshot antes; restaurar con --replicas=2.

No pod in any namespace resolves names, but by IP everything works fine. Walk the DNS chain end to end and fix it. Then tell this case apart from a namespace with a closed egress: which test separates them?

The manifest only sets up the target. The break touches kube-system and is done by hand: k -n kube-system scale deploy coredns --replicas=0. Snapshot first; restore with --replicas=2.

Nessun pod di nessun namespace risolve i nomi, ma per IP funziona tutto benissimo. Percorri la catena del DNS da un capo all'altro e sistema. Poi distingui questo caso da un namespace con egress chiuso: quale prova li separa?

Il manifest prepara solo il bersaglio. La rottura tocca kube-system e si fa a mano: k -n kube-system scale deploy coredns --replicas=0. Prima lo snapshot; ripristina con --replicas=2.

manifest · armar el escenariomanifest · set the scenemanifest · preparare lo scenario
Ver soluciónShow solutionMostra soluzione
# el hecho clave: por IP funciona, por nombre no → es DNS, no red# the key fact: by IP it works, by name it does not → it is DNS, not networking# il fatto chiave: per IP funziona, per nome no → è DNS, non rete
k exec -n m11 cliente -- nc -zvw2 <IP-POD> 5678      # open
k exec -n m11 cliente -- nc -zvw2 web 5678            # bad address

# 1 · ¿corren los pods de CoreDNS?# 1 · are the CoreDNS pods running?# 1 · i pod di CoreDNS girano?
k get pods -n kube-system -l k8s-app=kube-dns
# 2 · ¿el Service kube-dns tiene endpoints?# 2 · does the kube-dns Service have endpoints?# 2 · il Service kube-dns ha endpoint?
k -n kube-system describe svc kube-dns | grep -i endpoints
# 3 · ¿el pod apunta al nameserver correcto?# 3 · does the pod point at the right nameserver?# 3 · il pod punta al nameserver giusto?
k exec -n m11 cliente -- cat /etc/resolv.conf

k -n kube-system scale deploy coredns --replicas=2
k run t -n m11 --rm -it --image=busybox:1.28 -- nslookup web
Claves
Key points
Punti chiave
  • "Por IP sí, por nombre no" es el primer test, siempre. Parte el problema al medio en un comando: la red está sana, el que falla es el DNS.
  • La prueba que separa CoreDNS de un egress cerrado es el ALCANCE. CoreDNS caído afecta a todos los namespaces; una NetworkPolicy de egress afecta a uno solo. Probá desde un pod de otro namespace y ya sabés cuál de los dos es.
  • La cadena tiene tres eslabones y se revisan en orden: pods de CoreDNS → Service kube-dns con endpoints → resolv.conf del pod.
  • CoreDNS es un Deployment normal: logs, describe y get cm coredns como cualquier app. Un Corefile roto también se ve en sus logs.
  • "By IP yes, by name no" is the first test, always. It splits the problem in half with one command: the network is healthy, DNS is what fails.
  • The test separating CoreDNS from a closed egress is SCOPE. A downed CoreDNS affects every namespace; an egress NetworkPolicy affects one. Test from a pod in another namespace and you know which it is.
  • The chain has three links, checked in order: CoreDNS pods → kube-dns Service with endpoints → the pod's resolv.conf.
  • CoreDNS is an ordinary Deployment: logs, describe and get cm coredns like any app. A broken Corefile shows up in its logs too.
  • «Per IP sì, per nome no» è il primo test, sempre. Divide il problema a metà con un comando: la rete è sana, a fallire è il DNS.
  • La prova che separa CoreDNS da un egress chiuso è l'AMBITO. CoreDNS caduto colpisce tutti i namespace; una NetworkPolicy di egress ne colpisce uno. Prova da un pod di un altro namespace e sai quale dei due è.
  • La catena ha tre anelli, da controllare in ordine: pod di CoreDNS → Service kube-dns con endpoint → resolv.conf del pod.
  • CoreDNS è un Deployment normale: logs, describe e get cm coredns come qualsiasi app. Anche un Corefile rotto si vede nei suoi log.

Autoevaluación — antes de marcar M11 como ★ dominado

Self-check — before marking M11 as ★ mastered

Autovalutazione — prima di segnare M11 come ★ padroneggiato

  • Correr los cuatro cortes en orden, sin pensarlos.
  • Decir, viendo solo el mensaje de error, a qué capa te manda.
  • Distinguir refused de timeout y saber qué descarta cada uno.
  • Separar "selector que no matchea" de "pods no Ready" con un comando.
  • Reconocer una NetworkPolicy por el timeout sin logs.
  • Recorrer la cadena del DNS en sus tres eslabones.
  • Distinguir CoreDNS caído de un egress cerrado por el alcance.
  • No perder tiempo haciéndole ping a una ClusterIP.
  • Run the four cuts in order, without thinking.
  • Say, from the error message alone, which layer it sends you to.
  • Tell refused from timeout and know what each rules out.
  • Separate "selector does not match" from "pods not Ready" with one command.
  • Recognise a NetworkPolicy by the timeout with no logs.
  • Walk the DNS chain through its three links.
  • Tell a downed CoreDNS from a closed egress by scope.
  • Not waste time pinging a ClusterIP.
  • Eseguire i quattro tagli in ordine, senza pensarci.
  • Dire, dal solo messaggio d'errore, a quale strato ti manda.
  • Distinguere refused da timeout e sapere cosa esclude ciascuno.
  • Separare «selector che non corrisponde» da «pod non Ready» con un comando.
  • Riconoscere una NetworkPolicy dal timeout senza log.
  • Percorrere la catena del DNS nei suoi tre anelli.
  • Distinguere CoreDNS caduto da un egress chiuso in base all'ambito.
  • Non perdere tempo a fare ping a un ClusterIP.
Módulo 11 completado · Fin de la Fase 1: los 5 dominios cubiertos · Siguiente: Fase 2 — labs por dominio, Killer.sh y speed drills
Module 11 complete · End of Phase 1: all 5 domains covered · Next: Phase 2 — labs by domain, Killer.sh and speed drills
Modulo 11 completato · Fine della Fase 1: i 5 domini coperti · Prossimo: Fase 2 — lab per dominio, Killer.sh e speed drill