Tancàvem el mòdul 3 assenyalant que la xarxa de Rutas Norte és completament plana: qualsevol pod de rutas-norte-pro pot obrir una connexió a postgres-reserves:5432, i cap client d'internet no pot arribar encara a www.rutasnorte.example. Abans de posar portes (les polítiques de xarxa de 04-06) i finestres (l'Ingress de 04-04), cal entendre com està construïda la casa. Aquesta lliçó és la que explica què hi ha realment sota d'aquella 10.244.x.x que veus a kubectl get pods -o wide, qui crea aquesta interfície de xarxa, per què la IP d'un Service no apareix en cap targeta de xarxa de cap màquina, i com un paquet que surt d'api-reserves acaba entrant a postgres-reserves. És la lliçó més "de lampisteria" del curs, i també la que fa que tota la resta deixi de semblar màgia.

Contingut

  1. El model de xarxa de Kubernetes i les seves quatre regles
  2. Per què aquest model simplifica tota la resta
  3. Els quatre plans de comunicació
  4. CNI: la interfície que connecta el pod a la xarxa
  5. Els plugins: Flannel, Calico, Cilium i Weave Net
  6. Superposició (VXLAN), encaminament natiu (BGP) i eBPF
  7. Els rangs d'adreces del clúster
  8. Com s'implementa de debò un ClusterIP: kube-proxy
  9. Recorregut complet d'un paquet a Rutas Norte
  10. Comprovació pràctica a minikube

  1. El model de xarxa de Kubernetes i les seves quatre regles

Kubernetes no implementa la xarxa. El que fa és imposar un contracte: defineix un model que qualsevol implementació de xarxa ha de complir, i deixa que altres el compleixin com vulguin. El contracte té quatre regles.

# Regla Què significa a la pràctica
1 Cada pod té la seva pròpia adreça IP No es comparteix la IP del node ni es fa mapatge de ports. api-reserves escolta al 3000 dins de la seva pròpia IP, encara que hi hagi cinc rèpliques al mateix node
2 Tot pod pot parlar amb tot pod sense NAT Tant és si són al mateix node o en nodes diferents: la connexió és directa, sense traducció d'adreces
3 Els agents del node arriben als pods d'aquest node El kubelet, i per tant les sondes de salut de 07-01, poden connectar amb els pods sense trucs
4 La IP que el pod veu de si mateix és la que veuen els altres Si dins del contenidor hostname -i diu 10.244.1.37, els altres pods el veuen exactament com a 10.244.1.37

La quarta regla sembla redundant, però és la que prohibeix explícitament el model de Docker clàssic. En un docker run -p 8080:80, el contenidor es pensa que és 172.17.0.4:80 mentre la resta del món el veu com a 192.168.1.10:8080. Aquesta discrepància trenca qualsevol protocol que anunciï la seva pròpia adreça: bases de dades en clúster, sistemes de descobriment, registres de servei. Kubernetes l'elimina d'arrel.

Fixa't en el que no diu el contracte: res sobre com s'encaminen els paquets, si hi ha encapsulació, quin rang d'IP s'usa o si hi ha tallafocs. Tot això és llibertat d'implementació.

  1. Per què aquest model simplifica tota la resta

El model es resumeix en una frase: "IP per pod, xarxa plana". Les seves conseqüències són enormes.

  • Els ports deixen de ser un recurs escàs. En un món de mapatge de ports, desplegar tres rèpliques d'api-reserves al mateix node obliga a assignar-los 3000, 3001 i 3002, i que algú en porti el compte. Amb IP per pod, totes tres escolten al 3000. El manifest no canvia segons on caigui el pod.
  • Les aplicacions no necessiten saber que són a Kubernetes. Una aplicació que funciona en una màquina virtual funciona en un pod: obre el seu port i connecta a host:port. Això és el que va permetre migrar tant programari sense reescriure'l.
  • El descobriment esdevé trivial. Com que no hi ha NAT, la IP que l'EndpointSlice de 02-05 apunta és directament connectable. Sense aquesta garantia, cada Service hauria de traduir adreces i ports per node.
  • La migració de pods és transparent. Un pod mor i un altre neix amb una altra IP, però la mecànica de connexió és idèntica.

El preu és que per defecte no hi ha cap aïllament. La regla 2 diu "tot pod pot parlar amb tot pod", i això és exactament el que significa: el pod més insignificant de rutas-norte-pro pot intentar connectar amb postgres-reserves. Les NetworkPolicies de 04-06 existeixen precisament per retallar aquest permís universal.

  1. Els quatre plans de comunicació

