Conceptes Fonamentals de Kubernetes
Els conceptes fonamentals que heu de dominar
Ara que ja entenem l'arquitectura general, anem a aprofundir en els conceptes que utilitzareu dia a dia quan treballeu amb Kubernetes. Aquests són els blocs de construcció bàsics que necessiteu conèixer per poder desplegar i gestionar aplicacions.
Pods: la unitat bàsica d'execució
Quan parleu amb algú que treballa amb Kubernetes, la primera cosa que us dirà és que el Pod és la unitat més petita i bàsica que podeu desplegar. Però què vol dir això exactament?
Un pod és com una capsa que encapsula un o més contenidors que treballen junts. Penseu en un pod com una petita "màquina virtual lleugera" que agrupa contenidors que necessiten compartir recursos. Tots els contenidors dins d'un mateix pod comparteixen la mateixa adreça IP, poden comunicar-se entre ells usant localhost, i poden compartir volums d'emmagatzematge.
Ara bé, tot i que un pod pot contenir múltiples contenidors, la pràctica més habitual i recomanada és tenir un sol contenidor per pod. Per què? Doncs perquè això fa que sigui més fàcil escalar i gestionar les aplicacions. Si teniu una aplicació web i voleu escalar-la, simplement creeu més pods amb aquesta aplicació. Si poseu múltiples coses diferents dins d'un mateix pod, aleshores no podeu escalar-les independentment.
Hi ha excepcions a aquesta regla, però. De vegades té sentit tenir múltiples contenidors en un pod quan un contenidor és l'aplicació principal i els altres són helpers. Per exemple, podríeu tenir un pod amb el vostre servidor web com a contenidor principal, i un segon contenidor que s'encarrega de recolectar els logs i enviar-los a un sistema centralitzat. Aquest patró s'anomena "sidecar pattern".
Una cosa molt important d'entendre sobre els pods és que són efímers, és a dir, temporals. Kubernetes pot crear i destruir pods en qualsevol moment. Si un node falla, tots els pods d'aquell node es consideren perduts i Kubernetes en crea de nous en altres nodes. Si actualitzeu una aplicació, els pods vells es destrueixen i es creen de nous amb la nova versió. Per això, mai no hauríeu de pensar en un pod específic com alguna cosa permanent. Les dades importants s'han de guardar fora dels pods, en volums persistents.
Un exemple bàsic d'un pod seria aquest, que executa un servidor web NGINX amb la versió 1.27:
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
spec:
containers:
- name: nginx
image: nginx:1.27
ports:
- containerPort: 80
Aquest fitxer YAML (que és el format estàndard per definir recursos a Kubernetes) diu molt simplement: "Vull un pod que es digui nginx-pod, que tingui un contenidor amb la imatge de Docker nginx:1.27, i que aquest contenidor exposi el port 80". Fixeu-vos que especifiquem la versió 1.27 de NGINX, no usem latest. Això és una bona pràctica perquè així sabem exactament quina versió estem executant.
Podeu trobar tota la documentació sobre pods a https://kubernetes.io/docs/concepts/workloads/pods/
Deployments: gestió intel·ligent dels vostres pods
Acabem de veure què són els pods, però hi ha un problema: normalment no creeu pods directament. Per què? Doncs perquè els pods són efímers i necessiteu alguna cosa que els gestioni de forma intel·ligent. Aquí és on entren els Deployments.
Un Deployment és com un gestor que s'encarrega de mantenir els vostres pods funcionant correctament. Quan creeu un Deployment, li esteu dient a Kubernetes: "Vull que sempre hi hagi X rèpliques d'aquesta aplicació funcionant, i si alguna falla, crea'n una de nova automàticament". Però els Deployments fan molt més que això.
La gran potència dels Deployments està en com gestionen les actualitzacions. Imagineu que teniu la vostra aplicació web funcionant amb 5 rèpliques (5 pods), i voleu actualitzar-la a una nova versió. Si destruíssiu tots els pods vells i crééssiu els nous d'un cop, tindríeu un downtime, un perióde de temps on l'aplicació no estaria disponible. Això no és acceptable en un entorn de producció.
Els Deployments tenen una funcionalitat anomenada "rolling update" (actualització rodant) que resol aquest problema de forma elegant. El que fa és anar actualitzant els pods progressivament: crea un pod nou amb la nova versió, espera que estigui funcionant correctament, i només llavors destrueix un pod vell. Després repeteix el procés fins que tots els pods estan actualitzats. D'aquesta manera, sempre teniu algunes rèpliques funcionant i mai hi ha downtime.
I encara hi ha més: si després d'actualitzar us adoneu que la nova versió té un error, podeu fer un rollback (revertir) a la versió anterior amb una sola comanda. Kubernetes recorda les versions anteriors i pot tornar enrere de forma automàtica.
Els Deployments també permeten escalar les vostres aplicacions molt fàcilment. Si veieu que necessiteu més capacitat, només heu de canviar el nombre de rèpliques i Kubernetes crea o destrueix pods automàticament per arribar al nombre desitjat.
Aquí teniu un exemple complet d'un Deployment que crea tres rèpliques d'un servidor web NGINX:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.27
ports:
- containerPort: 80
Analitzem aquest fitxer per entendre què fa cada part. A la secció de metadata donem un nom al deployment. Després, a spec, diem que volem 3 rèpliques. El selector amb matchLabels indica quins pods gestiona aquest Deployment (els que tenen l'etiqueta app: nginx). Finalment, template defineix com seran els pods que crearà: contindran un contenidor NGINX amb la versió 1.27.
La documentació oficial sobre Deployments es pot trobar a https://kubernetes.io/docs/concepts/workloads/controllers/deployment/
Services: fent que les vostres aplicacions siguin accessibles
Ara que entenem els Deployments i sabem que tenim múltiples rèpliques dels nostres pods funcionant, ens trobem amb un problema: com accedim a aquests pods? Recordeu que els pods són efímers i tenen adreces IP que poden canviar. Si un pod falla i se'n crea un de nou, tindrà una IP diferent. I si tenim 5 rèpliques, quina IP fem servir? Com balancem la càrrega entre elles?
Aquest és exactament el problema que resolen els Services. Un Service a Kubernetes és una abstracció que defineix un conjunt lògic de pods i una política per accedir-hi. Penseu en un Service com un nom DNS estable i una IP fixa que apunta als vostres pods, independentment de quantes rèpliques hi hagi o de si els pods canvien.
Quan creeu un Service, li doneu un selector que coincideix amb les etiquetes dels vostres pods. Per exemple, si els vostres pods tenen l'etiqueta "app: nginx", el Service amb selector "app: nginx" automàticament trobarà aquests pods i dirigirà el trànsit cap a ells. Si teniu 5 rèpliques, el Service distribuirà les peticions entre els 5 pods automàticament. Si un pod falla i se'n crea un de nou, el Service ho detecta automàticament i comença a enviar-li trànsit.
Kubernetes ofereix diferents tipus de Services depenent de com voleu exposar la vostra aplicació. El tipus més bàsic és ClusterIP, que és el tipus per defecte. Aquest tipus crea una IP interna al clúster que només és accessible des de dins del clúster. És perfecte per a comunicacions internes entre diferents aplicacions del vostre clúster.
El tipus NodePort és útil quan voleu que l'aplicació sigui accessible des de fora del clúster. Amb NodePort, Kubernetes obre un port específic en tots els nodes del clúster, i qualsevol trànsit que arribi a qualsevol node en aquest port es redirigeix automàticament als vostres pods. Els ports que podeu utilitzar van del 30000 al 32767.
El tipus LoadBalancer és utilitzat principalment en entorns de núvol (AWS, Google Cloud, Azure). Aquest tipus crea automàticament un balancejador de càrrega del proveïdor de núvol que distribueix el trànsit entre els nodes del vostre clúster.
Finalment, hi ha ExternalName, que és una mica diferent: aquest tipus mapeja el vostre Service a un nom DNS extern. És útil quan voleu que els vostres pods puguin accedir a un servei extern usant un nom intern del clúster.
Aquí teniu un exemple pràctic d'un Service de tipus NodePort que exposa la nostra aplicació NGINX:
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
type: NodePort
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
nodePort: 30080
En aquest exemple, estem creant un Service anomenat nginx-service. El selector "app: nginx" indica que aquest Service enviarà trànsit als pods que tinguin aquesta etiqueta. Definim tres ports: port 80 és el port en què el Service escolta dins del clúster, targetPort 80 és el port on els pods escolten, i nodePort 30080 és el port que s'obrirà en tots els nodes per accedir des de fora.
Podeu trobar tots els detalls sobre Services a la documentació oficial: https://kubernetes.io/docs/concepts/services-networking/service/
Ingress: el proxy invers i balancejador de càrrega de Kubernetes
Fins ara hem vist com exposar aplicacions amb Services, però hi ha una limitació important: si tenim múltiples aplicacions i fem servir NodePort per a cadascuna, acabarem amb molts ports diferents oberts (30080, 30081, 30082...), i això no és gens pràctic. El que realment volem és poder accedir a totes les nostres aplicacions web pel port 80 o 443 estàndard, i que alguna cosa intel·ligent s'encarregui de dirigir cada petició a l'aplicació correcta segons el domini o el path de la URL.
Això és exactament el que fa un Ingress. Un Ingress és un recurs de Kubernetes que gestiona l'accés extern als serveis del vostre clúster, normalment HTTP i HTTPS. Funciona de manera similar a un servidor web com NGINX o Apache quan actuen com a proxy invers: rep les peticions externes i les redirigeix al servei intern adequat segons regles que definiu.
Però atenció, hi ha una cosa important d'entendre: un recurs Ingress per si sol no fa res. Necessiteu també un Ingress Controller, que és el component que realment implementa la funcionalitat d'Ingress. És com si l'Ingress fos la configuració (les regles que voleu aplicar) i l'Ingress Controller fos el programari que aplica aquestes regles. El més popular és el NGINX Ingress Controller, que al 2025 va per la versió 1.11 o superior.
Amb un Ingress podeu fer coses molt útils. Per exemple, podeu tenir múltiples aplicacions web diferents al vostre clúster, i que totes es puguin accedir pel port 80, però cadascuna amb un path diferent. Imagineu que teniu una API REST a "/api", un panell d'administració a "/admin", i l'aplicació principal a "/". L'Ingress pot dirigir cada petició al servei correcte segons el path.
També podeu fer enrutament basat en el nom de domini (virtual hosts). Per exemple, podríeu tenir "api.example.com" que apunta a la vostra API, "admin.example.com" que apunta al panell d'administració, i "www.example.com" que apunta a l'aplicació principal. Tot això amb un sol Ingress Controller que escolta al port 80.
Una altra funcionalitat molt important dels Ingress és la terminació SSL/TLS. Això vol dir que podeu posar certificats HTTPS al vostre Ingress, i ell s'encarregarà de desxifrar el trànsit HTTPS abans d'enviar-lo als vostres serveis interns. Així, els vostres serveis poden funcionar simplement amb HTTP internament, i l'Ingress s'encarrega de la complexitat de HTTPS.
Els Ingress també poden fer redireccionaments, modificar capçaleres HTTP, aplicar autenticació bàsica, i moltes altres coses. La flexibilitat és immensa, especialment amb NGINX Ingress Controller que permet injectar configuració NGINX personalitzada mitjançant anotacions.
Per utilitzar Ingress al vostre clúster, primer heu d'instal·lar un Ingress Controller. Si esteu fent servir Minikube per practicar, això és tan senzill com executar la comanda "minikube addons enable ingress". En un clúster real, hauríeu d'instal·lar NGINX Ingress Controller seguint les instruccions oficials a https://kubernetes.github.io/ingress-nginx/