Del puerto crudo al routing: Ingress, Gateway API y NetworkPolicies
From a raw port to routing: Ingress, Gateway API and NetworkPolicies
Dalla porta grezza al routing: Ingress, Gateway API e NetworkPolicy
Un Service te da una IP estable. Lo que no te da es enrutar por host y por path, terminar TLS, ni decidir quién puede hablarle a quién. Eso es este módulo: la capa 7 (Ingress y su sucesor, Gateway API) y el firewall del cluster (NetworkPolicy).
A Service gives you a stable IP. What it does not give you is routing by host and path, TLS termination, or deciding who may talk to whom. That is this module: layer 7 (Ingress and its successor, Gateway API) and the cluster's firewall (NetworkPolicy).
Un Service ti dà un IP stabile. Ciò che non ti dà è il routing per host e path, la terminazione TLS, o decidere chi può parlare con chi. Questo è il modulo: il livello 7 (Ingress e il suo successore, Gateway API) e il firewall del cluster (NetworkPolicy).
Duración75 min
Duration75 min
Durata75 min
DominioServices & Networking
DomainServices & Networking
DominioServices & Networking
Peso20% (2 de 2)
Weight20% (2 of 2)
Peso20% (2 di 2)
RequiereM6 (Services, DNS)
RequiresM6 (Services, DNS)
RichiedeM6 (Service, DNS)
El M6 terminó con un NodePort: funciona, pero es un puerto raro en cada nodo y un Service por cada app. Con diez apps son diez puertos y ningún nombre. Ingress invierte eso: una sola entrada al cluster que mira el Host y el path de cada request HTTP y la manda al Service correcto — y de paso termina el TLS. Después viene Gateway API, el reemplazo oficial de Ingress, que ya está en el curriculum del CKA v1.34 y que casi seguro te van a tomar. Y al final, la otra mitad: NetworkPolicy, que no enruta nada sino que prohibe — porque por defecto en Kubernetes todos los pods pueden hablarle a todos.
M6 ended on a NodePort: it works, but it is an odd port on every node and one Service per app. Ten apps means ten ports and no names. Ingress flips that: a single entrance to the cluster that reads each HTTP request's Host and path and sends it to the right Service — terminating TLS along the way. Then comes Gateway API, Ingress's official replacement, already in the CKA v1.34 curriculum and almost certainly on your exam. And finally the other half: NetworkPolicy, which routes nothing and instead forbids — because by default in Kubernetes every pod can talk to every pod.
Il M6 finiva con un NodePort: funziona, ma è una porta strana su ogni nodo e un Service per ogni app. Con dieci app sono dieci porte e nessun nome. Ingress ribalta la cosa: un solo ingresso al cluster che legge Host e path di ogni richiesta HTTP e la manda al Service giusto — terminando il TLS per strada. Poi arriva Gateway API, il sostituto ufficiale di Ingress, già nel curriculum del CKA v1.34 e quasi certamente nel tuo esame. E infine l'altra metà: NetworkPolicy, che non instrada nulla ma proibisce — perché di default in Kubernetes ogni pod può parlare con ogni pod.
Modelo mental del módulo
Module mental model
Modello mentale del modulo
Ingress/Gateway = ENRUTA hacia adentro · NetworkPolicy = PROHIBE adentro
Ingress/Gateway = INSTRADA verso l'interno · NetworkPolicy = PROIBISCE dentro
Son dos ejes independientes que la gente mezcla. El primero es capa 7: HTTP entra desde afuera y se reparte por host/path a Services. El segundo es capa 3/4: qué pods pueden abrir conexiones a qué pods, por IP y puerto. Un Ingress bien configurado no te protege nada; una NetworkPolicy no enruta nada.
Two independent axes that people conflate. The first is layer 7: HTTP arrives from outside and is split by host/path across Services. The second is layer 3/4: which pods may open connections to which pods, by IP and port. A well-configured Ingress protects nothing; a NetworkPolicy routes nothing.
Due assi indipendenti che spesso si confondono. Il primo è il livello 7: l'HTTP arriva da fuori e viene distribuito per host/path fra i Service. Il secondo è il livello 3/4: quali pod possono aprire connessioni verso quali pod, per IP e porta. Un Ingress ben configurato non protegge nulla; una NetworkPolicy non instrada nulla.
7.1
Ingress: recurso + controller
Ingress: resource + controller
Ingress: risorsa + controller
La regla y el que la ejecuta. IngressClass.
The rule and whoever runs it. IngressClass.
La regola e chi la esegue. IngressClass.
7.2
Reglas: host, path, TLS
Rules: host, path, TLS
Regole: host, path, TLS
pathType, backends, secret TLS, default backend.
pathType, backends, TLS secret, default backend.
pathType, backend, secret TLS, default backend.
7.3
Gateway API
GatewayClass, Gateway, HTTPRoute. Lo nuevo del examen.
GatewayClass, Gateway, HTTPRoute. The exam's new material.
GatewayClass, Gateway, HTTPRoute. La novità dell'esame.
7.4
NetworkPolicies
Default deny, ingress/egress, los tres selectores.
Default deny, ingress/egress, the three selectors.
Default deny, ingress/egress, i tre selector.
7.5
CNI
Qué hace el plugin y cómo verificar que está vivo.
What the plugin does and how to check it is alive.
Cosa fa il plugin e come verificare che sia vivo.
★
Práctica · 8 ejercicios
Practice · 8 exercises
Pratica · 8 esercizi
Ingress, TLS, HTTPRoute y las policies que engañan, con manifest listo para aplicar.
Ingress, TLS, HTTPRoute and the policies that deceive, each with a ready-to-apply manifest.
Ingress, TLS, HTTPRoute e le policy che ingannano, ognuno con un manifest pronto da applicare.
7.1
La entrada HTTP · 20 min
The HTTP entrance · 20 min
L'ingresso HTTP · 20 min
Ingress: el recurso y el controller
Ingress: the resource and the controller
Ingress: la risorsa e il controller
El objeto describe el ruteo. Otro proceso lo ejecuta.
The object describes the routing. Another process executes it.
L'oggetto descrive il routing. Un altro processo lo esegue.
Práctica · Crear y leer
Practice · Create and read
Pratica · Creare e leggere
Imperativo: sí, existe
Imperative: yes, it exists
Imperativo: sì, esiste
# create ingress NAME --rule="HOST/PATH=SERVICE:PORT"k create ingress web --rule="demo.io/*=web:80"# Con class, TLS y varias reglas (--rule se repite)# With class, TLS and several rules (--rule repeats)# Con class, TLS e più regole (--rule si ripete)k create ingress tienda --class=nginx \
--rule="demo.io/api*=api-svc:8080" \
--rule="demo.io/*=web:80"# Generar el YAML para editarlo (el patrón de siempre)# Generate the YAML to edit it (the usual pattern)# Generare lo YAML per modificarlo (il solito pattern)k create ingress web --rule="demo.io/*=web:80" \
--dry-run=client -o yaml > ing.yaml
El YAML mínimo
The minimal YAML
Lo YAML minimo
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web
spec:
ingressClassName: nginx # QUIÉN lo atiende# WHO serves it# CHI lo serverules:
- host: demo.io
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web # un Service, no un pod# a Service, not a pod# un Service, non un podport:
number: 80
Verificar
Verify
Verificare
k get ingress
# NAME CLASS HOSTS ADDRESS PORTS# web nginx demo.io 192.168.64.11 80k describe ing web # reglas + eventos del controller# rules + controller events# regole + eventi del controllerk get ingressclass # qué classes hay# which classes exist# quali class esistono# Probarlo sin DNS real: Host header a mano# Test it without real DNS: set the Host header by hand# Provarlo senza DNS reale: header Host a mano
curl -H"Host: demo.io" http://<IP-NODO>:<NODEPORT>/
⚠
Si ADDRESS queda vacío y describe no muestra eventos, casi siempre es que no hay ingress controller instalado o que el ingressClassName no matchea ninguna IngressClass. El objeto Ingress se crea igual: la API lo acepta aunque nadie lo vaya a atender.
If ADDRESS stays empty and describe shows no events, it is nearly always that no ingress controller is installed, or that ingressClassName matches no IngressClass. The Ingress object is created anyway: the API accepts it even when nobody will serve it.
Se ADDRESS resta vuoto e describe non mostra eventi, quasi sempre è perché non c'è un ingress controller installato, o perché ingressClassName non corrisponde ad alcuna IngressClass. L'oggetto Ingress viene creato lo stesso: l'API lo accetta anche se nessuno lo servirà.
Teoría · Dos piezas separadas
Theory · Two separate pieces
Teoria · Due pezzi separati
El recurso no hace nada
The resource does nothing
La risorsa non fa nulla
Un objeto Ingress es declaración pura: "el host demo.io va al Service web". Quien lo hace realidad es el ingress controller: un pod (normalmente nginx, Traefik o HAProxy) que observa los objetos Ingress y se reconfigura a sí mismo. A diferencia de casi todo lo demás, el controller no viene con Kubernetes: lo instalás vos.
An Ingress object is pure declaration: "host demo.io goes to Service web". What makes it real is the ingress controller: a pod (usually nginx, Traefik or HAProxy) that watches Ingress objects and reconfigures itself. Unlike almost everything else, the controller does not ship with Kubernetes: you install it.
Un oggetto Ingress è pura dichiarazione: "l'host demo.io va al Service web". A renderlo reale è l'ingress controller: un pod (di solito nginx, Traefik o HAProxy) che osserva gli oggetti Ingress e si riconfigura da solo. A differenza di quasi tutto il resto, il controller non arriva con Kubernetes: lo installi tu.
Cómo entra el tráfico
How traffic gets in
Come entra il traffico
El controller es un Deployment con su propio Service — normalmente NodePort en bare-metal o LoadBalancer en la nube. O sea: el tráfico entra por el Service del controller, y de ahí el controller decide, mirando el HTTP, a qué Service interno mandarlo. El Ingress no reemplaza a los Services: se apoya en ellos.
The controller is a Deployment with its own Service — usually NodePort on bare metal or LoadBalancer in the cloud. So: traffic enters through the controller's Service, and from there the controller decides, by reading the HTTP, which internal Service to forward to. Ingress does not replace Services: it rests on them.
Il controller è un Deployment con il proprio Service — di solito NodePort su bare metal o LoadBalancer in cloud. Quindi: il traffico entra dal Service del controller, e da lì il controller decide, leggendo l'HTTP, a quale Service interno inoltrarlo. Ingress non sostituisce i Service: si appoggia su di essi.
IngressClass
Si hay varios controllers en el cluster, ingressClassName dice cuál se hace cargo. Una IngressClass puede marcarse como default con la anotación ingressclass.kubernetes.io/is-default-class: "true"; ahí podés omitir el campo.
With several controllers in the cluster, ingressClassName says which one takes charge. An IngressClass can be marked default with the annotation ingressclass.kubernetes.io/is-default-class: "true"; then you can omit the field.
Con più controller nel cluster, ingressClassName dice quale se ne occupa. Una IngressClass può essere marcata come default con l'annotazione ingressclass.kubernetes.io/is-default-class: "true"; allora puoi omettere il campo.
Qué agrega sobre un Service
What it adds over a Service
Cosa aggiunge rispetto a un Service
Capacidad
Service
Ingress
Capability
Service
Ingress
Capacità
Service
Ingress
Capa
L4 (TCP/UDP)
L7 (HTTP/S)
Layer
L4 (TCP/UDP)
L7 (HTTP/S)
Livello
L4 (TCP/UDP)
L7 (HTTP/S)
Rutea por host
no
sí
Routes by host
no
yes
Instrada per host
no
sì
Rutea por path
no
sí
Routes by path
no
yes
Instrada per path
no
sì
Termina TLS
no
sí
Terminates TLS
no
yes
Termina il TLS
no
sì
Puntos de entrada
uno por app
uno para todas
Entry points
one per app
one for all
Punti d'ingresso
uno per app
uno per tutte
★
Cadena completa, memorizala en este orden: cliente → Service del controller (NodePort/LB) → pod del controller → regla del Ingress → Service de la app → pod. Cuando algo no anda, recordá que hay dos Services en el camino.
The full chain, memorise it in this order: client → the controller's Service (NodePort/LB) → controller pod → Ingress rule → the app's Service → pod. When something breaks, remember there are two Services on the path.
La catena completa, memorizzala in quest'ordine: client → Service del controller (NodePort/LB) → pod del controller → regola dell'Ingress → Service dell'app → pod. Quando qualcosa non va, ricorda che ci sono due Service sul percorso.
7.2
Ruteo fino · 15 min
Fine routing · 15 min
Routing fine · 15 min
Hosts, paths, pathType y TLS
Hosts, paths, pathType and TLS
Host, path, pathType e TLS
Donde se pierden los puntos: pathType y el secret del TLS.
Where the points are lost: pathType and the TLS secret.
Dove si perdono i punti: pathType e il secret del TLS.
rules:
- host: tienda.demo.io
http: {paths: [...]} # → Service tienda
- host: blog.demo.io
http: {paths: [...]} # → Service blog# Sin host: la regla matchea CUALQUIER host# With no host: the rule matches ANY host# Senza host: la regola corrisponde a QUALSIASI host
TLS: el secret primero
TLS: the secret first
TLS: prima il secret
# 1. Certificado (en el examen te lo suelen dar)# 1. Certificate (usually given to you in the exam)# 1. Certificato (all'esame di solito te lo danno)
openssl req -x509-newkey rsa:2048 -nodes-days 365 \
-keyout tls.key -out tls.crt -subj"/CN=demo.io"# 2. Secret de tipo tls (nombres de clave FIJOS)# 2. A tls-type Secret (FIXED key names)# 2. Un Secret di tipo tls (nomi delle chiavi FISSI)k create secret tls demo-tls --cert=tls.crt --key=tls.key
# 3. Referenciarlo en el Ingress# 3. Reference it in the Ingress# 3. Referenziarlo nell'Ingressspec:
tls:
- hosts: [demo.io]
secretName: demo-tls
rules: ...
Backend por defecto (catch-all)
Default backend (catch-all)
Backend predefinito (catch-all)
spec:
defaultBackend:
service:
name: fallback
port: {number: 80}
# Lo que no matchea ninguna regla cae acá# Whatever matches no rule lands here# Ciò che non corrisponde a nessuna regola finisce qui
★
El secret TLS tiene que estar en el mismo namespace que el Ingress. Es el error más repetido del tema: creás el secret en default y el Ingress vive en web, y el controller sirve un certificado auto-firmado genérico sin decir mucho más que un evento.
The TLS secret must live in the same namespace as the Ingress. It is the most repeated mistake here: you create the secret in default while the Ingress lives in web, and the controller serves a generic self-signed certificate, saying little beyond one event.
Il secret TLS deve stare nello stesso namespace dell'Ingress. È l'errore più ripetuto del tema: crei il secret in default mentre l'Ingress vive in web, e il controller serve un certificato autofirmato generico, dicendo poco più di un evento.
Teoría · Los detalles que puntúan
Theory · The details that score
Teoria · I dettagli che danno punti
pathType: obligatorio y con trampa
pathType: mandatory, and a trap
pathType: obbligatorio, e una trappola
pathType
Matchea
pathType
Matches
pathType
Corrisponde a
Exact
El path exacto, sin más (case-sensitive)
Exact
That exact path, nothing else (case-sensitive)
Exact
Quel path esatto, nient'altro (case-sensitive)
Prefix
Por elementos separados por /
Prefix
By elements separated by /
Prefix
Per elementi separati da /
ImplementationSpecific
Lo que decida el controller
ImplementationSpecific
Whatever the controller decides
ImplementationSpecific
Quel che decide il controller
Prefix con /foo matchea /foo y /foo/bar, pero no/foobar: compara segmentos completos, no texto. Es la sutileza que hace fallar ejercicios.
Prefix with /foo matches /foo and /foo/bar, but not/foobar: it compares whole segments, not text. That subtlety is what fails exercises.
Prefix con /foo corrisponde a /foo e /foo/bar, ma non a /foobar: confronta segmenti interi, non testo. È la sottigliezza che fa fallire gli esercizi.
Prioridad de matcheo
Match priority
Priorità di corrispondenza
Ante varias reglas que matchean, gana el path más largo. Por eso /api le gana a / sin importar el orden en que los escribiste. Y si dos empatan en largo, gana Exact sobre Prefix. El matcheo además es case-sensitive en los dos tipos: /API no entra por una regla /api.
When several rules match, the longest path wins. That is why /api beats / regardless of the order you wrote them in. And if two tie on length, Exact beats Prefix. Matching is also case-sensitive for both types: /API does not match an /api rule.
Se più regole corrispondono, vince il path più lungo. Per questo /api batte / indipendentemente dall'ordine in cui li hai scritti. E se due pareggiano in lunghezza, vince Exact su Prefix. Il match è inoltre case-sensitive per entrambi i tipi: /API non entra da una regola /api.
TLS: quién termina qué
TLS: who terminates what
TLS: chi termina cosa
El TLS termina en el controller: de ahí hacia el Service el tráfico va en claro dentro del cluster (salvo que configures re-encryption con anotaciones). El secret tiene que ser de tipo kubernetes.io/tls, con las claves tls.crt y tls.key — esos nombres no son negociables.
TLS terminates at the controller: from there to the Service the traffic travels in the clear inside the cluster (unless you configure re-encryption with annotations). The secret must be of type kubernetes.io/tls, with the keys tls.crt and tls.key — those names are not negotiable.
Il TLS termina al controller: da lì al Service il traffico viaggia in chiaro dentro il cluster (a meno che tu non configuri la re-encryption con annotazioni). Il secret deve essere di tipo kubernetes.io/tls, con le chiavi tls.crt e tls.key — quei nomi non sono negoziabili.
Anotaciones: potentes y no portables
Annotations: powerful and not portable
Annotazioni: potenti e non portabili
Rewrites, redirects, timeouts, rate limiting: casi nada de eso está en la spec de Ingress; se hace con anotaciones propias del controller (nginx.ingress.kubernetes.io/rewrite-target, etc.). Esa fragmentación es exactamente la razón por la que existe Gateway API.
Rewrites, redirects, timeouts, rate limiting: almost none of that is in the Ingress spec; it is done with controller-specific annotations (nginx.ingress.kubernetes.io/rewrite-target, etc.). That fragmentation is exactly why Gateway API exists.
Rewrite, redirect, timeout, rate limiting: quasi nulla di questo è nella spec di Ingress; si fa con annotazioni specifiche del controller (nginx.ingress.kubernetes.io/rewrite-target, ecc.). Quella frammentazione è esattamente il motivo per cui esiste Gateway API.
★
Ante la duda en el examen: pathType: Prefix y path: /. Es el caso general y el que menos sorpresas da. Guardá Exact para cuando el enunciado diga literalmente "solo esa ruta".
When in doubt in the exam: pathType: Prefix and path: /. It is the general case and the one with fewest surprises. Save Exact for when the wording literally says "only that route".
Nel dubbio all'esame: pathType: Prefix e path: /. È il caso generale e quello con meno sorprese. Tieni Exact per quando il testo dice letteralmente "solo quella rotta".
VisorExplorerVisore · pathTypey la regla que ganaand the winning rulee la regola che vince
Ojo con /apifoo: es el caso que hace fallar ejercicios.
Watch /apifoo: it is the case that fails exercises.
Attenzione a /apifoo: è il caso che fa fallire gli esercizi.
Referencia · todos los campos del Ingress
Reference · every Ingress field
Riferimento · tutti i campi dell'Ingress
Campo
Qué hace
Field
What it does
Campo
Cosa fa
ingressClassName
Qué controller se hace cargo. Si lo omitís, solo lo toma la IngressClass marcada como default; si no hay ninguna, nadie lo atiende y ADDRESS queda vacío.
ingressClassName
Which controller takes it. If you omit it, only the IngressClass marked as default picks it up; if there is none, nobody serves it and ADDRESS stays empty.
ingressClassName
Quale controller se ne occupa. Se lo ometti, lo prende solo la IngressClass marcata come default; se non ce n'è nessuna, non lo serve nessuno e ADDRESS resta vuoto.
rules[].host
El Host: que tiene que traer el request. Omitido, matchea cualquier host. Admite un comodín de un solo nivel: *.demo.io cubre a.demo.io, pero no a.b.demo.io ni demo.io.
rules[].host
The Host: the request must carry. Omitted, it matches any host. It takes a single-level wildcard: *.demo.io covers a.demo.io, but not a.b.demo.io nor demo.io.
rules[].host
L'Host: che la richiesta deve portare. Omesso, corrisponde a qualsiasi host. Accetta un wildcard di un solo livello: *.demo.io copre a.demo.io, ma non a.b.demo.io né demo.io.
path
La ruta que se compara. Siempre arranca con /. Ante varias reglas que matchean, gana el más largo, no el orden.
path
The route being compared. Always starts with /. When several rules match, the longest wins, not the order.
path
Il percorso da confrontare. Inizia sempre con /. Quando più regole corrispondono, vince il più lungo, non l'ordine.
pathType: Prefix
Compara por elementos separados por /. /api cubre /api y /api/loquesea — pero no/apifoo.
pathType: Prefix
Compares by elements split on /. /api covers /api and /api/anything — but not/apifoo.
pathType: Prefix
Confronta per elementi separati da /. /api copre /api e /api/qualsiasi — ma non/apifoo.
pathType: Exact
Solo esa ruta, literal y sensible a mayúsculas. No cubre subpaths: /salud no incluye /salud/x.
pathType: Exact
That route only, literal and case-sensitive. It does not cover subpaths: /salud does not include /salud/x.
pathType: Exact
Solo quel percorso, letterale e case-sensitive. Non copre i subpath: /salud non include /salud/x.
pathType: ImplementationSpecific
Lo decide el controller. Ahí entran los comodines y las regex de nginx — a cambio, el manifiesto deja de ser portable. En el examen, usá Prefix o Exact salvo que te pidan otra cosa.
pathType: ImplementationSpecific
The controller decides. That is where nginx wildcards and regex live — in exchange, the manifest stops being portable. In the exam use Prefix or Exact unless told otherwise.
pathType: ImplementationSpecific
Decide il controller. Lì entrano i wildcard e le regex di nginx — in cambio, il manifest smette di essere portabile. All'esame usa Prefix o Exact salvo diversa richiesta.
backend.service.name
El Service destino. Tiene que existir en el mismo namespace que el Ingress.
backend.service.name
The target Service. It must exist in the same namespace as the Ingress.
backend.service.name
Il Service di destinazione. Deve esistere nello stesso namespace dell'Ingress.
backend.service.port.number
El puerto del Service, no el del container. Si el Service tiene nombre de puerto, se usa port.name en su lugar.
backend.service.port.number
The Service port, not the container one. If the Service names its port, use port.name instead.
backend.service.port.number
La porta del Service, non quella del container. Se il Service dà un nome alla porta, si usa port.name.
tls[].secretName
El Secret con el certificado: tipo kubernetes.io/tls, claves tls.crt y tls.key, y en el namespace del Ingress. Es el error más repetido del tema.
tls[].secretName
The Secret holding the certificate: type kubernetes.io/tls, keys tls.crt and tls.key, and in the Ingress namespace. The most repeated mistake on this topic.
tls[].secretName
Il Secret con il certificato: tipo kubernetes.io/tls, chiavi tls.crt e tls.key, e nel namespace dell'Ingress. È l'errore più ripetuto del tema.
tls[].hosts
Para qué nombres presenta ese certificado (SNI). Sin ningún host en las reglas, el controller no sabe qué servir.
tls[].hosts
Which names that certificate is presented for (SNI). With no host in the rules, the controller does not know what to serve.
tls[].hosts
Per quali nomi presenta quel certificato (SNI). Senza nessun host nelle regole, il controller non sa cosa servire.
defaultBackend
A dónde va lo que no matchea ninguna regla — un catch-all. Sin él, el controller devuelve 404.
defaultBackend
Where whatever matches no rule goes — a catch-all. Without it, the controller returns 404.
defaultBackend
Dove va ciò che non corrisponde a nessuna regola — un catch-all. Senza, il controller risponde 404.
Constructor · armá el Ingress campo por campo y mirá el YAML
metadata
agregar una regla
extras
7.3
Lo nuevo · 25 min
The new material · 25 min
La novità · 25 min
Gateway API: el sucesor de Ingress
Gateway API: Ingress's successor
Gateway API: il successore di Ingress
Tres objetos en vez de uno, y un rol distinto para cada uno.
Three objects instead of one, each with a different role.
Tre oggetti invece di uno, ciascuno con un ruolo diverso.
Práctica · Los tres objetos
Practice · The three objects
Pratica · I tre oggetti
Primero: ¿está instalado?
First: is it installed?
Prima: è installato?
# Gateway API son CRDs (M3): no vienen con el cluster# Gateway API are CRDs (M3): they do not ship with the cluster# Gateway API sono CRD (M3): non arrivano col clusterk get crd | grep gateway.networking.k8s.io
k api-resources | grep -i gateway
k get gatewayclass # qué implementaciones hay# which implementations exist# quali implementazioni ci sonok get gateway,httproute -A# qué hay desplegado# what is deployed# cosa è distribuito
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: prod-gw
namespace: infra
spec:
gatewayClassName: nginx
listeners:
- name: http
protocol: HTTP
port: 80
allowedRoutes: # QUIÉN puede engancharse# WHO may attach# CHI può agganciarsinamespaces:
from: All # All | Same | Selector
HTTPRoute: las reglas (la usa el dev)
HTTPRoute: the rules (used by the dev)
HTTPRoute: le regole (la usa il dev)
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: web-route
spec:
parentRefs: # a QUÉ Gateway se engancha# WHICH Gateway it attaches to# a QUALE Gateway si aggancia
- name: prod-gw
namespace: infra
hostnames: ["demo.io"]
rules:
- matches:
- path:
type: PathPrefix # ojo: PathPrefix, no Prefix# careful: PathPrefix, not Prefix# attenzione: PathPrefix, non Prefixvalue: /api
backendRefs:
- name: api
port: 8080
Split de tráfico (canary), gratis
Traffic splitting (canary), for free
Split del traffico (canary), gratis
backendRefs:
- {name: web-v1, port: 80, weight: 90}
- {name: web-v2, port: 80, weight: 10}
# Con Ingress esto exigía anotaciones propietarias# With Ingress this required proprietary annotations# Con Ingress questo richiedeva annotazioni proprietarie
⚠
No hay kubectl create httproute: son CRDs, así que se escriben a mano. Practicá encontrarlos rápido en la doc (kubernetes.io → Services, Load Balancing and Networking → Gateway API) y usá k explain httproute.spec --recursive como red de seguridad offline.
There is no kubectl create httproute: they are CRDs, so you write them by hand. Practise finding them fast in the docs (kubernetes.io → Services, Load Balancing and Networking → Gateway API) and use k explain httproute.spec --recursive as your offline safety net.
Non esiste kubectl create httproute: sono CRD, quindi si scrivono a mano. Allenati a trovarli in fretta nella documentazione (kubernetes.io → Services, Load Balancing and Networking → Gateway API) e usa k explain httproute.spec --recursive come rete di sicurezza offline.
Teoría · Por qué existe
Theory · Why it exists
Teoria · Perché esiste
El problema de Ingress
Ingress's problem
Il problema di Ingress
La spec de Ingress es diminuta y todo lo interesante quedó en anotaciones específicas de cada controller. Migrar de nginx a Traefik significaba reescribir todo. Además, un solo objeto mezclaba dos responsabilidades: la infraestructura de entrada (del admin) y las rutas de cada app (del dev).
The Ingress spec is tiny and everything interesting ended up in controller-specific annotations. Migrating from nginx to Traefik meant rewriting everything. On top of that, a single object mixed two responsibilities: the entry infrastructure (the admin's) and each app's routes (the dev's).
La spec di Ingress è minuscola e tutto ciò che è interessante è finito in annotazioni specifiche di ogni controller. Migrare da nginx a Traefik significava riscrivere tutto. In più, un solo oggetto mescolava due responsabilità: l'infrastruttura d'ingresso (dell'admin) e le rotte di ogni app (del dev).
La separación en tres
The split into three
La divisione in tre
Objeto
Lo maneja
Define
Object
Owned by
Defines
Oggetto
Gestito da
Definisce
GatewayClass
Proveedor / admin
Qué implementación
GatewayClass
Provider / admin
Which implementation
GatewayClass
Provider / admin
Quale implementazione
Gateway
Admin del cluster
Puertos, protocolo, TLS
Gateway
Cluster admin
Ports, protocol, TLS
Gateway
Admin del cluster
Porte, protocollo, TLS
HTTPRoute
Dev de la app
Hosts, paths, backends
HTTPRoute
App developer
Hosts, paths, backends
HTTPRoute
Dev dell'app
Host, path, backend
Cada rol toca solo lo suyo. El Gateway declara quién puede engancharse con allowedRoutes; la HTTPRoute declara a qué Gateway se engancha con parentRefs. Las dos puntas tienen que consentir — ahí está la seguridad del modelo.
Each role touches only its own. The Gateway declares who may attach with allowedRoutes; the HTTPRoute declares which Gateway it attaches to with parentRefs. Both ends must consent — that is the model's security.
Ogni ruolo tocca solo il proprio. Il Gateway dichiara chi può agganciarsi con allowedRoutes; l'HTTPRoute dichiara a quale Gateway si aggancia con parentRefs. Entrambe le parti devono acconsentire — è lì la sicurezza del modello.
Equivalencias mentales
Mental equivalences
Equivalenze mentali
Ingress
Gateway API
IngressClass
GatewayClass
Ingress (listener)
Gateway
Ingress (listener)
Gateway
Ingress (listener)
Gateway
Ingress (rules)
HTTPRoute
Ingress (rules)
HTTPRoute
Ingress (rules)
HTTPRoute
pathType: Prefix
type: PathPrefix
anotaciones
campos de la spec
annotations
spec fields
annotazioni
campi della spec
Estado en v1.34
Status in v1.34
Stato nella v1.34
Ingress está congelado (no recibe features nuevas, pero no está deprecado ni se va a ir). Gateway API es GA para HTTPRoute/Gateway/GatewayClass, se instala como CRDs, y más allá de HTTP existen GRPCRoute, TLSRoute, TCPRoute y UDPRoute — o sea, sirve también para lo que no es HTTP.
Ingress is frozen (no new features, but not deprecated and not going away). Gateway API is GA for HTTPRoute/Gateway/GatewayClass, installs as CRDs, and beyond HTTP there are GRPCRoute, TLSRoute, TCPRoute and UDPRoute — so it also covers what is not HTTP.
Ingress è congelato (nessuna nuova feature, ma non è deprecato e non sparirà). Gateway API è GA per HTTPRoute/Gateway/GatewayClass, si installa come CRD, e oltre all'HTTP esistono GRPCRoute, TLSRoute, TCPRoute e UDPRoute — quindi copre anche ciò che non è HTTP.
★
Gateway API entró explícitamente al curriculum del CKA. Lo más probable que te pidan: convertir un Ingress existente a HTTPRoute, o crear una HTTPRoute contra un Gateway que ya está. Practicá los dos sentidos de la traducción hasta que salga sin pensar.
Gateway API entered the CKA curriculum explicitly. The likeliest ask: convert an existing Ingress into an HTTPRoute, or create an HTTPRoute against a Gateway that already exists. Drill the translation both ways until it is automatic.
Gateway API è entrato esplicitamente nel curriculum del CKA. La richiesta più probabile: convertire un Ingress esistente in HTTPRoute, o creare un HTTPRoute su un Gateway già presente. Allena la traduzione in entrambi i versi finché non viene automatica.
Referencia · campos del Gateway
Reference · Gateway fields
Riferimento · campi del Gateway
Campo
Qué hace
Field
What it does
Campo
Cosa fa
gatewayClassName
Qué implementación lo hace realidad. Apunta a una GatewayClass, que a su vez nombra al controller. Es el equivalente de ingressClassName.
gatewayClassName
Which implementation makes it real. Points at a GatewayClass, which in turn names the controller. The equivalent of ingressClassName.
gatewayClassName
Quale implementazione lo realizza. Punta a una GatewayClass, che a sua volta nomina il controller. È l'equivalente di ingressClassName.
listeners[].name
Nombre del listener, único dentro del Gateway. Es lo que una route referencia con sectionName.
listeners[].name
Listener name, unique within the Gateway. It is what a route references with sectionName.
listeners[].name
Nome del listener, unico nel Gateway. È ciò che una route referenzia con sectionName.
listeners[].protocol
HTTP, HTTPS, TLS, TCP o UDP. Define qué Route se le puede enganchar: una HTTPRoute solo va a HTTP o HTTPS; para el resto hay TCPRoute, UDPRoute y TLSRoute.
listeners[].protocol
HTTP, HTTPS, TLS, TCP or UDP. It decides which Route can attach: an HTTPRoute only goes to HTTP or HTTPS; the rest have TCPRoute, UDPRoute and TLSRoute.
listeners[].protocol
HTTP, HTTPS, TLS, TCP o UDP. Decide quale Route può agganciarsi: una HTTPRoute va solo su HTTP o HTTPS; per il resto ci sono TCPRoute, UDPRoute e TLSRoute.
listeners[].port
El puerto donde escucha. Dos listeners pueden compartirlo solo si se distinguen por hostname y comparten protocolo.
listeners[].port
The port it listens on. Two listeners can share it only if they differ by hostname and share the protocol.
listeners[].port
La porta di ascolto. Due listener possono condividerla solo se si distinguono per hostname e condividono il protocollo.
listeners[].hostname
Para qué nombre escucha. Una route se engancha solo si sus hostnamesintersecan con este. Vacío = cualquiera.
listeners[].hostname
Which name it serves. A route attaches only if its hostnamesintersect with this one. Empty = any.
listeners[].hostname
Per quale nome ascolta. Una route si aggancia solo se i suoi hostnamessi intersecano con questo. Vuoto = qualsiasi.
tls.mode: Terminate
El Gateway descifra: necesita certificateRefs. De ahí al backend el tráfico va en claro dentro del cluster.
tls.mode: Terminate
The Gateway decrypts: it needs certificateRefs. From there to the backend traffic travels in the clear inside the cluster.
tls.mode: Terminate
Il Gateway decifra: richiede certificateRefs. Da lì al backend il traffico viaggia in chiaro dentro il cluster.
tls.mode: Passthrough
El Gateway no descifra: el TLS llega entero al backend. No lleva certificateRefs y, como nunca ve HTTP, no admite una HTTPRoute — ese caso va con TLSRoute.
tls.mode: Passthrough
The Gateway does not decrypt: TLS reaches the backend whole. It takes no certificateRefs and, since it never sees HTTP, it accepts no HTTPRoute — that case goes with TLSRoute.
tls.mode: Passthrough
Il Gateway non decifra: il TLS arriva intero al backend. Non prende certificateRefs e, non vedendo mai HTTP, non accetta una HTTPRoute — quel caso va con TLSRoute.
tls.certificateRefs
Los Secret con el certificado, como el secretName del Ingress pero en lista (podés servir varios nombres).
tls.certificateRefs
The Secrets holding the certificate, like the Ingress secretName but as a list (you can serve several names).
tls.certificateRefs
I Secret con il certificato, come il secretName dell'Ingress ma in lista (puoi servire più nomi).
allowedRoutes.namespaces.from
Quién puede engancharse: All (cualquier namespace), Same (solo el del Gateway) o Selector (los namespaces con ciertos labels). Es la mitad del consentimiento — la otra mitad es el parentRefs de la route.
allowedRoutes.namespaces.from
Who may attach: All (any namespace), Same (only the Gateway's) or Selector (namespaces carrying certain labels). It is half of the consent — the other half is the route's parentRefs.
allowedRoutes.namespaces.from
Chi può agganciarsi: All (qualsiasi namespace), Same (solo quello del Gateway) o Selector (i namespace con certe label). È metà del consenso — l'altra metà è il parentRefs della route.
Y los de la HTTPRoute
And the HTTPRoute ones
E quelli della HTTPRoute
Campo
Qué hace
Field
What it does
Campo
Cosa fa
parentRefs
A qué Gateway se engancha esta route: nombre y namespace. Es la otra mitad del consentimiento.
parentRefs
Which Gateway this route attaches to: name and namespace. It is the other half of the consent.
parentRefs
A quale Gateway si aggancia questa route: nome e namespace. È l'altra metà del consenso.
parentRefs[].sectionName
Un listener concreto del Gateway, por su name. Omitido, la route intenta engancharse a todos los que la acepten.
parentRefs[].sectionName
A specific listener of the Gateway, by its name. Omitted, the route tries to attach to every listener that accepts it.
parentRefs[].sectionName
Un listener specifico del Gateway, per il suo name. Omesso, la route prova ad agganciarsi a tutti quelli che la accettano.
hostnames
Para qué nombres vale esta route. Tienen que intersecar con el hostname del listener, o no recibe tráfico.
hostnames
Which names this route serves. They must intersect the listener's hostname, or it gets no traffic.
hostnames
Per quali nomi vale questa route. Devono intersecarsi con l'hostname del listener, altrimenti non riceve traffico.
matches.path.type: PathPrefix
Por segmentos, igual que el Prefix del Ingress — pero acá se llama distinto. Es el que vas a usar casi siempre.
matches.path.type: PathPrefix
By segments, just like the Ingress Prefix — but here it has a different name. The one you will use almost always.
matches.path.type: PathPrefix
Per segmenti, come il Prefix dell'Ingress — ma qui si chiama diversamente. È quello che userai quasi sempre.
matches.path.type: Exact
Literal, sin subpaths. Mismo significado que en Ingress.
matches.path.type: Exact
Literal, no subpaths. Same meaning as in Ingress.
matches.path.type: Exact
Letterale, senza subpath. Stesso significato che in Ingress.
matches.path.type: RegularExpression
Expresión regular. Es de soporte opcional en la spec: puede que tu implementación no lo acepte. PathPrefix y Exact son los obligatorios.
matches.path.type: RegularExpression
Regular expression. It is optional support in the spec: your implementation may not accept it. PathPrefix and Exact are the mandatory ones.
matches.path.type: RegularExpression
Espressione regolare. Ha supporto opzionale nella spec: la tua implementazione potrebbe non accettarlo. PathPrefix ed Exact sono obbligatori.
matches.method
Limita la regla a un verbo HTTP (GET, POST…). Con Ingress esto no existía: había que resolverlo con anotaciones.
matches.method
Limits the rule to one HTTP verb (GET, POST…). With Ingress this did not exist: you solved it with annotations.
matches.method
Limita la regola a un verbo HTTP (GET, POST…). Con Ingress non esisteva: si risolveva con annotation.
matches.headers
Matchea por cabecera, con type: Exact o RegularExpression. Es lo que permite un canary por header sin tocar el resto del tráfico.
matches.headers
Matches on a header, with type: Exact or RegularExpression. This is what enables a header-based canary without touching the rest of the traffic.
matches.headers
Corrisponde su un header, con type: Exact o RegularExpression. È ciò che permette un canary per header senza toccare il resto del traffico.
matches.queryParams
Lo mismo, pero sobre los parámetros de la query string.
matches.queryParams
The same, but on query string parameters.
matches.queryParams
Lo stesso, ma sui parametri della query string.
filters: RequestRedirect
Contesta un redirect (scheme, hostname, statusCode) en vez de reenviar. Por eso no puede convivir con backendRefs: la API rechaza esa combinación.
filters: RequestRedirect
Answers a redirect (scheme, hostname, statusCode) instead of forwarding. That is why it cannot coexist with backendRefs: the API rejects that combination.
filters: RequestRedirect
Risponde un redirect (scheme, hostname, statusCode) invece di inoltrare. Per questo non può convivere con backendRefs: l'API rifiuta quella combinazione.
filters: URLRewrite
Reescribe el path o el host antes de reenviar. ReplacePrefixMatch cambia el prefijo que matcheó — el equivalente del rewrite-target de nginx, pero en la spec.
filters: URLRewrite
Rewrites path or host before forwarding. ReplacePrefixMatch swaps the prefix that matched — the equivalent of nginx's rewrite-target, but in the spec.
filters: URLRewrite
Riscrive il path o l'host prima di inoltrare. ReplacePrefixMatch cambia il prefisso che ha corrisposto — l'equivalente del rewrite-target di nginx, ma nella spec.
filters: RequestHeaderModifier
Agrega, reemplaza o borra cabeceras del request (set, add, remove) antes de que llegue al backend.
filters: RequestHeaderModifier
Adds, replaces or removes request headers (set, add, remove) before it reaches the backend.
filters: RequestHeaderModifier
Aggiunge, sostituisce o rimuove header della richiesta (set, add, remove) prima che arrivi al backend.
backendRefs[].name / port
El Service destino y su puerto. Pueden ser varios en la misma regla.
backendRefs[].name / port
The target Service and its port. There can be several in the same rule.
backendRefs[].name / port
Il Service di destinazione e la sua porta. Possono essere più d'uno nella stessa regola.
backendRefs[].weight
Proporción, no porcentaje: 90 y 10 reparten 90%/10%, igual que 9 y 1. En 0 ese backend no recibe nada. Esto con Ingress exigía anotaciones propietarias.
backendRefs[].weight
Proportion, not percentage: 90 and 10 split 90%/10%, same as 9 and 1. At 0 that backend gets nothing. With Ingress this required proprietary annotations.
backendRefs[].weight
Proporzione, non percentuale: 90 e 10 dividono 90%/10%, come 9 e 1. A 0 quel backend non riceve nulla. Con Ingress serviva un'annotation proprietaria.
Constructor · Gateway + HTTPRoute, y si realmente se enganchan
Gateway · lo arma el admin
agregar un listener
HTTPRoute · la arma el dev
agregar una regla
7.4
Firewall interno · 20 min
Internal firewall · 20 min
Firewall interno · 20 min
NetworkPolicies
Por defecto todo pod habla con todo pod. Esto lo corta.
By default every pod talks to every pod. This cuts that.
Di default ogni pod parla con ogni pod. Questo lo taglia.
Práctica · De cero a aislado
Practice · From zero to isolated
Pratica · Da zero a isolato
Deny all: el punto de partida
Deny all: the starting point
Deny all: il punto di partenza
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
namespace: prod
spec:
podSelector: {} # {} = TODOS los pods del ns# {} = ALL pods in the ns# {} = TUTTI i pod del nspolicyTypes: [Ingress, Egress]
# Sin reglas → no se permite nada. Base de todo diseño.# No rules → nothing is allowed. The base of every design.# Nessuna regola → non è permesso nulla. La base di ogni design.
Permitir solo desde el frontend
Allow only from the frontend
Permettere solo dal frontend
spec:
podSelector:
matchLabels: {app: db} # A QUIÉN protege# WHO it protects# CHI proteggepolicyTypes: [Ingress]
ingress:
- from:
- podSelector:
matchLabels: {app: web}
ports:
- protocol: TCP
port: 5432
Desde otro namespace
From another namespace
Da un altro namespace
ingress:
- from:
- namespaceSelector:
matchLabels: {kubernetes.io/metadata.name: prod}
podSelector: # SIN guión: AND# NO dash: AND# SENZA trattino: ANDmatchLabels: {app: web}
# "pods app=web QUE ESTÉN en el ns prod"# "app=web pods THAT ARE IN the prod ns"# "pod app=web CHE STANNO nel ns prod"ingress:
- from:
- namespaceSelector: {matchLabels: {env: prod}}
- podSelector: {matchLabels: {app: web}} # CON guión: OR# WITH dash: OR# CON trattino: OR# "cualquier pod del ns prod, O cualquier pod app=web de ESTE ns"# "any pod in the prod ns, OR any app=web pod in THIS ns"# "qualsiasi pod del ns prod, O qualsiasi pod app=web di QUESTO ns"
k get netpol -n prod
k describe netpol default-deny -n prod
# Antes y después: el mismo curl# Before and after: the same curl# Prima e dopo: lo stesso curlk run t --rm-it-n prod --image=busybox:1.28 -- \
wget -qO---timeout=2 db:5432
⚠
Un deny-all de egress rompe el DNS y con eso rompe todo lo demás, porque los pods resuelven contra CoreDNS en kube-system. Si aplicaste egress y "no resuelve nada", es esto. Abrí el puerto 53 UDP y TCP.
An egress deny-all breaks DNS and with it everything else, because pods resolve against CoreDNS in kube-system. If you applied egress and "nothing resolves", this is it. Open port 53 on UDP and TCP.
Un deny-all di egress rompe il DNS e con esso tutto il resto, perché i pod risolvono contro CoreDNS in kube-system. Se hai applicato egress e "non risolve nulla", è questo. Apri la porta 53 in UDP e TCP.
Teoría · Cómo razonarlas
Theory · How to reason about them
Teoria · Come ragionarle
Las cuatro reglas de oro
The four golden rules
Le quattro regole d'oro
Sin ninguna policy: todo permitido. Kubernetes es abierto por defecto.
Apenas una policy selecciona un pod, ese pod pasa a estar aislado para los policyTypes declarados: se niega todo salvo lo que las policies permitan.
Son aditivas y solo permiten: no existe una regla "deny". Varias policies sobre el mismo pod se suman (unión de lo permitido).
Son namespaced: la policy vive en un namespace y su podSelector solo alcanza pods de ese namespace.
With no policy at all: everything is allowed. Kubernetes is open by default.
The moment one policy selects a pod, that pod becomes isolated for the declared policyTypes: everything is denied except what policies allow.
They are additive and only allow: there is no "deny" rule. Several policies on the same pod add up (union of what is allowed).
They are namespaced: the policy lives in a namespace and its podSelector reaches only pods in that namespace.
Senza alcuna policy: tutto permesso. Kubernetes è aperto di default.
Appena una policy seleziona un pod, quel pod diventa isolato per i policyTypes dichiarati: si nega tutto tranne ciò che le policy permettono.
Sono additive e permettono soltanto: non esiste una regola "deny". Più policy sullo stesso pod si sommano (unione di ciò che è permesso).
Sono namespaced: la policy vive in un namespace e il suo podSelector raggiunge solo i pod di quel namespace.
Los tres selectores del from/to
The three selectors in from/to
I tre selector di from/to
Selector
Selecciona
Selector
Selects
Selector
Seleziona
podSelector
Pods (del mismo ns, salvo que lo combines)
podSelector
Pods (in the same ns, unless combined)
podSelector
Pod (dello stesso ns, salvo combinazione)
namespaceSelector
Todos los pods de los ns que matcheen
namespaceSelector
All pods in the matching namespaces
namespaceSelector
Tutti i pod dei namespace corrispondenti
ipBlock
CIDRs — para tráfico externo al cluster
ipBlock
CIDRs — for traffic external to the cluster
ipBlock
CIDR — per traffico esterno al cluster
El guión que cambia el sentido
The dash that changes the meaning
Il trattino che cambia il senso
Dentro de un ítem de la lista from, varios selectores son AND. Cada guión abre un ítem nuevo, y entre ítems es OR. Es la trampa clásica del tema: un guión de más abre la puerta a un namespace entero.
Within one item of the from list, several selectors are AND. Each dash opens a new item, and between items it is OR. It is the classic trap here: one extra dash opens the door to an entire namespace.
Dentro un elemento della lista from, più selector sono in AND. Ogni trattino apre un nuovo elemento, e fra elementi è OR. È la trappola classica del tema: un trattino di troppo apre la porta a un intero namespace.
Es el CNI quien las aplica
The CNI is what enforces them
È il CNI ad applicarle
El objeto NetworkPolicy lo acepta la API siempre, pero solo tiene efecto si tu CNI lo soporta. Calico y Cilium sí; Flannel puro no. Si creás una policy y el tráfico pasa igual, sospechá del CNI antes que de tu YAML.
The API always accepts a NetworkPolicy object, but it only takes effect if your CNI supports it. Calico and Cilium do; plain Flannel does not. If you create a policy and traffic flows anyway, suspect the CNI before your YAML.
L'API accetta sempre un oggetto NetworkPolicy, ma ha effetto solo se il tuo CNI lo supporta. Calico e Cilium sì; Flannel puro no. Se crei una policy e il traffico passa lo stesso, sospetta del CNI prima che del tuo YAML.
Lo que las policies no ven
What policies do not see
Cosa le policy non vedono
Trabajan sobre IPs y puertos, no sobre Services: filtrás por la IP del pod destino, no por la ClusterIP. Y no aplican a tráfico del propio nodo hacia sus pods (por ejemplo, las probes del kubelet, que nunca se bloquean).
They work on IPs and ports, not Services: you filter by the destination pod's IP, not the ClusterIP. And they do not apply to traffic from a node to its own pods (for example the kubelet's probes, which are never blocked).
Lavorano su IP e porte, non sui Service: filtri per l'IP del pod di destinazione, non per il ClusterIP. E non si applicano al traffico da un nodo verso i propri pod (per esempio le probe del kubelet, che non vengono mai bloccate).
★
Receta de examen para "permití solo X→Y": (1) podSelector = el destino Y, nunca el origen; (2) policyTypes: [Ingress]; (3) from = el origen X; (4) ports = el puerto del container. Leé siempre la dirección del enunciado antes de escribir.
Exam recipe for "allow only X→Y": (1) podSelector = the destination Y, never the source; (2) policyTypes: [Ingress]; (3) from = the source X; (4) ports = the container's port. Always read the direction in the wording before writing.
Ricetta d'esame per "permetti solo X→Y": (1) podSelector = la destinazione Y, mai l'origine; (2) policyTypes: [Ingress]; (3) from = l'origine X; (4) ports = la porta del container. Leggi sempre la direzione nel testo prima di scrivere.
VisorExplorerVisore · quién llega al podwho reaches the podchi raggiunge il poddb
Compará AND y OR: el YAML cambia en un solo guión, y la superficie de acceso cambia entera.
Compare AND and OR: the YAML changes by a single dash, and the whole access surface changes.
Confronta AND e OR: lo YAML cambia di un solo trattino, e l'intera superficie di accesso cambia.
7.5
La base · 10 min
The foundation · 10 min
La base · 10 min
CNI: el plugin que hace posible todo lo anterior
CNI: the plugin that makes all the above possible
CNI: il plugin che rende possibile tutto quanto sopra
Poco que configurar, mucho que verificar cuando se rompe.
Little to configure, a lot to check when it breaks.
Poco da configurare, molto da verificare quando si rompe.
Práctica · Verificar
Practice · Verify
Pratica · Verificare
¿Quién es el CNI de este cluster?
Which CNI does this cluster use?
Qual è il CNI di questo cluster?
# Los pods del plugin corren como DaemonSet# The plugin's pods run as a DaemonSet# I pod del plugin girano come DaemonSetk get pods -n kube-system -o wide | grep -Ei'calico|flannel|cilium|weave'k get ds -A# La config, en cada nodo# The config, on each node# La config, su ogni nodo
ls /etc/cni/net.d/
cat /etc/cni/net.d/10-calico.conflist
ls /opt/cni/bin/ # los binarios# the binaries# i binari
El síntoma clásico de CNI ausente
The classic symptom of a missing CNI
Il sintomo classico di CNI assente
k get nodes
# NotReadyk describe node worker1
# KubeletNotReady: cni plugin not initializedk get pods -A# CoreDNS en Pending → siempre es el CNI# CoreDNS Pending → it is always the CNI# CoreDNS in Pending → è sempre il CNI
Comprobar la red plana
Checking the flat network
Verificare la rete piatta
# Un pod en cada nodo, y que se hablen# A pod on each node, and make them talk# Un pod su ogni nodo, e falli parlarek run p1 --image=nginx
k get pod p1 -o wide # anotá la IP# note the IP# annota l'IPk run p2 --rm-it--image=busybox:1.28 -- \
wget -qO---timeout=2 <IP-DE-P1>
★
Regla mnemotécnica: CoreDNS en Pending y nodos NotReady al mismo tiempo = CNI. Es el primer chequeo después de un kubeadm init y una de las causas más repetidas de cluster roto en los labs.
Mnemonic: CoreDNS Pending and nodes NotReady at the same time = CNI. It is the first check after a kubeadm init and one of the most repeated causes of a broken cluster in labs.
Mnemonica: CoreDNS in Pending e nodi NotReady insieme = CNI. È il primo controllo dopo un kubeadm init e una delle cause più ripetute di cluster rotto nei lab.
Teoría · Qué hace
Theory · What it does
Teoria · Cosa fa
El contrato
The contract
Il contratto
CNI (Container Network Interface) es un estándar, no un producto. Cuando el kubelet crea un pod, invoca al plugin y le pide: darle una IP, crear su interfaz de red y programar las rutas para que llegue a los demás pods. Al borrarlo, lo deshace. Kubernetes no trae implementación propia: por eso un cluster recién inicializado tiene los nodos NotReady hasta que instalás una.
CNI (Container Network Interface) is a standard, not a product. When the kubelet creates a pod, it invokes the plugin and asks it to: give it an IP, create its network interface and program the routes so it reaches the other pods. On deletion, it undoes that. Kubernetes ships no implementation of its own: that is why a freshly initialised cluster has NotReady nodes until you install one.
CNI (Container Network Interface) è uno standard, non un prodotto. Quando il kubelet crea un pod, invoca il plugin e gli chiede: dargli un IP, creare la sua interfaccia di rete e programmare le rotte perché raggiunga gli altri pod. Alla cancellazione, disfa tutto. Kubernetes non porta un'implementazione propria: per questo un cluster appena inizializzato ha i nodi NotReady finché non ne installi una.
Quién hace qué (ordenar esto vale oro)
Who does what (getting this straight is gold)
Chi fa cosa (mettere ordine qui vale oro)
Componente
Responsable de
Component
Responsible for
Componente
Responsabile di
CNI
IP del pod, red pod-a-pod, NetworkPolicy
CNI
Pod IP, pod-to-pod network, NetworkPolicy
CNI
IP del pod, rete pod-a-pod, NetworkPolicy
kube-proxy
Services: ClusterIP → pods (M6)
kube-proxy
Services: ClusterIP → pods (M6)
kube-proxy
Service: ClusterIP → pod (M6)
CoreDNS
Nombres → IPs (M6)
CoreDNS
Names → IPs (M6)
CoreDNS
Nomi → IP (M6)
Ingress controller
HTTP externo → Services
Ingress controller
External HTTP → Services
Ingress controller
HTTP esterno → Service
Las implementaciones que verás
The implementations you will meet
Le implementazioni che incontrerai
Calico — el de tu cluster. Ruteo L3, NetworkPolicy completa (y extendida).
Flannel — simple, overlay VXLAN, sin soporte de NetworkPolicy.
Cilium — eBPF, puede reemplazar a kube-proxy, policies L7.
Calico — yours. L3 routing, full (and extended) NetworkPolicy.
Flannel — simple, VXLAN overlay, no NetworkPolicy support.
Cilium — eBPF, can replace kube-proxy, L7 policies.
Calico — il tuo. Routing L3, NetworkPolicy completa (ed estesa).
Flannel — semplice, overlay VXLAN, senza supporto NetworkPolicy.
Cilium — eBPF, può sostituire kube-proxy, policy L7.
Para el examen
For the exam
Per l'esame
No te van a pedir instalar ni configurar un CNI a mano. Sí te pueden pedir diagnosticar que falta o está caído (M10) y saber que las NetworkPolicies dependen de él.
You will not be asked to install or configure a CNI by hand. You may well be asked to diagnose that one is missing or down (M10), and to know that NetworkPolicies depend on it.
Non ti chiederanno di installare o configurare un CNI a mano. Possono però chiederti di diagnosticare che manca o è caduto (M10), e di sapere che le NetworkPolicy dipendono da lui.
★
Cierre del módulo
Module wrap-up
Chiusura del modulo
Lo que te llevás del Módulo 7
What you take from Module 7
Cosa porti via dal Modulo 7
Resumen · Comandos clave
Summary · Key commands
Riassunto · Comandi chiave
# Ingressk create ingress web --rule="demo.io/*=web:80"k create ingress web --class=nginx --rule="demo.io/api*=api:8080"k get ingress,ingressclass
k describe ing web
# TLSk create secret tls demo-tls --cert=tls.crt --key=tls.key
# Gateway API (CRDs: a mano, pero verificá que estén)# Gateway API (CRDs: by hand, but check they exist)# Gateway API (CRD: a mano, ma verifica che ci siano)k get crd | grep gateway.networking
k get gatewayclass,gateway,httproute -Ak explain httproute.spec.rules --recursive # NetworkPolicyk get netpol -Ak describe netpol default-deny -n prod
# CNIk get pods -n kube-system -o wide
ls /etc/cni/net.d/
# Probar HTTP sin DNS# Test HTTP without DNS# Provare HTTP senza DNS
curl -H"Host: demo.io" http://<IP-NODO>:<NODEPORT>/api
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
El Ingress no hace nada solo: hace falta un controller instalado, y el tráfico entra por el Service de ese controller.
pathType es obligatorio y Prefix compara segmentos, no texto. Gana el path más largo.
El secret TLS va en el mismo namespace que el Ingress, tipo kubernetes.io/tls.
Gateway API parte Ingress en tres: GatewayClass (impl), Gateway (listener), HTTPRoute (reglas). Las dos puntas consienten: allowedRoutes + parentRefs.
NetworkPolicy: sin policy todo pasa; con una policy que te seleccione, solo pasa lo permitido. Son aditivas y nunca niegan explícitamente.
El guión en from decide AND vs OR. Y todo esto lo ejecuta el CNI: si no lo soporta, tu policy es decorativa.
Ingress does nothing on its own: you need an installed controller, and traffic enters through that controller's Service.
pathType is mandatory and Prefix compares segments, not text. The longest path wins.
The TLS secret goes in the same namespace as the Ingress, of type kubernetes.io/tls.
Gateway API splits Ingress into three: GatewayClass (impl), Gateway (listener), HTTPRoute (rules). Both ends consent: allowedRoutes + parentRefs.
NetworkPolicy: with no policy everything passes; with a policy selecting you, only what is allowed passes. They are additive and never deny explicitly.
The dash in from decides AND vs OR. And the CNI executes all of it: if it does not support policies, yours are decorative.
Ingress non fa nulla da solo: serve un controller installato, e il traffico entra dal Service di quel controller.
pathType è obbligatorio e Prefix confronta segmenti, non testo. Vince il path più lungo.
Il secret TLS va nello stesso namespace dell'Ingress, di tipo kubernetes.io/tls.
Gateway API divide Ingress in tre: GatewayClass (impl), Gateway (listener), HTTPRoute (regole). Entrambe le parti acconsentono: allowedRoutes + parentRefs.
NetworkPolicy: senza policy passa tutto; con una policy che ti seleziona, passa solo ciò che è permesso. Sono additive e non negano mai esplicitamente.
Il trattino in from decide AND contro OR. E tutto questo lo esegue il CNI: se non lo supporta, la tua policy è decorativa.
★
El hilo del módulo: Kubernetes separa siempre declaración de ejecución. Ingress declara y el controller ejecuta; NetworkPolicy declara y el CNI ejecuta. Por eso el diagnóstico es siempre el mismo: primero ¿el objeto está bien escrito?, después ¿hay alguien que lo esté ejecutando?
The thread of the module: Kubernetes always separates declaration from execution. Ingress declares and the controller executes; NetworkPolicy declares and the CNI executes. That is why the diagnosis is always the same: first, is the object written correctly? then, is anyone actually executing it?
Il filo del modulo: Kubernetes separa sempre la dichiarazione dall'esecuzione. Ingress dichiara e il controller esegue; NetworkPolicy dichiara e il CNI esegue. Per questo la diagnosi è sempre la stessa: prima, l'oggetto è scritto bene? poi, c'è qualcuno che lo sta eseguendo?
Checkpoint Módulo 7: Ingress (reglas, pathType, TLS), Gateway API (los tres objetos y la traducción desde Ingress), NetworkPolicies (default deny, AND vs OR, DNS en egress) y el rol del CNI. Dominio Services & Networking (20%) completo. Siguiente: Módulo 8 — Storage.
Module 7 checkpoint: Ingress (rules, pathType, TLS), Gateway API (the three objects and the translation from Ingress), NetworkPolicies (default deny, AND vs OR, DNS in egress) and the CNI's role. The Services & Networking domain (20%) is complete. Next: Module 8 — Storage.
Checkpoint Modulo 7: Ingress (regole, pathType, TLS), Gateway API (i tre oggetti e la traduzione da Ingress), NetworkPolicy (default deny, AND contro OR, DNS in egress) e il ruolo del CNI. Dominio Services & Networking (20%) completo. Prossimo: Modulo 8 — Storage.
★
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
Ingress y TLS, la traducción a Gateway API, y las policies que engañan.
Ingress and TLS, the Gateway API translation, and the policies that deceive.
Ingress e TLS, la traduzione a Gateway API, e le policy che ingannano.
0 / 8
🧠
Modelo mental. Dos ejes que no se mezclan: Ingress/Gateway enrutan (capa 7, hacia adentro) y NetworkPolicy prohibe (capa 3/4, adentro). Y en los dos casos, Kubernetes separa declaración de ejecución: el objeto siempre se crea; que haga algo depende de que haya un controller o un CNI que lo ejecute.
Mental model. Two axes that never mix: Ingress/Gateway route (layer 7, inward) and NetworkPolicy forbids (layer 3/4, inside). And in both cases Kubernetes separates declaration from execution: the object is always created; whether it does anything depends on a controller or a CNI executing it.
Modello mentale. Due assi che non si mescolano: Ingress/Gateway instradano (livello 7, verso l'interno) e NetworkPolicy proibisce (livello 3/4, dentro). E in entrambi i casi Kubernetes separa la dichiarazione dall'esecuzione: l'oggetto viene sempre creato; che faccia qualcosa dipende da un controller o da un CNI che lo esegua.
◆
Manifests publicados. Cada ejercicio tiene su YAML servido por este mismo sitio: k apply -f <url>/manifests/m7e1.yaml. Los E son la solución de referencia; los Tplantan el problema — aplicalos y diagnosticá sin leerlos. k delete -f <misma-url> limpia. E2 depende de E1, y E4/E5 del Gateway de E4.
Published manifests. Every exercise has its YAML served by this very site: k apply -f <url>/manifests/m7e1.yaml. The E ones are the reference solution; the T ones plant the problem — apply them and diagnose without reading them. k delete -f <same-url> cleans up. E2 depends on E1, and E4/E5 on E4's Gateway.
Manifest pubblicati. Ogni esercizio ha il suo YAML servito da questo stesso sito: k apply -f <url>/manifests/m7e1.yaml. Gli E sono la soluzione di riferimento; i Tpiantano il problema — applicali e diagnostica senza leggerli. k delete -f <stessa-url> pulisce. E2 dipende da E1, ed E4/E5 dal Gateway dell'E4.
◆
Preparación. Snapshot antes de todo. E1–E3 necesitan un ingress controller — pineá la versión, no uses main, que es una rama móvil: k apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.13.9/deploy/static/provider/baremetal/deploy.yaml El controller queda como NodePort: sacá los puertos con k -n ingress-nginx get svc ingress-nginx-controller. E4–E5 necesitan los CRDs de Gateway API: k apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.6.2/standard-install.yaml Ojo: los CRDs te dejan crear y validar los objetos, pero no enrutan tráfico — para eso hace falta además una implementación (nginx-gateway-fabric, Istio, Cilium). E6, T1 y T2 funcionan tal cual con Calico. Los ejercicios usan los namespaces ing (E1–E5) y prod/dev (E6, T1, T2); aplicá los de policies de a uno, borrando el anterior.
Setup. Snapshot before anything. E1–E3 need an ingress controller — pin the version, do not use main, which is a moving branch: k apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.13.9/deploy/static/provider/baremetal/deploy.yaml The controller comes up as a NodePort: get the ports with k -n ingress-nginx get svc ingress-nginx-controller. E4–E5 need the Gateway API CRDs: k apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.6.2/standard-install.yaml Careful: the CRDs let you create and validate the objects, but they do not route traffic — that also needs an implementation (nginx-gateway-fabric, Istio, Cilium). E6, T1 and T2 work as-is with Calico. The exercises use namespaces ing (E1–E5) and prod/dev (E6, T1, T2); apply the policy ones one at a time, deleting the previous.
Preparazione. Snapshot prima di tutto. E1–E3 richiedono un ingress controller — fissa la versione, non usare main, che è un ramo mobile: k apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.13.9/deploy/static/provider/baremetal/deploy.yaml Il controller esce come NodePort: prendi le porte con k -n ingress-nginx get svc ingress-nginx-controller. E4–E5 richiedono i CRD di Gateway API: k apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.6.2/standard-install.yaml Attenzione: i CRD ti permettono di creare e validare gli oggetti, ma non instradano traffico — per quello serve anche un'implementazione (nginx-gateway-fabric, Istio, Cilium). E6, T1 e T2 funzionano così come sono con Calico. Gli esercizi usano i namespace ing (E1–E5) e prod/dev (E6, T1, T2); applica quelli delle policy uno alla volta, cancellando il precedente.
E1
Un Ingress, dos backends
One Ingress, two backends
Un Ingress, due backend
~6 min
Tenés dos Deployments expuestos como Services: web:80 y api:8080. Creá un solo Ingress de clase nginx para el host demo.io que mande /api a api y todo lo demás a web. Probalo sin tocar el DNS.
You have two Deployments exposed as Services: web:80 and api:8080. Create a single Ingress of class nginx for the host demo.io sending /api to api and everything else to web. Test it without touching DNS.
Hai due Deployment esposti come Service: web:80 e api:8080. Crea un solo Ingress di classe nginx per l'host demo.io che mandi /api ad api e tutto il resto a web. Provalo senza toccare il DNS.
# http-echo en los dos: la salida es una palabra, y el E2 se puede leer# http-echo on both: the output is one word, so E2 stays readable# http-echo su entrambi: l'output è una parola, e l'E2 resta leggibilek create deploy web --image=hashicorp/http-echo -- -text=web -listen=:5678
k expose deploy web --port=80 --target-port=5678
k create deploy api --image=hashicorp/http-echo -- -text=api -listen=:8080
k expose deploy api --port=8080
# --rule se repite; el orden no importa (gana el path más largo)# --rule repeats; order does not matter (longest path wins)# --rule si ripete; l'ordine non conta (vince il path più lungo)k create ingress demo --class=nginx \
--rule="demo.io/api*=api:8080" \
--rule="demo.io/*=web:80"k get ing demo && k describe ing demo
# el NodePort del controller, y el Host a mano# the controller's NodePort, and the Host by hand# il NodePort del controller, e l'Host a manok-n ingress-nginx get svc ingress-nginx-controller
curl -H"Host: demo.io" http://<IP-NODO>:<NODEPORT>/api
curl -H"Host: demo.io" http://<IP-NODO>:<NODEPORT>/
Claves
Key points
Punti chiave
El * del --rule es lo que genera pathType: Prefix. Sin él, kubectl te pone Exact: mirá el YAML generado antes de aplicar.
Hay dos Services en el camino — el del controller y el de tu app. Cuando falla, verificá los dos.
El -H "Host:" te evita tocar /etc/hosts: el controller rutea por el header, no por DNS real.
The * in --rule is what produces pathType: Prefix. Without it, kubectl writes Exact: read the generated YAML before applying.
There are two Services on the path — the controller's and your app's. When it fails, check both.
-H "Host:" saves you editing /etc/hosts: the controller routes on the header, not on real DNS.
L'* in --rule è ciò che produce pathType: Prefix. Senza, kubectl scrive Exact: leggi lo YAML generato prima di applicare.
Ci sono due Service sul percorso — quello del controller e quello della tua app. Quando fallisce, controllali entrambi.
-H "Host:" ti evita di toccare /etc/hosts: il controller instrada sull'header, non sul DNS reale.
E2
pathType: el caso /apifoo
pathType: the /apifoo case
pathType: il caso /apifoo
~5 min
Sobre el Ingress del E1, predecí antes de probar a qué Service va cada request: /api, /api/v1/users, /apifoo, /. Después agregá una regla /salud con pathType: Exact y predecí /salud y /salud/x. Verificá todas con curl.
On E1's Ingress, predict before testing which Service each request goes to: /api, /api/v1/users, /apifoo, /. Then add a /salud rule with pathType: Exact and predict /salud and /salud/x. Verify them all with curl.
Sull'Ingress dell'E1, prevedi prima di provare a quale Service va ogni richiesta: /api, /api/v1/users, /apifoo, /. Poi aggiungi una regola /salud con pathType: Exact e prevedi /salud e /salud/x. Verificale tutte con curl.
/api → api # Prefix cubre también el path exacto# Prefix also covers the exact path# Prefix copre anche il path esatto
/api/v1/users → api # segmentos: /api + resto# segments: /api + rest# segmenti: /api + resto
/apifoo → web # "apifoo" es OTRO segmento, no /api# "apifoo" is ANOTHER segment, not /api# "apifoo" è UN ALTRO segmento, non /api
/ → web
/salud → salud # Exact matchea justo esto# Exact matches exactly this# Exact corrisponde esattamente a questo
/salud/x → web # Exact NO cubre subpaths# Exact does NOT cover subpaths# Exact NON copre i subpath# primero el backend, o la regla apunta a un Service que no existe# the backend first, or the rule points at a Service that does not exist# prima il backend, o la regola punta a un Service inesistentek create deploy salud --image=hashicorp/http-echo -- -text=salud -listen=:5678
k expose deploy salud --port=80 --target-port=5678
k edit ing demo # agregar la regla /salud con pathType: Exact# add the /salud rule with pathType: Exact# aggiungi la regola /salud con pathType: Exact
for p in /api /api/v1/users /apifoo / /salud /salud/x; do
echo -n"$p -> "; curl -s-H"Host: demo.io" http://<IP>:<NP>$p
done
Claves
Key points
Punti chiave
Prefix compara segmentos, no texto. Es el detalle que hace fallar este tema.
Gana el path más largo, no el que escribiste primero. El orden en el YAML es irrelevante.
Exact no cubre subpaths. Usalo solo cuando el enunciado diga literalmente "solo esa ruta".
Prefix compares segments, not text. It is the detail that fails this topic.
The longest path wins, not the one you wrote first. Order in the YAML is irrelevant.
Exact does not cover subpaths. Use it only when the wording literally says "only that route".
Prefix confronta segmenti, non testo. È il dettaglio che fa fallire questo tema.
Vince il path più lungo, non quello scritto per primo. L'ordine nello YAML è irrilevante.
Exact non copre i subpath. Usalo solo quando il testo dice letteralmente "solo quella rotta".
E3
TLS en el Ingress
TLS on the Ingress
TLS sull'Ingress
~6 min
Serví demo.io por HTTPS con un certificado auto-firmado. Creá el Secret, referencialo en el Ingress y verificá con curl -k que el certificado servido es el tuyo (mirá el CN). Extra: creá el Secret en otro namespace a propósito y observá qué certificado sirve el controller.
Serve demo.io over HTTPS with a self-signed certificate. Create the Secret, reference it in the Ingress and verify with curl -k that the served certificate is yours (check the CN). Extra: create the Secret in another namespace on purpose and observe which certificate the controller serves.
Servi demo.io in HTTPS con un certificato autofirmato. Crea il Secret, referenzialo nell'Ingress e verifica con curl -k che il certificato servito sia il tuo (guarda il CN). Extra: crea il Secret in un altro namespace di proposito e osserva quale certificato serve il controller.
openssl req -x509-newkey rsa:2048 -nodes-days 365 \
-keyout tls.key -out tls.crt -subj"/CN=demo.io"k create secret tls demo-tls --cert=tls.crt --key=tls.key
k get secret demo-tls -o jsonpath='{.type}'# kubernetes.io/tlsk edit ing demo
# spec.tls: [{hosts: [demo.io], secretName: demo-tls}]# spec.tls: [{hosts: [demo.io], secretName: demo-tls}]# spec.tls: [{hosts: [demo.io], secretName: demo-tls}]
curl -kv--resolve demo.io:<HTTPS-NP>:<IP> https://demo.io:<HTTPS-NP>/ 2>&1 | grep -i subject
# CN=demo.io → sirve el tuyo# CN=demo.io → yours is being served# CN=demo.io → serve il tuo# CN=Kubernetes Ingress Controller Fake Certificate → el secret no lo encontró# CN=Kubernetes Ingress Controller Fake Certificate → it did not find the secret# CN=Kubernetes Ingress Controller Fake Certificate → non ha trovato il secret
Claves
Key points
Punti chiave
El Secret va en el mismo namespace que el Ingress. Si no, el controller cae en su certificado falso: el síntoma es "anda pero el navegador se queja de otro CN", no un error.
El tipo tiene que ser kubernetes.io/tls, con las claves tls.crt y tls.key. create secret tls te lo garantiza; un generic no.
El TLS termina en el controller: de ahí al Service el tráfico va en claro dentro del cluster.
The Secret goes in the same namespace as the Ingress. Otherwise the controller falls back to its fake certificate: the symptom is "it works but the browser complains about another CN", not an error.
The type must be kubernetes.io/tls, with the keys tls.crt and tls.key. create secret tls guarantees that; a generic does not.
TLS terminates at the controller: from there to the Service the traffic is in the clear inside the cluster.
Il Secret va nello stesso namespace dell'Ingress. Altrimenti il controller ripiega sul suo certificato finto: il sintomo è "funziona ma il browser si lamenta di un altro CN", non un errore.
Il tipo deve essere kubernetes.io/tls, con le chiavi tls.crt e tls.key. create secret tls te lo garantisce; un generic no.
Il TLS termina al controller: da lì al Service il traffico è in chiaro dentro il cluster.
E4
Traducir el Ingress a HTTPRoute
Translate the Ingress into an HTTPRoute
Tradurre l'Ingress in HTTPRoute
~8 min
Es el ejercicio que más probable te tomen. Tomá el Ingress del E1 y escribí la HTTPRoute equivalente contra un Gateway prod-gw que vive en el namespace infra. Sin kubectl create: a mano, apoyándote en k explain. Después listá qué se te fue en la traducción (qué campo de Ingress no tiene lugar en la HTTPRoute, y dónde está ahora).
The most likely exam ask. Take E1's Ingress and write the equivalent HTTPRoute against a Gateway prod-gw living in the infra namespace. No kubectl create: by hand, leaning on k explain. Then list what was lost in translation (which Ingress field has no place in the HTTPRoute, and where it lives now).
L'esercizio più probabile all'esame. Prendi l'Ingress dell'E1 e scrivi l'HTTPRoute equivalente su un Gateway prod-gw che vive nel namespace infra. Senza kubectl create: a mano, appoggiandoti a k explain. Poi elenca cosa si è perso nella traduzione (quale campo dell'Ingress non ha posto nell'HTTPRoute, e dove sta ora).
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: demo-route
spec:
parentRefs:
- name: prod-gw
namespace: infra
hostnames: ["demo.io"]
rules:
- matches:
- path: {type: PathPrefix, value: /api}
backendRefs:
- {name: api, port: 8080}
- matches:
- path: {type: PathPrefix, value: /}
backendRefs:
- {name: web, port: 80}
# verificar que se enganchó al Gateway# check it attached to the Gateway# verificare che si sia agganciata al Gatewayk describe httproute demo-route
# CON implementación instalada → status.parents: Accepted=True# WITH an implementation installed → status.parents: Accepted=True# CON un'implementazione installata → status.parents: Accepted=True# con SOLO los CRDs → status.parents VACÍO, y el Gateway PROGRAMMED=Unknown# with ONLY the CRDs → status.parents EMPTY, and the Gateway PROGRAMMED=Unknown# con i SOLI CRD → status.parents VUOTO, e il Gateway PROGRAMMED=Unknown# Nadie escribe el status si no hay controller. El YAML igual es correcto.# Nobody writes the status without a controller. The YAML is still correct.# Nessuno scrive lo status senza controller. Lo YAML è comunque corretto.
Claves
Key points
Punti chiave
El diccionario: ingressClassName→ nada (está en el Gateway) · host→hostnames (lista) · pathType: Prefix→type: PathPrefix · backend.service→backendRefs (lista, con pesos).
Lo que se fue: el listener y el TLS. En Ingress el puerto y el certificado estaban en el mismo objeto; en Gateway API viven en el Gateway, que es del admin. Esa es justamente la separación de roles.
Las dos puntas consienten: el Gateway con allowedRoutes, la ruta con parentRefs. Si Accepted=False, mirá esos dos campos antes que nada.
Sin comando imperativo, la doc es tu herramienta. k explain httproute.spec.rules --recursive funciona offline y te da la estructura entera.
Los CRDs te dan los objetos, no el ruteo. Instalar Gateway API te deja crear y validar Gateways y HTTPRoutes — que es lo que pide el examen — pero nada mueve tráfico hasta que instales una implementación (nginx-gateway-fabric, Istio, Cilium). Con solo CRDs el status queda en blanco: no es un error tuyo.
The dictionary: ingressClassName→ nothing (it is on the Gateway) · host→hostnames (a list) · pathType: Prefix→type: PathPrefix · backend.service→backendRefs (a list, with weights).
What was lost: the listener and the TLS. In Ingress the port and the certificate lived in the same object; in Gateway API they live on the Gateway, which belongs to the admin. That is exactly the role separation.
Both ends consent: the Gateway via allowedRoutes, the route via parentRefs. If Accepted=False, look at those two fields before anything else.
With no imperative command, the docs are your tool. k explain httproute.spec.rules --recursive works offline and gives you the whole structure.
The CRDs give you the objects, not the routing. Installing Gateway API lets you create and validate Gateways and HTTPRoutes — which is what the exam asks — but nothing moves traffic until you install an implementation (nginx-gateway-fabric, Istio, Cilium). With CRDs alone the status stays blank: that is not your mistake.
Il dizionario: ingressClassName→ nulla (sta sul Gateway) · host→hostnames (lista) · pathType: Prefix→type: PathPrefix · backend.service→backendRefs (lista, con pesi).
Cosa si è perso: il listener e il TLS. In Ingress la porta e il certificato stavano nello stesso oggetto; in Gateway API vivono sul Gateway, che è dell'admin. È esattamente la separazione dei ruoli.
Entrambe le parti acconsentono: il Gateway con allowedRoutes, la route con parentRefs. Se Accepted=False, guarda quei due campi prima di tutto.
Senza comando imperativo, la documentazione è il tuo strumento. k explain httproute.spec.rules --recursive funziona offline e ti dà l'intera struttura.
I CRD ti danno gli oggetti, non l'instradamento. Installare Gateway API ti permette di creare e validare Gateway e HTTPRoute — che è ciò che chiede l'esame — ma nulla muove traffico finché non installi un'implementazione (nginx-gateway-fabric, Istio, Cilium). Coi soli CRD lo status resta vuoto: non è un tuo errore.
E5
Canary con HTTPRoute (90/10)
Canary with HTTPRoute (90/10)
Canary con HTTPRoute (90/10)
~6 min
Con dos Services web-v1 y web-v2 (que devuelvan textos distintos), hacé que demo.io/ mande el 90% del tráfico a v1 y el 10% a v2. Verificalo con 20 requests seguidos y contá. Después movelo a 50/50 sin recrear la ruta.
With two Services web-v1 and web-v2 (returning different text), make demo.io/ send 90% of traffic to v1 and 10% to v2. Verify with 20 requests in a row and count. Then move it to 50/50 without recreating the route.
Con due Service web-v1 e web-v2 (che restituiscano testi diversi), fai in modo che demo.io/ mandi il 90% del traffico a v1 e il 10% a v2. Verifica con 20 richieste di fila e conta. Poi passa a 50/50 senza ricreare la route.
rules:
- matches:
- path: {type: PathPrefix, value: /}
backendRefs:
- {name: web-v1, port: 80, weight: 90}
- {name: web-v2, port: 80, weight: 10}
# contar la distribución# count the distribution# contare la distribuzione
for i in $(seq 20); do curl -s-H"Host: demo.io" http://<IP>:<NP>/; done | sort | uniq -ck edit httproute demo-route # weight: 50 y 50# weight: 50 and 50# weight: 50 e 50
Claves
Key points
Punti chiave
Esto es lo que Ingress no podía hacer sin anotaciones propietarias. Es el argumento más concreto de por qué existe Gateway API: lo que antes era específico de nginx ahora es un campo de la spec.
Los weight son proporciones relativas, no porcentajes: 9 y 1 dan lo mismo que 90 y 10.
Con 20 requests la muestra es chica: no esperes exactamente 18/2. La proporción se ve en el orden de magnitud.
Contar requests solo funciona con una implementación de Gateway API instalada. Con los CRDs pelados la ruta se crea pero no reparte nada: quedate con escribir bien el YAML, que es lo que se puntúa.
This is what Ingress could not do without proprietary annotations. It is the most concrete argument for Gateway API: what used to be nginx-specific is now a spec field.
weight values are relative proportions, not percentages: 9 and 1 give the same as 90 and 10.
With 20 requests the sample is small: do not expect exactly 18/2. The proportion shows in the order of magnitude.
Counting requests only works with a Gateway API implementation installed. With bare CRDs the route is created but splits nothing: settle for writing the YAML correctly, which is what scores.
Questo è ciò che Ingress non poteva fare senza annotazioni proprietarie. È l'argomento più concreto per Gateway API: ciò che era specifico di nginx ora è un campo della spec.
I weight sono proporzioni relative, non percentuali: 9 e 1 danno lo stesso di 90 e 10.
Con 20 richieste il campione è piccolo: non aspettarti esattamente 18/2. La proporzione si vede nell'ordine di grandezza.
Contare le richieste funziona solo con un'implementazione di Gateway API installata. Coi soli CRD la route si crea ma non distribuisce nulla: accontentati di scrivere bene lo YAML, che è ciò che dà punti.
E6
Default deny y la excepción justa
Default deny and the exact exception
Default deny e l'eccezione precisa
~8 min
En el namespace prod hay tres pods: web (app=web), cache (app=cache) y db (app=db, escucha en 5432). Verificá primero que todos llegan a db. Después hacé que solo web pueda hablarle a db en el 5432, y nadie más. Volvé a verificar los tres.
In namespace prod there are three pods: web (app=web), cache (app=cache) and db (app=db, listening on 5432). First verify that all reach db. Then make it so only web can talk to db on 5432, and nobody else. Re-verify all three.
Nel namespace prod ci sono tre pod: web (app=web), cache (app=cache) e db (app=db, in ascolto su 5432). Verifica prima che tutti raggiungano db. Poi fai in modo che solo web possa parlare a db sulla 5432, e nessun altro. Riverifica tutti e tre.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata: {name: db-solo-web, namespace: prod}
spec:
podSelector:
matchLabels: {app: db} # el DESTINO, nunca el origen# the DESTINATION, never the source# la DESTINAZIONE, mai l'originepolicyTypes: [Ingress]
ingress:
- from:
- podSelector:
matchLabels: {app: web}
ports:
- {protocol: TCP, port: 5432}
# verificar desde cada origen (el mismo comando, distinto pod)# verify from each source (same command, different pod)# verificare da ogni origine (stesso comando, pod diverso)k exec -n prod web -- nc -zvw2 db 5432 # openk exec -n prod cache -- nc -zvw2 db 5432 # timeout# timeout# timeout
Claves
Key points
Punti chiave
El podSelector de arriba es el destino, no el origen. Es el error de dirección más común: leé el enunciado y preguntate "¿a quién estoy protegiendo?".
No hace falta un deny-all aparte: esta policy ya aísla a db por el solo hecho de seleccionarlo. El deny-all explícito se usa cuando querés cerrar un namespace entero de una.
El port es el del container, no el del Service. Las policies trabajan sobre IPs de pod.
Verificá con TCP crudo (nc), no con curl a un puerto que no habla HTTP: el error te confundiría.
The top-level podSelector is the destination, not the source. It is the most common direction mistake: read the wording and ask "who am I protecting?".
You do not need a separate deny-all: this policy already isolates db simply by selecting it. An explicit deny-all is for closing a whole namespace at once.
The port is the container's, not the Service's. Policies work on pod IPs.
Verify with raw TCP (nc), not curl against a port that does not speak HTTP: the error would mislead you.
Il podSelector in alto è la destinazione, non l'origine. È l'errore di direzione più comune: leggi il testo e chiediti "chi sto proteggendo?".
Non serve un deny-all separato: questa policy isola già db per il solo fatto di selezionarlo. Il deny-all esplicito serve a chiudere un intero namespace in un colpo.
La port è quella del container, non del Service. Le policy lavorano sugli IP dei pod.
Verifica con TCP grezzo (nc), non con curl su una porta che non parla HTTP: l'errore ti confonderebbe.
T1
Troubleshooting — el guión de más
Troubleshooting — the extra dash
Troubleshooting — il trattino di troppo
~7 min
Una policy debía permitir a db (ns prod) recibir solo de los pods app=webdel namespace dev. Pero desde dev le llega cualquier pod, y encima le llega un web de prod. Encontrá el carácter culpable y arreglalo.
A policy was meant to let db (ns prod) receive only from app=web pods in the dev namespace. But any pod from dev gets through, and on top of that a web from prod does too. Find the guilty character and fix it.
Una policy doveva permettere a db (ns prod) di ricevere solo dai pod app=webdel namespace dev. Ma da dev arriva qualsiasi pod, e per giunta arriva anche un web di prod. Trova il carattere colpevole e sistemalo.
manifest · plantar el problemamanifest · plant the problemmanifest · piantare il problema
Ver soluciónShow solutionMostra soluzione
# MAL — dos ítems de lista: OR# WRONG — two list items: OR# SBAGLIATO — due elementi di lista: ORingress:
- from:
- namespaceSelector:
matchLabels: {kubernetes.io/metadata.name: dev}
- podSelector: # ← el guiónmatchLabels: {app: web}
# BIEN — un solo ítem con dos selectores: AND# RIGHT — a single item with two selectors: AND# GIUSTO — un solo elemento con due selector: ANDingress:
- from:
- namespaceSelector:
matchLabels: {kubernetes.io/metadata.name: dev}
podSelector: # ← sin guiónmatchLabels: {app: web}
Claves
Key points
Punti chiave
Un guión = un ítem nuevo = OR. Selectores dentro del mismo ítem = AND. Es la trampa número uno del tema y un cambio de un solo carácter.
El segundo síntoma delata el resto: un podSelector suelto (sin namespaceSelector al lado) se refiere al namespace de la policy. Por eso entraba también el web de prod.
Verificá siempre desde varios orígenes, no solo desde el que querías permitir: un OR de más solo se nota probando lo que no debería pasar.
One dash = one new item = OR. Selectors within the same item = AND. It is the number-one trap here, and a one-character change.
The second symptom gives away the rest: a bare podSelector (with no namespaceSelector beside it) refers to the policy's namespace. That is why prod's web got in too.
Always verify from several sources, not just the one you meant to allow: an extra OR only shows up by testing what should not pass.
Un trattino = un nuovo elemento = OR. Selector dentro lo stesso elemento = AND. È la trappola numero uno del tema, e una modifica di un solo carattere.
Il secondo sintomo svela il resto: un podSelector isolato (senza namespaceSelector accanto) si riferisce al namespace della policy. Per questo entrava anche il web di prod.
Verifica sempre da più origini, non solo da quella che volevi permettere: un OR di troppo si nota solo provando ciò che non dovrebbe passare.
T2
Troubleshooting — el egress que mató el DNS
Troubleshooting — the egress that killed DNS
Troubleshooting — l'egress che ha ucciso il DNS
~7 min
Aplicaste un default-deny de [Ingress, Egress] en prod y después una regla de egress que permite hablarle a db. Aun así, los pods de prod no llegan a db: bad address 'db'. Diagnosticá y arreglá.
You applied a default-deny with [Ingress, Egress] in prod, then an egress rule allowing traffic to db. Still, prod pods cannot reach db: bad address 'db'. Diagnose and fix.
Hai applicato un default-deny con [Ingress, Egress] in prod, poi una regola di egress che permette il traffico verso db. Eppure i pod di prod non raggiungono db: bad address 'db'. Diagnostica e sistema.
manifest · plantar el problemamanifest · plant the problemmanifest · piantare il problema
Ver soluciónShow solutionMostra soluzione
# la pista está en el mensaje: no es "connection refused", es "bad address"# the clue is in the message: it is not "connection refused", it is "bad address"# l'indizio è nel messaggio: non è "connection refused", è "bad address"# → falla la RESOLUCIÓN, no la conexión. El egress bloqueó el DNS.# → RESOLUTION fails, not the connection. Egress blocked DNS.# → fallisce la RISOLUZIONE, non la connessione. L'egress ha bloccato il DNS.k exec -n prod web -- nc -zvw2 <IP-DEL-POD-DB> 5432 # por IP SÍ anda# by IP it DOES work# per IP funziona# agregar la salida al DNS: UDP y TCP# add the DNS egress: UDP and TCP# aggiungere l'egress verso il DNS: UDP e TCPegress:
- to:
- namespaceSelector:
matchLabels: {kubernetes.io/metadata.name: kube-system}
ports:
- {protocol: UDP, port: 53}
- {protocol: TCP, port: 53}
k exec -n prod web -- nc -zvw2 db 5432 # open
Claves
Key points
Punti chiave
Un deny-all de egress rompe el DNS y con eso rompe todo. Es la consecuencia menos intuitiva del tema, y la que más tiempo hace perder.
El mismo truco de M6: "por IP sí, por nombre no" = DNS. Ese contraste te ahorra media hora.
Abrí el 53 en UDP y TCP: las respuestas grandes se reintentan por TCP, así que con solo UDP funciona a veces — el peor tipo de bug.
Regla práctica: si ponés Egress en policyTypes, escribí la regla del DNS en el mismo momento. No es un extra, es parte del default-deny.
An egress deny-all breaks DNS and with it everything. It is the least intuitive consequence here, and the one that costs the most time.
The same trick as M6: "by IP yes, by name no" = DNS. That contrast saves you half an hour.
Open 53 on UDP and TCP: large answers retry over TCP, so UDP alone works sometimes — the worst kind of bug.
Rule of thumb: if you put Egress in policyTypes, write the DNS rule at the same moment. It is not an extra, it is part of the default-deny.
Un deny-all di egress rompe il DNS e con esso tutto. È la conseguenza meno intuitiva del tema, e quella che fa perdere più tempo.
Lo stesso trucco del M6: "per IP sì, per nome no" = DNS. Quel contrasto ti risparmia mezz'ora.
Apri la 53 in UDP e TCP: le risposte grandi si ritentano via TCP, quindi con il solo UDP funziona a volte — il peggior tipo di bug.
Regola pratica: se metti Egress nei policyTypes, scrivi la regola del DNS nello stesso momento. Non è un extra, è parte del default-deny.
Autoevaluación — antes de marcar M7 como ★ dominado
Self-check — before marking M7 as ★ mastered
Autovalutazione — prima di segnare M7 come ★ padroneggiato
Crear un Ingress de dos reglas imperativamente, en menos de 1 min.
Predecir el matcheo de Prefix y Exact sin probar, incluido /apifoo.
Montar TLS y saber en qué namespace va el secret y de qué tipo.
Escribir una HTTPRoute de memoria y decir qué campo del Ingress ya no le corresponde.
Hacer un split de tráfico con pesos.
Escribir "solo X puede hablarle a Y en el puerto P" sin dudar de la dirección.
Distinguir AND de OR en un from mirando la indentación.
Reconocer al instante que un egress sin regla de DNS es lo que rompió todo.
Create a two-rule Ingress imperatively, in under 1 min.
Predict Prefix and Exact matching without testing, /apifoo included.
Set up TLS and know which namespace the secret goes in and of what type.
Write an HTTPRoute from memory and say which Ingress field no longer belongs to it.
Do a weighted traffic split.
Write "only X may talk to Y on port P" without hesitating on the direction.
Tell AND from OR in a from block by looking at the indentation.
Instantly recognise that an egress with no DNS rule is what broke everything.
Creare un Ingress di due regole in modo imperativo, in meno di 1 min.
Prevedere la corrispondenza di Prefix ed Exact senza provare, /apifoo incluso.
Configurare il TLS e sapere in quale namespace va il secret e di che tipo.
Scrivere un HTTPRoute a memoria e dire quale campo dell'Ingress non gli appartiene più.
Fare uno split di traffico con i pesi.
Scrivere "solo X può parlare a Y sulla porta P" senza esitare sulla direzione.
Distinguere AND da OR in un blocco from guardando l'indentazione.
Riconoscere all'istante che un egress senza regola DNS è ciò che ha rotto tutto.
Módulo 7 completado · Services & Networking, parte 2 de 2 · Siguiente: Storage — volumes, PV/PVC y StorageClasses
Module 7 complete · Services & Networking, part 2 of 2 · Next: Storage — volumes, PV/PVC and StorageClasses
Modulo 7 completato · Services & Networking, parte 2 di 2 · Prossimo: Storage — volume, PV/PVC e StorageClass