Quan algú diu "la xarxa de Kubernetes" acostuma a estar barrejant quatre problemes diferents, amb solucions diferents.

flowchart TB
    subgraph N1["Node 1"]
      subgraph P1["Pod api-reserves 10.244.1.5"]
        C1["contenidor api"]
        C2["sidecar de registres"]
      end
      P2["Pod redis-cache<br/>10.244.1.9"]
    end
    subgraph N2["Node 2"]
      P3["Pod postgres-reserves<br/>10.244.2.4"]
    end
    EXT["Client d'internet"]
    SVC["Service ClusterIP<br/>10.96.31.72"]

    C1 -.->|"1. localhost"| C2
    P1 -->|"2. pod a pod, sense NAT"| P3
    P1 -->|"3. pod a Service"| SVC
    SVC --> P2
    EXT -->|"4. exterior a Service"| SVC
Pla Com es resol On s'estudia
1. Contenidor ↔ contenidor dins del mateix pod Comparteixen el network namespace: es veuen per localhost i competeixen pels mateixos ports Ja vist a 02-01; patrons a 06-04
2. Pod ↔ pod Ho implementa el plugin CNI. És el tema central d'aquesta lliçó Aquí, apartats 4 a 7
3. Pod ↔ Service Ho implementa kube-proxy (o el CNI, si substitueix kube-proxy) reescrivint destinacions Aquí, apartat 8
4. Exterior ↔ Service Tipus de Service NodePort/LoadBalancer i Ingress 04-02 i 04-04

Un error de diagnòstic molt habitual és atacar el pla equivocat. Si api-reserves no arriba a postgres-reserves per IP de pod, el problema és del CNI. Si hi arriba per IP de pod però no pel nom del Service, el problema és de kube-proxy o del DNS de 04-03. Separar els plans estalvia hores.

  1. CNI: la interfície que connecta el pod a la xarxa

CNI (Container Network Interface) és una especificació de la CNCF, molt curta i deliberadament avorrida: defineix com un runtime de contenidors demana a un programa extern que connecti o desconnecti un contenidor d'una xarxa. No és un producte: és un contracte entre dues parts.

La cadena d'invocació en crear un pod és aquesta:

sequenceDiagram
    participant K as kubelet
    participant CR as containerd
    participant CNI as Plugin CNI
    participant IPAM as IPAM
    K->>CR: crear sandbox del pod
    CR->>CR: crear network namespace buit
    CR->>CNI: ADD (namespace, ID del pod)
    CNI->>IPAM: dona'm una IP del podCIDR del node
    IPAM-->>CNI: 10.244.1.37/24
    CNI->>CNI: crear veth, moure un extrem al ns
    CNI->>CNI: assignar IP, ruta per defecte
    CNI-->>CR: OK, IP 10.244.1.37
    CR-->>K: sandbox llest
    K->>CR: arrencar els contenidors del pod

Els punts que convé fixar:

  • Qui invoca el plugin és el kubelet a través del runtime (containerd, al nostre clúster). L'apiserver no toca la xarxa.
  • El plugin s'instal·la com un binari a /opt/cni/bin i es configura amb un fitxer JSON a /etc/cni/net.d. Per això els plugins es despleguen gairebé sempre com un DaemonSet (06-02): un pod per node que copia el binari i el fitxer de configuració en arrencar i després es queda executant el seu agent.
  • Les operacions són ADD, DEL, CHECK i VERSION. En esborrar el pod s'invoca DEL i la IP torna al pool.
  • IPAM (IP Address Management) és un subcomponent: decideix quina IP concreta s'assigna dins del rang que li toca al node.

El que fa el plugin en un ADD típic, traduït a ordres que ja coneixes de Linux:

  1. Crea un parell veth (dues interfícies virtuals unides com un cable).
  2. Deixa un extrem al network namespace de l'amfitrió (amb nom tipus veth3a7f2c1@if3) i mou l'altre dins del namespace del pod, on s'anomena eth0.
  3. Demana una IP a l'IPAM i l'assigna a eth0.
  4. Afegeix la ruta per defecte del pod, apuntant al pont o a la passarel·la d'enllaç del node.
  5. A l'amfitrió, connecta el seu extrem al pont (cni0, docker0, cbr0) o crea la ruta corresponent.
  6. Retorna al runtime la IP assignada, que acaba a status.podIP del pod.

