A la lliçó anterior vam desmuntar la ficció del ClusterIP: una adreça que no existeix en cap interfície i que només viu com a regles d'iptables programades per kube-proxy. Però aquell descobriment deixa intacte el problema que arrosseguem des del final del mòdul 3: un ClusterIP només és accessible des de dins del clúster. Un client que vol comprar un bitllet a www.rutasnorte.example no té cap manera d'arribar a botiga-web. Aquesta lliçó recorre els quatre tipus de Service —ClusterIP, NodePort, LoadBalancer i ExternalName— més dues variants que no són tipus però es comporten com si ho fossin: els serveis headless i els serveis sense selector. En acabar sabràs exactament quin fer servir en cada situació, per què LoadBalancer no és la solució per publicar la plataforma, i com donar un nom intern del clúster a la passarel·la de pagaments externa.
Contingut
- Panorama: sis maneres de declarar un Service
- Com cada tipus es construeix sobre l'anterior
NodePorten detallLoadBalanceri el seu costexternalTrafficPolicy:Clusterdavant deLocalExternalName: la passarel·la de pagaments- Serveis sense selector: endpoints a mà
- Serveis headless
sessionAffinity, ports amb nom i multiport- Què fa servir Rutas Norte i per què
- Panorama: sis maneres de declarar un Service
Abans d'entrar en detall, la taula que convé tenir al davant durant tota la lliçó.
| Forma | spec clau |
Abast | Qui l'implementa | Quan fer-lo servir |
|---|---|---|---|---|
| ClusterIP | type: ClusterIP (per defecte) |
Només dins del clúster | kube-proxy | Comunicació entre components. El 90 % dels casos |
| NodePort | type: NodePort |
IP de qualsevol node, port 30000-32767 | kube-proxy | Proves, laboratori, o com a fonament d'un balancejador extern |
| LoadBalancer | type: LoadBalancer |
IP pública/externa | Un controlador del proveïdor de núvol | Exposar un servei TCP/UDP a l'exterior al núvol |
| ExternalName | type: ExternalName + externalName |
Redirecció de nom DNS | CoreDNS (registre CNAME) | Donar un nom intern a un servei de fora |
| Headless | clusterIP: None |
Només DNS, sense IP virtual | CoreDNS (una A per pod) | StatefulSets, clients que balancegen sols |
| Sense selector | Sense selector, amb EndpointSlice manual |
Igual que el seu tipus | Tu, a mà | Servei extern amb IP fixes, migracions |
Les dues últimes files no són valors de type: són modificacions que s'hi combinen. Un Service pot ser ClusterIP i headless, o ClusterIP i sense selector.
- Com cada tipus es construeix sobre l'anterior
Els tres primers tipus no són alternatives: són capes acumulatives. Un NodePort continua tenint el seu ClusterIP i continua funcionant des de dins. Un LoadBalancer continua tenint el seu NodePort.
flowchart TB
subgraph LB["type: LoadBalancer"]
subgraph NP["type: NodePort"]
subgraph CIP["type: ClusterIP"]
A["IP virtual interna<br/>10.96.x.x:port<br/>regles de kube-proxy"]
end
B["A mes: port 30000-32767<br/>obert a TOTS els nodes"]
end
C["A mes: IP externa aprovisionada<br/>pel proveidor, que apunta<br/>als NodePorts dels nodes"]
end
Comprova-ho amb la sortida de kubectl:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
api-reserves ClusterIP 10.96.201.14 <none> 3000/TCP 9d
botiga-web NodePort 10.96.88.7 <none> 80:31080/TCP 4m
demo-lb LoadBalancer 10.96.44.190 10.0.0.51 80:32410/TCP 2mFixa't en la columna PORT(S): 80:31080/TCP significa "port 80 del Service, publicat també al 31080 de cada node". I tots tres tenen CLUSTER-IP, inclòs el LoadBalancer. Aquesta acumulació és la raó que el diagnòstic es faci sempre de dins cap a fora: si el ClusterIP no funciona, el NodePort tampoc no ho farà.
NodePort en detall
NodePort en detallUn NodePort obre el mateix port a tots els nodes del clúster, independentment d'on siguin els pods. Si truques a aquell port en un node que no allotja cap rèplica, kube-proxy reenvia el trànsit al node que sí que la té.
# k8s/entorns/dev/botiga-web-service-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
name: botiga-web
namespace: rutas-norte-dev
labels:
app: botiga-web
app.kubernetes.io/part-of: rutas-norte
entorn: dev
spec:
type: NodePort
selector: # recorda: nomes app i entorn als selectors
app: botiga-web
entorn: dev
ports:
- name: http
port: 80 # port del ClusterIP
targetPort: 8080 # port del contenidor nginx
nodePort: 31080 # OPCIONAL: si s'omet, l'assigna el clusterPunts que cal tenir clars:
- El rang per defecte és 30000-32767 (uns 2.700 ports). Es pot canviar amb
--service-node-port-rangea l'apiserver, però és una decisió del clúster, no de l'equip d'aplicació. - Si omets
nodePort, Kubernetes en tria un de lliure. És el recomanable: fixar-lo introdueix un conflicte potencial entre equips i unInvalid value: provided port is already allocatedquan algú s'avança. - El port s'obre a tots els nodes, encara que només un tingui pods. Amb
externalTrafficPolicy: Localaixò canvia (apartat 5). - Prova a minikube:
Per què no es fa servir en producció
| Problema | Conseqüència |
|---|---|
| Ports lletjos i arbitraris | Ningú no escriurà http://rutasnorte.example:31080 al navegador |
| Sense nom de domini ni TLS | Caldria resoldre l'HTTPS per fora |
| Sense alta disponibilitat | Apuntes a la IP d'un node; si aquell node cau, el servei deixa de respondre encara que el pod visqui |
| Requereix obrir el tallafocs | 2.700 ports potencialment accessibles a tots els nodes |
| No agrupa serveis | Un port per Service, sense encaminament per host ni per ruta |
L'ús legítim de NodePort és com a fonament: els balancejadors dels núvols i molts controladors d'Ingress s'hi recolzen precisament. Per a desenvolupament i demostracions ràpides, és perfecte.
LoadBalancer i el seu cost
LoadBalancer i el seu costtype: LoadBalancer diu al clúster: "demana al proveïdor d'infraestructura un balancejador extern que apunti a aquest servei". Kubernetes no el materialitza: ho fa un controlador que forma part del cloud-controller-manager del núvol, o un complement com MetalLB en instal·lacions pròpies.
apiVersion: v1
kind: Service
metadata:
name: botiga-web
namespace: rutas-norte-pro
spec:
type: LoadBalancer
selector:
app: botiga-web
entorn: pro
ports:
- name: http
port: 80
targetPort: 8080En un clúster sense proveïdor de núvol, el resultat és aquest:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
botiga-web LoadBalancer 10.96.44.190 <pending> 80:32410/TCP 5mAquest <pending> etern és una de les preguntes més repetides per qui comença. No és una fallada: és que ningú no ha recollit la petició. L'objecte està ben creat, però no existeix cap controlador capaç d'aprovisionar una IP externa. A minikube es resol amb:
# En un altre terminal; demana contrasenya d'administrador i cal deixar-lo obert
minikube -p rutas-norte tunnelNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
botiga-web LoadBalancer 10.96.44.190 10.96.44.190 80:32410/TCPminikube tunnel crea rutes a la teva màquina perquè les IP assignades siguin accessibles. És una emulació local, no un balancejador real.
L'argument econòmic que porta a Ingress
Cada Service de tipus LoadBalancer provoca l'aprovisionament d'un balancejador independent al núvol, amb la seva IP pública i la seva factura. Per a Rutas Norte:
| Servei a publicar | Balancejador propi? | Cost mensual aproximat |
|---|---|---|
botiga-web |
Sí | 1 balancejador |
api-reserves |
Sí | 1 balancejador |
| Panell d'administració intern | Sí | 1 balancejador |
| Mètriques de Grafana (07-04) | Sí | 1 balancejador |
Quatre balancejadors, quatre IP públiques, quatre certificats TLS per gestionar per separat i cap possibilitat d'encaminar per ruta o per capçalera. Multiplicat per tres entorns, dotze. L'alternativa és un únic LoadBalancer davant d'un controlador d'Ingress, que reparteix internament per domini i per ruta. D'aquí ve 04-04.
A més, LoadBalancer opera en L4: no entén HTTP, no pot encaminar per Host, no pot reescriure rutes. Per a serveis que no són HTTP (un broker MQTT, un postgres exposat a una altra xarxa) continua sent la resposta correcta.
externalTrafficPolicy: Cluster davant de Local
externalTrafficPolicy: Cluster davant de LocalS'aplica a NodePort i LoadBalancer, i decideix què fa un node quan li arriba trànsit extern per a un Service.
flowchart TB
subgraph CL["externalTrafficPolicy: Cluster (per defecte)"]
direction LR
C1["Client 203.0.113.9"] --> N1["Node A<br/>(sense pods)"]
N1 -->|"SNAT: origen passa a IP del node A"| N2["Node B<br/>pod botiga-web"]
N2 --> R1["El pod veu origen = 192.168.49.2"]
end
subgraph LO["externalTrafficPolicy: Local"]
direction LR
C2["Client 203.0.113.9"] --> M1["Node A<br/>(sense pods)"]
M1 -->|"DESCARTA"| X1["Sense resposta"]
C2 --> M2["Node B<br/>pod botiga-web"]
M2 --> R2["El pod veu origen = 203.0.113.9"]
end
Cluster (per defecte) |
Local |
|
|---|---|---|
| Salt extra entre nodes | Sí, si el node no té pods | No, mai |
| IP d'origen del client | Es perd (SNAT al node) | Es conserva |
| Repartiment de càrrega | Uniforme entre tots els pods | Proporcional als pods d'aquell node |
| Comprovació de salut del balancejador | Tots els nodes responen | Només els que tenen pods (per healthCheckNodePort) |
| Si un node no té pods | Reenvia | Descarta el paquet |
El desequilibri de Local mereix un exemple. Si botiga-web té 3 rèpliques i el node A n'allotja 2 i el node B 1, un balancejador que reparteixi 50/50 entre nodes farà que cada pod del node A rebi un 25 % del trànsit i el del node B un 50 %. Es corregeix amb antiafinitat de pods (06-05).
Per a Rutas Norte, la IP d'origen importa: els registres d'accés, la limitació de peticions als pics dels ponts i el bloqueig d'adreces abusives en depenen. Amb Cluster totes les peticions semblarien venir dels nodes.
Quan el trànsit arriba per un Ingress HTTP hi ha una alternativa: el controlador afegeix la capçalera X-Forwarded-For amb la IP real. Però això només serveix per a HTTP i només si l'aplicació la llegeix. Existeix també internalTrafficPolicy, amb la mateixa idea aplicada al trànsit intern del clúster: Local obliga que un pod es connecti només a rèpliques del seu propi node.
ExternalName: la passarel·la de pagaments
ExternalName: la passarel·la de pagamentsapi-reserves ha de cobrar els bitllets contra pagos.proveedorexterno.example, que és fora del clúster. Es podria posar aquest domini en un ConfigMap i llestos, però ExternalName dona una capa d'indirecció molt útil.
# k8s/entorns/pro/passarella-pagaments-externalname.yaml
apiVersion: v1
kind: Service
metadata:
name: passarella-pagaments
namespace: rutas-norte-pro
labels:
app.kubernetes.io/part-of: rutas-norte
entorn: pro
spec:
type: ExternalName
externalName: pagos.proveedorexterno.exampleQuè passa per sota: CoreDNS crea un registre CNAME. Quan api-reserves resol passarella-pagaments.rutas-norte-pro.svc.cluster.local, la resposta és un àlies cap a pagos.proveedorexterno.example, que es resol pel DNS extern (04-03).
kubectl run t --rm -it --restart=Never -n rutas-norte-pro \
--image=nicolaka/netshoot -- nslookup passarella-pagamentsServer: 10.96.0.10
Address: 10.96.0.10#53
passarella-pagaments.rutas-norte-pro.svc.cluster.local
canonical name = pagos.proveedorexterno.example.
Name: pagos.proveedorexterno.example
Address: 198.51.100.44Avantatges per al nostre cas:
- L'aplicació sempre apunta a
passarella-pagaments, als tres entorns. El que canvia és l'externalNamede cada namespace: arutas-norte-devapuntaria apagos-sandbox.proveedorexterno.example, aproal de producció. Canviar de proveïdor no toca ni una línia de codi. - No hi ha proxy: el trànsit va directe del pod a la destinació externa, sense passar per kube-proxy.
I les seves tres limitacions, que causen sorpreses:
- No tradueix ports. El
portsd'unExternalNameés decoratiu. Si el proveïdor escolta al 8443, el teu client ha de demanar el 8443. - No fa TLS. El certificat del proveïdor serà el de
pagos.proveedorexterno.example, no el depassarella-pagaments, així que la validació SNI/hostname farà servir el nom real. Amb HTTP iHostreescrit pot fallar la comprovació a l'altre extrem. - Depèn del DNS extern. Si CoreDNS no pot reenviar al resolutor del node, això no funciona.
Nota important per a 04-06: un ExternalName no compta com a excepció en una política de xarxa. Per permetre la sortida cap al proveïdor caldrà autoritzar el seu rang d'IP amb ipBlock.
- Serveis sense selector: endpoints a mà
Un Service normal esbrina les seves destinacions mitjançant el selector. Si omets el selector, el controlador d'endpoints no crea res i pots escriure tu mateix l'EndpointSlice. El resultat és un ClusterIP normal, amb el seu nom DNS i el seu balanceig, que apunta a adreces que no són pods.
Cas realista de Rutas Norte: durant la migració, la base de dades de facturació continua en una màquina virtual de l'oficina, a 10.20.30.40:5432.
# k8s/entorns/pro/facturacio-externa.yaml
apiVersion: v1
kind: Service
metadata:
name: facturacio-llegat
namespace: rutas-norte-pro
spec:
ports:
- name: postgres
port: 5432
targetPort: 5432
protocol: TCP
# SENSE selector: ningu no omple els endpoints automaticament
---
apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
name: facturacio-llegat-manual
namespace: rutas-norte-pro
labels:
# OBLIGATORIA: enllaca el slice amb el Service
kubernetes.io/service-name: facturacio-llegat
addressType: IPv4
ports:
- name: postgres # ha de coincidir amb el name del Service
port: 5432
protocol: TCP
endpoints:
- addresses:
- "10.20.30.40"
conditions:
ready: trueDetalls crítics:
- L'etiqueta
kubernetes.io/service-nameés el que uneix el slice amb el Service. Sense ella, el Service es queda sense endpoints. - El camp
ports[].namede l'EndpointSlice ha de coincidir amb elports[].namedel Service. - Ningú no comprova la salut d'aquella adreça. Si la màquina cau, el Service continua enviant-hi trànsit. La responsabilitat de mantenir la llista és teva.
- Les adreces no poden ser IP de Services (
10.96.x.x) ni de bucle local.
Avantatge principal: l'aplicació connecta a facturacio-llegat:5432 des del primer dia. El dia que aquella base de dades es migri a un pod del clúster, s'afegeix el selector, s'esborra el slice manual i l'aplicació no se n'assabenta. És el patró d'indirecció que fa les migracions tolerables.
- Serveis headless
Un Service amb clusterIP: None és headless: no té IP virtual, no crea regles a kube-proxy i no balanceja res. L'única cosa que fa és publicar al DNS una entrada A per cada pod que casa amb el selector.
apiVersion: v1
kind: Service
metadata:
name: postgres-reserves-headless
namespace: rutas-norte-pro
spec:
clusterIP: None # aixo el converteix en headless
selector:
app: postgres-reserves
entorn: pro
ports:
- name: postgres
port: 5432| Service normal | Service headless | |
|---|---|---|
CLUSTER-IP |
10.96.x.x |
None |
| Regles de kube-proxy | Sí | No |
| Resposta DNS | Una A: la IP virtual | Una A per pod llest |
| Balanceig | El fa el kernel | El fa el client |
| Ús típic | Tota la resta | Bases de dades en clúster, StatefulSets |
$ nslookup postgres-reserves-headless.rutas-norte-pro.svc.cluster.local
Name: postgres-reserves-headless... Address: 10.244.0.14
Name: postgres-reserves-headless... Address: 10.244.0.18
Name: postgres-reserves-headless... Address: 10.244.0.23Per a què serveix això? Per als casos en què el client necessita distingir els pods entre si:
- Una rèplica de PostgreSQL amb un primari i dos secundaris: el client escriu al primari i llegeix dels secundaris. Un ClusterIP que repartís a l'atzar ho trencaria.
- Bases de dades distribuïdes (Cassandra, Elasticsearch, Kafka) on cada node ha de conèixer els altres pel seu nom.
- Clients amb balanceig propi (gRPC), que volen la llista de destinacions per repartir per petició i no per connexió.
El detall complet dels registres DNS que genera és a 04-03, i el seu ús real —amb identitats estables tipus postgres-reserves-0.postgres-reserves-headless— arriba amb els StatefulSets de 06-01, on per fi postgres-reserves deixarà de ser un Deployment.
Un matís: un Service headless i sense selector no genera registres A; en el seu lloc CoreDNS retorna els noms de l'externalName si n'hi hagués, o els endpoints manuals que defineixis.
sessionAffinity, ports amb nom i multiport
sessionAffinity, ports amb nom i multiportsessionAffinity: ClientIP
Per defecte kube-proxy reparteix les connexions a l'atzar. Amb afinitat, totes les connexions de la mateixa IP d'origen van al mateix pod durant un temps.
spec:
sessionAffinity: ClientIP
sessionAffinityConfig:
clientIP:
timeoutSeconds: 10800 # 3 hores; per defecte tambe 10800És un martell tosc i cal dir-ho clar:
- Funciona per IP, no per usuari. Cent clients darrere del NAT d'una empresa són una sola IP i cauen tots al mateix pod.
- Trenca el repartiment de càrrega i complica els desplegaments progressius.
- Amb
externalTrafficPolicy: Cluster, la IP d'origen ja ve emmascarada, així que l'afinitat s'aplica sobre la IP del node: inútil.
Per a Rutas Norte no el fem servir: api-reserves és sense estat, i la sessió del comprador va en un JWT i a redis-cache. Aquesta és la solució correcta; l'afinitat de sessió és un pedaç per a aplicacions que guarden estat en memòria.
Ports amb nom i multiport
Quan un Service exposa més d'un port, name és obligatori a cadascun.
apiVersion: v1
kind: Service
metadata:
name: api-reserves
namespace: rutas-norte-pro
spec:
selector:
app: api-reserves
entorn: pro
ports:
- name: http # obligatori en haver-hi diversos
port: 3000
targetPort: api # apunta a un port AMB NOM del contenidor
protocol: TCP
- name: metrics # el consumira Prometheus al 07-03
port: 9090
targetPort: metrics
protocol: TCPAmb el contenidor declarant:
Avantatges de fer servir targetPort amb nom: si demà l'aplicació canvia de port, es toca només el Deployment. I els noms de port són els que habiliten els registres SRV del DNS (04-03). Restricció: el nom ha de tenir 15 caràcters o menys i ser minúscules, dígits i guions.
- Què fa servir Rutas Norte i per què
| Component | Tipus triat | Motiu |
|---|---|---|
botiga-web |
ClusterIP |
Es publicarà per Ingress (04-04), no directament |
api-reserves |
ClusterIP multiport (http + metrics) |
Igual; les mètriques no s'exposen mai fora |
postgres-reserves |
ClusterIP (i headless a 06-01) |
No ha de sortir mai del clúster |
redis-cache |
ClusterIP |
Ús intern exclusiu |
worker-notificacions |
Sense Service | No rep connexions entrants; només consumeix de la cua |
passarella-pagaments |
ExternalName |
Indirecció cap al proveïdor extern |
facturacio-llegat |
Sense selector + EndpointSlice manual | Base de dades encara fora del clúster |
| Controlador d'Ingress | LoadBalancer (un de sol) |
Un balancejador per a tota la plataforma |
Aquella última fila és la conclusió pràctica de la lliçó: la plataforma sencera acaba tenint un sol punt d'entrada de pagament, i tota la resta viu en ClusterIP.
Un detall sobre worker-notificacions que convé interioritzar: no tot Deployment necessita un Service. El Service existeix per rebre connexions. Un procés que només fa connexions sortints no en necessita cap. (Sí que en necessitarà un si més endavant exposa mètriques per a Prometheus.)
Errors Comuns i Consells
- Posar
type: LoadBalanceren un clúster local i esperar una IP. El<pending>és l'esperat sense proveïdor. A minikube,minikube tunnel; en un servidor propi, MetalLB. - Fixar
nodePorta mà "perquè sigui fàcil de recordar". Genera col·lisions entre equips i desplegaments que fallen ambprovided port is already allocated. Deixa que l'assigni el clúster. - Canviar de
ClusterIPaNodePorti creure que es perd el ClusterIP. No es perd: els tipus són acumulatius. El trànsit intern continua igual. - Fer servir
ExternalNameamb ports diferents. No tradueix ports. Si el proveïdor escolta al 8443, el teu client ha de demanar 8443 explícitament. - Un Service sense selector sense EndpointSlice. Es crea sense cap error i no respon mai. Comprova sempre amb
kubectl get endpointslices -l kubernetes.io/service-name=<svc>. - Oblidar
nameen un Service multiport. L'error és clar (must specify name for multiple ports), però arriba tard: acostuma't a anomenar sempre els ports, fins i tot amb un de sol. - Fer servir
sessionAffinityper arreglar una aplicació amb estat en memòria. Estàs tapant el problema. Treu l'estat aredis-cache. - Esperar que un Service headless balancegi. No ho fa. El client rep totes les IP i decideix ell. Moltes biblioteques HTTP agafen només la primera.
- Consell:
kubectl get svc -A -o custom-columns=NS:.metadata.namespace,NOM:.metadata.name,TIPUS:.spec.typeés una auditoria d'un cop d'ull. QualsevolLoadBalancerinesperat és diners sortint. - Consell: en depurar, ves sempre de dins cap a fora. ClusterIP → NodePort → LoadBalancer. Una fallada a la capa interna es manifesta a totes les externes.
Exercicis
Exercici 1: Publicar botiga-web amb NodePort i comprovar les capes
A rutas-norte-dev, canvia el Service de botiga-web a NodePort sense fixar el port. Comprova que continua funcionant des de dins pel seu ClusterIP i des de fora per la IP del node. Explica quina columna de kubectl get svc et diu tots dos ports.
Exercici 2: La passarel·la de pagaments amb ExternalName
Crea el Service passarella-pagaments a rutas-norte-dev apuntant a un sandbox (pagos-sandbox.proveedorexterno.example) i a rutas-norte-pro al domini real. Verifica des d'un pod efímer que la resolució retorna un CNAME diferent a cada namespace. Explica per què això permet que el codi d'api-reserves sigui idèntic als dos entorns.
Exercici 3: Base de dades de facturació fora del clúster
Crea facturacio-llegat com a Service sense selector amb un EndpointSlice manual apuntant a 10.20.30.40:5432. Comprova que el Service té endpoints i que el nom resol. Després, provoca la fallada típica: esborra l'etiqueta kubernetes.io/service-name del slice i observa què passa.
Solucions
Exercici 1
kubectl patch svc botiga-web -n rutas-norte-dev -p '{"spec":{"type":"NodePort"}}'
kubectl get svc botiga-web -n rutas-norte-dev# Des de dins: el ClusterIP segueix viu
kubectl run t --rm -it --restart=Never -n rutas-norte-dev \
--image=nicolaka/netshoot -- curl -s -o /dev/null -w '%{http_code}\n' http://botiga-web
# Des de fora
curl -s -o /dev/null -w '%{http_code}\n' http://$(minikube -p rutas-norte ip):30417La columna PORT(S) amb format 80:30417/TCP dona tots dos: a l'esquerra el port del ClusterIP, a la dreta el NodePort. Demostra que NodePort afegeix una capa sobre ClusterIP.
Exercici 2
for NS in dev pro; do
DEST=$( [ $NS = pro ] && echo pagos.proveedorexterno.example \
|| echo pagos-sandbox.proveedorexterno.example )
kubectl create service externalname passarella-pagaments \
--external-name=$DEST -n rutas-norte-$NS
done
kubectl run t --rm -it --restart=Never -n rutas-norte-dev \
--image=nicolaka/netshoot -- nslookup passarella-pagamentspassarella-pagaments.rutas-norte-dev.svc.cluster.local
canonical name = pagos-sandbox.proveedorexterno.example.El codi d'api-reserves fa servir sempre http://passarella-pagaments/cobraments. El namespace determina a quin proveïdor real es tradueix, sense variables d'entorn diferents ni branques al codi. Canviar de proveïdor és editar un manifest.
Exercici 3
kubectl apply -f k8s/entorns/pro/facturacio-externa.yaml
kubectl get endpointslices -n rutas-norte-pro \
-l kubernetes.io/service-name=facturacio-llegat# Provocar la fallada: treure l'etiqueta que uneix slice i Service
kubectl label endpointslice facturacio-llegat-manual \
-n rutas-norte-pro kubernetes.io/service-name-
kubectl get endpointslices -n rutas-norte-pro \
-l kubernetes.io/service-name=facturacio-llegat
# No resources foundEl Service continua existint, el seu ClusterIP continua assignat, kubectl get svc no mostra res estrany, i tota connexió es queda penjada fins a esgotar el temps d'espera. És el mateix quadre clínic que un selector que no casa, vist a 02-05: el Service sembla sa i no té destinacions. Per això la primera comprovació davant de "el Service no respon" és sempre mirar-ne els endpoints.
Conclusió
Ja coneixes el catàleg complet. ClusterIP és el tipus per defecte i el que fa servir gairebé tota la plataforma: només accessible des de dins. NodePort hi afegeix a sobre un port del rang 30000-32767 obert a tots els nodes, útil per provar i com a fonament d'altres mecanismes, però inacceptable en producció pels seus ports arbitraris, la seva manca de TLS i la seva dependència de la IP d'un node concret. LoadBalancer hi afegeix a sobre una IP externa aprovisionada pel proveïdor —d'aquí el <pending> etern quan no n'hi ha cap, i minikube tunnel per emular-lo—, i el seu cost d'un balancejador per servei és exactament l'argument que justifica l'Ingress. ExternalName no encamina trànsit: fa que CoreDNS retorni un CNAME, i amb ell hem donat a la passarel·la de pagaments un nom intern estable, diferent per entorn, sense tocar el codi.
Saps que els tres primers tipus són capes acumulatives, cosa que imposa diagnosticar sempre de dins cap a fora. Entens externalTrafficPolicy: Cluster reenvia entre nodes però destrueix la IP d'origen del client, mentre que Local la conserva a canvi d'un repartiment de càrrega desigual. I domines les dues variants que no són tipus: els serveis sense selector, on escrius tu l'EndpointSlice per apuntar a una base de dades externa i on l'etiqueta kubernetes.io/service-name és la baula que tothom oblida; i els serveis headless, que renuncien a la IP virtual per publicar una entrada A per pod, imprescindibles quan el client necessita distingir rèpliques.
Hi ha un fil que ha travessat tota la lliçó sense desenvolupar-se: el DNS. ExternalName funciona perquè CoreDNS crea un CNAME. Headless funciona perquè CoreDNS crea una A per pod. api-reserves troba postgres-reserves perquè hi ha un nom que es resol. La lliçó següent, 04-03, obre aquella caixa: què és CoreDNS, quines formes curtes de nom funcionen i quan, per què ndots: 5 pot multiplicar per cinc les consultes a la passarel·la de pagaments, i com diagnosticar les tres fallades de DNS que veuràs una vegada i una altra a la teva carrera.
Curs de Kubernetes
Mòdul 1: Introducció a Kubernetes
- Què és Kubernetes?
- Arquitectura de Kubernetes
- Conceptes i Terminologia Clau
- Configuració d'un Clúster de Kubernetes
- La CLI de Kubernetes: kubectl
- Objectes, Manifests YAML i el Model Declaratiu
- El Projecte del Curs: la Plataforma Rutas Norte
Mòdul 2: Components Principals de Kubernetes
- Pods
- ReplicaSets
- Deployments
- Actualitzacions, Rollbacks i Estratègies de Desplegament
- Serveis
- Namespaces
- Etiquetes, Selectors i Anotacions
Mòdul 3: Gestió de Configuració i Secrets
- ConfigMaps
- Secrets
- Variables d'Entorn
- Quotes i Límits de Recursos
- LimitRanges i Classes de Qualitat de Servei (QoS)
- ServiceAccounts i Accés a l'API des dels Pods
Mòdul 4: Xarxes a Kubernetes
- Xarxes de Clúster
- Tipus de Serveis
- DNS Intern i Descobriment de Serveis
- Controladors d'Ingress
- TLS i Gestió de Certificats amb cert-manager
- Polítiques de Xarxa
Mòdul 5: Emmagatzematge a Kubernetes
- Volums
- Volums Persistents
- Reclamacions de Volums Persistents
- Classes d'Emmagatzematge
- Aprovisionament Dinàmic, Expansió i Snapshots
- Còpies de Seguretat i Restauració de Dades
Mòdul 6: Conceptes Avançats de Kubernetes
- StatefulSets
- DaemonSets
- Treballs i CronJobs
- Init Containers, Sidecars i Patrons Multicontenidor
- Planificació: Afinitat, Taints i Toleracions
- Definicions de Recursos Personalitzats (CRDs)
- Operadors i el Patró Controlador
Mòdul 7: Monitoratge i Registre
- Verificacions de Salut i Sondes
- Servidor de Mètriques i kubectl top
- Monitoratge amb Prometheus
- Visualització i Alertes amb Grafana i Alertmanager
- Registre Centralitzat amb Elasticsearch, Fluentd i Kibana (EFK)
- Depuració d'Aplicacions i Esdeveniments del Clúster
Mòdul 8: Seguretat a Kubernetes
- Control d'Accés Basat en Rols (RBAC)
- Contextos de Seguretat i Enduriment del Contenidor
- Polítiques de Seguretat de Pods i Pod Security Standards
- Seguretat de Xarxa
- Seguretat d'Imatges
- Auditoria, Escaneig i Gestió de Vulnerabilitats
Mòdul 9: Escalat i Rendiment
- Autoescalat Horitzontal de Pods
- Autoescalat Vertical de Pods
- Autoescalat de Clúster
- Escalat per Esdeveniments i Mètriques Personalitzades amb KEDA
- Alta Disponibilitat: PodDisruptionBudgets i Topologia
- Ajust de Rendiment
Mòdul 10: Ecosistema i Eines de Kubernetes
- Minikube i Entorns Locals amb kind
- Kubeadm
- Helm
- Kustomize
- GitOps amb Argo CD i Flux
- Kubernetes Gestionat: EKS, AKS i GKE
Mòdul 11: Estudis de Cas i Aplicacions del Món Real
- Desplegament d'una Aplicació Web
- Execució d'Aplicacions amb Estat
- CI/CD amb Kubernetes
- Estratègies de Desplegament: Blue-Green i Canary
- Gestió Multi-Clúster
- Operació en Producció: Incidències, Runbooks i Costos