Si el CNI falla o no està instal·lat, veuràs el símptoma clàssic:

NAME                            READY   STATUS                 RESTARTS   AGE
api-reserves-7d9f5c8b4-x2kp9    0/1     ContainerCreating      0          3m

Events:
  Warning  FailedCreatePodSandBox  kubelet  Failed to create pod sandbox:
  plugin type="bridge" failed (add): failed to set bridge addr: could not add IP

Pods eternament en ContainerCreating amb errors de sandbox gairebé sempre són problema de xarxa del node, no del teu manifest.

  1. Els plugins: Flannel, Calico, Cilium i Weave Net

Triar plugin és una de les decisions més duradores d'un clúster: canviar-lo amb càrrega en producció és una operació delicada. Aquests són els quatre històricament més utilitzats.

Flannel Calico Cilium Weave Net
Model de dades Superposició VXLAN (o host-gw) Encaminament natiu L3 amb BGP; opció VXLAN/IPIP eBPF al kernel; opcional VXLAN/geneve o natiu Superposició pròpia (VXLAN "fast datapath")
NetworkPolicy No la implementa Sí, i a més polítiques pròpies més riques Sí, incloses polítiques L7 (HTTP, Kafka, DNS) Sí (suport bàsic)
Rendiment Bo; penalització per encapsulació Molt bo en mode natiu (sense encapsular) El millor: pot substituir kube-proxy Acceptable; el menys ràpid dels quatre
Complexitat Mínima Mitjana (BGP requereix entendre la xarxa física) Alta; requereix kernel modern Baixa
Xifratge en trànsit No WireGuard WireGuard o IPsec Sí, integrat
Observabilitat Cap Mètriques Prometheus Hubble: fluxos, mapes de servei, L7 Bàsica
Quan triar-lo Aprendre, laboratori, clúster sense requisits d'aïllament Producció amb NetworkPolicy i xarxa sota el teu control Producció exigent, observabilitat, polítiques L7, malla sense sidecars Instal·lacions senzilles on ja s'usa

Conseqüència pràctica per a Rutas Norte, i cal subratllar-la: si el clúster fa servir Flannel, les NetworkPolicies que escriguis a 04-06 s'aplicaran sense error i no faran absolutament res. L'objecte es crea, kubectl get networkpolicy el llista, i el trànsit continua passant. És la fallada silenciosa més perillosa d'aquesta part del curs, i per això la verificarem explícitament.

Els clústers gestionats de 10-06 porten el seu propi plugin (Amazon VPC CNI, Azure CNI, el de GKE), que sol assignar als pods IP de la xarxa real del núvol. Això fa que un pod sigui directament encaminable des d'altres màquines de la VPC, amb la contrapartida de consumir adreces de l'espai corporatiu.

  1. Superposició (VXLAN), encaminament natiu (BGP) i eBPF

El problema que resolen tots és el mateix: el pod 10.244.1.5 és al node A i vol parlar amb 10.244.2.4, que és al node B. La xarxa física entre nodes no sap res de 10.244.0.0/16: si li lliures aquest paquet tal qual, el descarta.

Xarxa superposada (VXLAN)

Es construeix una xarxa virtual damunt de la física. El node origen fica el paquet original sencer dins d'un paquet UDP adreçat a la IP real del node destinació (port 8472 a VXLAN), que el desencapsula i el lliura al pod.

[ IP nodeA -> IP nodeB | UDP 8472 | VXLAN | IP 10.244.1.5 -> 10.244.2.4 | TCP 5432 | dades ]
   \_______________ sobre exterior _______________/ \____________ paquet original ______/
  • Avantatge decisiu: funciona sobre qualsevol xarxa, sense tocar routers ni demanar res a l'equip de xarxes. Per això és el mode per defecte de tantes instal·lacions.
  • Cost: la capçalera afegeix uns 50 bytes, cosa que redueix la MTU efectiva (de 1500 a 1450 típicament) i provoca fragmentació si alguna cosa la ignora; hi ha feina extra d'encapsular i desencapsular a cada paquet; i el trànsit és opac per als tallafocs i analitzadors de la xarxa física, que només veuen UDP entre nodes.

Encaminament natiu (BGP)

No s'encapsula res. Cada node anuncia per BGP als routers de la xarxa física: "el rang 10.244.2.0/24 s'assoleix a través meu". La xarxa física aprèn les rutes i lliura els paquets de pod directament.

  • Avantatge: sense sobrecost, MTU íntegra, el trànsit de pods és visible i filtrable amb les eines de xarxa existents.
  • Requisit: la xarxa ho ha de permetre. En un centre de dades propi amb routers que parlin BGP, és l'ideal. En molts núvols o en xarxes corporatives tancades, no és possible i es torna a l'encapsulació.

eBPF

eBPF permet carregar programes verificats dins del kernel de Linux i enganxar-los a punts concrets de la pila de xarxa. Cilium l'utilitza per prendre decisions d'encaminament, balanceig i política abans que el paquet recorri tota la maquinària d'iptables.

  • Pot substituir per complet kube-proxy, eliminant les cadenes d'iptables que veurem a l'apartat 8.
  • Escala molt millor: on iptables degrada amb milers de Services, eBPF fa servir taules hash de cost constant.
  • Habilita polítiques amb coneixement d'HTTP (per ruta i mètode) i identitat de càrrega de treball.
  • A canvi, exigeix un kernel raonablement recent i apuja el llistó de coneixement per depurar.
Criteri VXLAN BGP natiu eBPF
Sobrecost per paquet Alt (~50 B + encapsulat) Nul Nul o negatiu
Requisits de la xarxa física Cap Ha d'encaminar/parlar BGP Cap
Visibilitat des de la xarxa física Baixa Alta Mitjana
Escalat amb molts Services Depèn de kube-proxy Depèn de kube-proxy Excel·lent

  1. Els rangs d'adreces del clúster

En un clúster conviuen tres espais d'adreces que no s'han de confondre mai.

Rang Què adreça Exemple a minikube Encaminable fora?
Xarxa de nodes Les màquines físiques o virtuals 192.168.49.0/24 Sí, és la xarxa real
podCIDR / cluster CIDR Les IP dels pods 10.244.0.0/16, trossejat en /24 per node Només dins del clúster
serviceCIDR Les IP virtuals dels Services 10.96.0.0/12 No existeix en cap interfície

El cluster CIDR global es reparteix: el kube-controller-manager, amb --allocate-node-cidrs, assigna a cada node una porció (per defecte un /24, és a dir 254 pods útils per node) i l'escriu a spec.podCIDR de l'objecte Node. L'IPAM del plugin CNI reparteix IP dins d'aquesta porció. Així es garanteix que dos nodes no assignin mai la mateixa IP.

On es configuren:

# En crear el cluster amb kubeadm (llico 10-02)
kubeadm init --pod-network-cidr=10.244.0.0/16 --service-cidr=10.96.0.0/12

# A minikube, en crear el perfil
minikube start -p rutas-norte --extra-config=kubeadm.pod-network-cidr=10.244.0.0/16

Tres avisos que estalvien incidents:

  1. No es poden canviar en calent. Canviar el serviceCIDR d'un clúster viu no és una operació suportada; es planifica abans de crear-lo.
  2. No s'han de solapar amb la xarxa corporativa. Si la teva empresa fa servir 10.96.0.0/16 per a servidors, els pods de Rutas Norte no hi podran parlar: el node es pensarà que aquelles IP són Services del clúster.
  3. El /24 per node és un límit real. Un node gran amb 300 pods es queda sense adreces encara que li sobri CPU i memòria.

  1. Com s'implementa de debò un ClusterIP: kube-proxy

Aquí hi ha la revelació de la lliçó. Quan a 02-05 vas crear el Service postgres-reserves amb clusterIP: 10.96.140.22, aquella adreça no es va assignar a cap interfície de cap màquina. És una ficció. No respon al ping. No hi ha cap procés escoltant-hi.

El que existeix són regles de reescriptura de destinació instal·lades a cada node per kube-proxy, un DaemonSet del namespace kube-system que observa l'API i, cada vegada que canvia un Service o un EndpointSlice, actualitza aquestes regles.

flowchart LR
    API["kube-apiserver<br/>Services + EndpointSlices"] -->|watch| KP["kube-proxy<br/>(un pod per node)"]
    KP -->|programa regles| DP["iptables / IPVS<br/>del kernel del node"]
    POD["Pod origen"] -->|"connecta a 10.96.140.22:5432"| DP
    DP -->|"DNAT a 10.244.2.4:5432"| DEST["Pod postgres-reserves"]

Mode iptables (el més habitual)

Per a cada Service, kube-proxy crea una cadena KUBE-SERVICES que casa per IP i port de destinació, salta a una cadena KUBE-SVC-XXXX pròpia del Service, i d'allà reparteix entre les cadenes KUBE-SEP-YYYY, una per endpoint, cadascuna amb la seva regla DNAT.

# Cadena d'entrada: captura el transit cap a la IP del Service
-A KUBE-SERVICES -d 10.96.140.22/32 -p tcp --dport 5432
   -j KUBE-SVC-QW3RTY5432ABCD

# Repartiment entre 2 endpoints amb probabilitat estadistica
-A KUBE-SVC-QW3RTY5432ABCD -m statistic --mode random --probability 0.50000
   -j KUBE-SEP-AAA111
-A KUBE-SVC-QW3RTY5432ABCD -j KUBE-SEP-BBB222

# Cada endpoint: traduccio de desti a la IP real del pod
-A KUBE-SEP-AAA111 -p tcp -j DNAT --to-destination 10.244.2.4:5432
-A KUBE-SEP-BBB222 -p tcp -j DNAT --to-destination 10.244.3.7:5432

D'aquí surten tres fets importants:

  • El balanceig és aleatori per connexió, no per petició. Una connexió TCP llarga (una sessió de PostgreSQL, un WebSocket) queda enganxada a un pod fins que es tanca. Per això una API que multiplexa peticions sobre poques connexions pot repartir malament la càrrega.
  • La probabilitat és en cascada: amb 3 endpoints, les regles porten 1/3, després 1/2, després la resta. Així surt uniforme.
  • El cost és lineal: iptables avalua regles en ordre. Amb desenes de milers de Services, cada actualització obliga a reprogramar taules enormes i apareixen latències de sincronització. És el motiu que existeixin IPVS i eBPF.

Mode IPVS

IPVS és el balancejador de càrrega L4 del kernel de Linux, amb taules hash en lloc de llistes de regles.

iptables IPVS
Estructura Llista de regles avaluada en ordre Taula hash, cost constant
Escalat Degrada amb milers de Services Estable amb desenes de milers
Algorismes Només aleatori rr, lc, dh, sh, sed, nq
Depuració iptables-save ipvsadm -Ln
Requisits Cap Mòduls ip_vs* carregats

En mode IPVS sí que apareix una interfície kube-ipvs0 al node amb les IP dels Services assignades, però és una interfície dummy: serveix perquè el kernel accepti els paquets, no per respondre.

La regla mental que cal endur-se: el Service és una regla, no una màquina. Si un ClusterIP no respon, no busquis un procés caigut: busca endpoints buits (selector que no casa, com vas veure a 02-05) o un kube-proxy que no sincronitza.

  1. Recorregut complet d'un paquet a Rutas Norte

Seguim una connexió real: el pod api-reserves-7d9f5c8b4-x2kp9 (10.244.1.5, node 1) obre una connexió a postgres-reserves:5432 (ClusterIP 10.96.140.22), l'únic endpoint del qual és 10.244.2.4 al node 2. El clúster fa servir VXLAN.

sequenceDiagram
    participant APP as api-reserves (10.244.1.5)
    participant DNS as CoreDNS
    participant NS1 as Kernel node 1
    participant NET as Xarxa fisica
    participant NS2 as Kernel node 2
    participant PG as postgres-reserves (10.244.2.4)

    APP->>DNS: postgres-reserves.rutas-norte-pro.svc.cluster.local?
    DNS-->>APP: 10.96.140.22
    APP->>NS1: SYN a 10.96.140.22:5432 (surt per eth0/veth)
    NS1->>NS1: KUBE-SERVICES -> KUBE-SVC -> KUBE-SEP<br/>DNAT desti = 10.244.2.4:5432
    NS1->>NS1: ruta: 10.244.2.0/24 esta via VXLAN al node2
    NS1->>NET: encapsula UDP 8472 node1 -> node2
    NET->>NS2: lliura el paquet exterior
    NS2->>NS2: desencapsula: IP 10.244.1.5 -> 10.244.2.4
    NS2->>PG: SYN pel veth del pod
    PG-->>NS2: SYN-ACK a 10.244.1.5
    NS2->>NET: tornada encapsulada
    NET->>NS1: lliurament
    NS1->>NS1: conntrack desfa el DNAT:<br/>origen passa a 10.96.140.22:5432
    NS1-->>APP: SYN-ACK aparentment del ClusterIP

Els detalls que importen:

  • La resolució del nom passa primer i és independent de tota la resta (04-03).
  • El DNAT passa al node d'origen, abans d'encaminar. El node 2 no veu mai la IP del Service.
  • postgres-reserves veu com a origen 10.244.1.5, la IP real del pod client, no la del node. Això és la regla 2 (sense NAT d'origen) i és el que permet que les NetworkPolicies de 04-06 puguin identificar l'emissor per les seves etiquetes. Compte: això canvia quan el trànsit entra des de fora amb externalTrafficPolicy: Cluster (04-02).
  • conntrack és imprescindible: el kernel recorda la traducció per desfer-la a la resposta. Una taula conntrack plena provoca connexions que es perden aleatòriament sota càrrega, un símptoma clàssic als pics dels ponts de Rutas Norte.

  1. Comprovació pràctica a minikube

Tot l'anterior es pot tocar amb les mans al perfil rutas-norte.

Els rangs del clúster

# podCIDR assignat a cada node
kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.podCIDR}{"\n"}{end}'
rutas-norte     10.244.0.0/24
# El serviceCIDR no s'exposa com a camp; es dedueix provocant un error
kubectl create svc clusterip prova-cidr --tcp=80:80 --dry-run=server \
  -o yaml --clusterip=1.2.3.4
The Service "prova-cidr" is invalid: spec.clusterIPs[0]:
Invalid value: []string{"1.2.3.4"}: failed to allocate IP 1.2.3.4:
the provided IP (1.2.3.4) is not in the valid range. The range of valid IPs is 10.96.0.0/12

És un truc molt útil: el missatge d'error et revela el rang exacte.

Les IP reals de la plataforma

kubectl get pods -n rutas-norte-pro -o wide
kubectl get svc  -n rutas-norte-pro
NAME                             READY  STATUS   IP            NODE
api-reserves-7d9f5c8b4-x2kp9     1/1    Running  10.244.0.31   rutas-norte
postgres-reserves-5c9d7f-4nm2q   1/1    Running  10.244.0.14   rutas-norte

NAME                TYPE        CLUSTER-IP      PORT(S)
postgres-reserves   ClusterIP   10.96.140.22    5432/TCP

Les IP de pod són a 10.244.0.x (el podCIDR de l'únic node) i la del Service a 10.96.x.x. Rangs diferents, natureses diferents.

Les regles que no existeixen i les que sí

# La IP del Service no es a cap interficie del node
minikube -p rutas-norte ssh -- ip -4 addr show | grep -E "inet "
    inet 127.0.0.1/8 scope host lo
    inet 192.168.49.2/24 brd 192.168.49.255 scope global eth0
    inet 10.244.0.1/24 brd 10.244.0.255 scope global bridge

Ni rastre de 10.96.140.22. Ara les regles:

minikube -p rutas-norte ssh -- \
  "sudo iptables-save -t nat | grep 10.96.140.22"
-A KUBE-SERVICES -d 10.96.140.22/32 -p tcp -m comment
   --comment "rutas-norte-pro/postgres-reserves cluster IP" -m tcp --dport 5432
   -j KUBE-SVC-6GHJ2KLM4NOPQRST

El comentari inclou <namespace>/<servei>: és la manera més ràpida de localitzar les regles d'un Service concret.

Un pod efímer amb eines de xarxa

La imatge nicolaka/netshoot porta dig, curl, nc, tcpdump, traceroute i ipvsadm. És la navalla suïssa per depurar xarxes a Kubernetes.

kubectl run netshoot --rm -it --restart=Never \
  -n rutas-norte-pro --image=nicolaka/netshoot -- bash

Dins del pod:

# 1. La meva propia IP: ha d'estar al podCIDR del node
ip -4 addr show eth0 | grep inet
# inet 10.244.0.42/24 scope global eth0

# 2. Connectivitat pod a pod DIRECTA (pla 2, salta el Service)
nc -zv 10.244.0.14 5432
# Connection to 10.244.0.14 5432 port [tcp/postgresql] succeeded!

# 3. Connectivitat pod a Service (pla 3)
nc -zv postgres-reserves 5432
# Connection to postgres-reserves 5432 port [tcp/postgresql] succeeded!

# 4. El que demostra l'avis del modul 3: un pod qualsevol,
#    sense cap relacio amb la plataforma, arriba a la base de dades
#    amb les dades personals dels clients. Aixo ho arregla 04-06.

Si el pas 2 funciona i el 3 no, el CNI està bé i el problema és de Service o DNS. Si el 2 tampoc no funciona, és el CNI o una política de xarxa. Aquesta bifurcació és el 80 % del diagnòstic de xarxa a Kubernetes.

Errors Comuns i Consells

  • Confondre els tres rangs. Veure 10.96.x.x i buscar en quin node és aquell pod és un clàssic. Regla: 10.244.x.x és un pod (existeix), 10.96.x.x és un Service (és una regla), 192.168.x.x és un node.
  • Fer ping a un ClusterIP. No respon i això és normal: les regles de kube-proxy només casen TCP/UDP al port declarat, no ICMP. Un ping fallit a un Service no demostra res. Fes servir nc -zv o curl.
  • Solapar el podCIDR o el serviceCIDR amb la xarxa corporativa. Provoca fallades incomprensibles en parlar amb serveis externs, com la passarel·la de pagaments. Comprova-ho abans de crear el clúster, no després.
  • Ignorar la MTU amb VXLAN. Connexions que obren bé però es pengen en transferir blocs grans (una restauració de PostgreSQL, una resposta JSON de 2 MB) solen ser MTU mal ajustada. Diagnòstic: ping -M do -s 1400 <ip>.
  • Triar Flannel i escriure NetworkPolicies. S'apliquen sense error i no filtren res. Abans de confiar en una política, verifica que el CNI la implementa amb una prova real.
  • Culpar el CNI de tot. Abans d'això, comprova els plans per ordre: localhost dins del pod, IP de pod, ClusterIP, nom DNS. El primer que falli assenyala la capa culpable.
  • Consell: desa un àlies per al pod de depuració. alias kshoot='kubectl run netshoot-$RANDOM --rm -it --restart=Never --image=nicolaka/netshoot -- bash'. Amb --rm no deixes brossa al clúster.
  • Consell: en producció, revisa les mètriques de conntrack (nf_conntrack_count davant de nf_conntrack_max). Als pics dels ponts de Rutas Norte, la taula plena es manifesta com a errors de connexió intermitents sense cap pod caigut.

Exercicis

Exercici 1: Cartografiar la xarxa del clúster

Sobre el perfil rutas-norte, documenta: el podCIDR del node, el serviceCIDR, la IP del node, i les IP dels pods i Services de rutas-norte-pro. Classifica cada adreça al seu rang i explica quines existeixen físicament i quines no.

Exercici 2: Demostrar que el ClusterIP és una ficció

Tria el Service redis-cache. Demostra amb tres comprovacions que la seva IP no existeix en cap interfície, que sí que existeixen regles d'iptables per a ella, i que tot i així s'hi pot connectar. Explica qui fa la traducció i en quin node passa.

Exercici 3: Separar els plans davant d'una avaria

Un company diu que api-reserves "no veu la base de dades". Dissenya una seqüència de comprovacions, de la capa més baixa a la més alta, que permeti decidir si el problema és del CNI, del Service, del DNS o de la mateixa aplicació. Executa-la amb netshoot i anota quina sortida esperaries en cada cas de fallada.

Solucions

Exercici 1

kubectl get nodes -o custom-columns=NODE:.metadata.name,\
POD_CIDR:.spec.podCIDR,IP:.status.addresses[0].address

kubectl create svc clusterip x --tcp=80:80 --clusterip=1.2.3.4 --dry-run=server 2>&1 | tail -1

kubectl get pods -n rutas-norte-pro -o custom-columns=POD:.metadata.name,IP:.status.podIP
kubectl get svc  -n rutas-norte-pro -o custom-columns=SVC:.metadata.name,CLUSTERIP:.spec.clusterIP

Classificació esperada:

Adreça Rang Existeix?
192.168.49.2 Xarxa de nodes Sí, és eth0 del node
10.244.0.31 podCIDR Sí, és eth0 dins del pod
10.96.140.22 serviceCIDR No: només regles al kernel
10.244.0.1 podCIDR Sí, és el pont del node (passarel·la d'enllaç dels pods)

Exercici 2

IP=$(kubectl get svc redis-cache -n rutas-norte-pro -o jsonpath='{.spec.clusterIP}')

# 1. No es a cap interficie
minikube -p rutas-norte ssh -- "ip -4 addr | grep $IP || echo 'NO APAREIX: correcte'"

# 2. Si que hi ha regles
minikube -p rutas-norte ssh -- "sudo iptables-save -t nat | grep $IP"

# 3. I tanmateix connecta
kubectl run t --rm -it --restart=Never -n rutas-norte-pro \
  --image=nicolaka/netshoot -- nc -zv redis-cache 6379

La traducció (DNAT) la fa el kernel del node on s'executa el pod client, fent servir les regles que kube-proxy va programar a partir de l'EndpointSlice. El paquet surt del node ja amb la IP real del pod destinació.

Exercici 3

Seqüència de menor a major nivell, amb la conclusió de cada fallada:

kubectl exec -it deploy/api-reserves -n rutas-norte-pro -- sh

# Pla 1: el proces local escolta?
nc -zv localhost 3000            # falla -> l'app no ha arrencat: no es xarxa

# Pla 2: IP de pod directa
PGIP=$(kubectl get pod -l app=postgres-reserves -n rutas-norte-pro \
        -o jsonpath='{.items[0].status.podIP}')
nc -zv $PGIP 5432                # falla -> CNI o NetworkPolicy

# Pla 3: ClusterIP
nc -zv 10.96.140.22 5432         # falla (i l'anterior OK) -> kube-proxy o endpoints buits
kubectl get endpointslices -n rutas-norte-pro -l kubernetes.io/service-name=postgres-reserves

# Pla DNS
nslookup postgres-reserves       # falla (i l'anterior OK) -> CoreDNS o resolv.conf

# Pla aplicacio
psql -h postgres-reserves -U reserves -c 'select 1'   # falla -> credencials o base de dades

Cada esglaó que funciona descarta una capa sencera. El primer que falla anomena el culpable.

Conclusió

Ja saps què hi ha sota la xarxa de Kubernetes. El model se sosté en quatre regles obligatòries —IP per pod, comunicació pod a pod sense NAT, els agents del node arriben als seus pods, i la IP que el pod veu de si mateix és la que veuen els altres— i és aquesta uniformitat la que permet que les aplicacions no sàpiguen que són en un clúster i que els ports deixin de ser un recurs a administrar. Distingeixes els quatre plans de comunicació i saps quin diagnosticar primer quan alguna cosa falla.

Has vist que Kubernetes delega la implementació en un plugin CNI, que el kubelet invoca a través del runtime en crear cada pod, i que fa una feina molt concreta: crear un parell veth, demanar una IP a l'IPAM dins del podCIDR del node i programar les rutes. Coneixes les diferències reals entre Flannel, Calico, Cilium i Weave Net, i en particular que Flannel no implementa NetworkPolicy, un detall que condicionarà la lliçó 04-06. Entens el compromís entre encapsular amb VXLAN (funciona a qualsevol lloc, costa 50 bytes i MTU) i encaminar de forma nativa amb BGP (gratis, però exigeix col·laboració de la xarxa física), i per què eBPF està desplaçant tots dos enfocaments als clústers exigents.

I sobretot, has desmuntat la ficció més útil de Kubernetes: el ClusterIP no existeix. No és a cap interfície, no respon al ping i no hi ha cap procés al darrere. Només hi ha regles d'iptables o entrades d'IPVS que kube-proxy manté sincronitzades amb els EndpointSlices, fent DNAT al node d'origen i desfent-lo a la resposta gràcies a conntrack. Has seguit un paquet d'api-reserves a postgres-reserves de principi a fi i ho has comprovat al teu propi minikube.

Amb la lampisteria entesa, toca pujar un pis. A 04-02 veurem que ClusterIP és només un dels quatre tipus de Service, que cadascun es construeix sobre l'anterior, i com NodePort, LoadBalancer i ExternalName comencen a obrir la plataforma a l'exterior: el primer pas perquè un client que vol comprar un bitllet d'autobús pugui, per fi, arribar a botiga-web.

Curs de Kubernetes

Mòdul 1: Introducció a Kubernetes

Mòdul 2: Components Principals de Kubernetes

Mòdul 3: Gestió de Configuració i Secrets

Mòdul 4: Xarxes a Kubernetes

Mòdul 5: Emmagatzematge a Kubernetes

Mòdul 6: Conceptes Avançats de Kubernetes

Mòdul 7: Monitoratge i Registre

Mòdul 8: Seguretat a Kubernetes

Mòdul 9: Escalat i Rendiment

Mòdul 10: Ecosistema i Eines de Kubernetes

Mòdul 11: Estudis de Cas i Aplicacions del Món Real

Mòdul 12: Preparació per a la Certificació de Kubernetes

© Copyright 2026. Tots els drets reservats