Saps fer servir totes dues. Has aixecat Aurora Libros amb compose.yaml i overrides per entorn al mòdul 4, i l'has desplegada en un clúster amb StatefulSet, Ingress, HPA i rollback assajat al mòdul 6. Aquesta lliçó no ve a dir-te quina guanya, sinó a donar-te els criteris per decidir quina necessita el teu projecte, amb les equivalències exactes entre tots dos formats i una xifra honesta del cost de mantenir un clúster.
Contingut
- No són la mateixa categoria d'eina
- La pregunta correcta
- Comparativa a fons, dimensió per dimensió
- Equivalències conceptuals
- El mateix
aurora-api, en tots dos formats - Arbre de decisió
- El camí intermedi: Compose en producció
- Swarm com a esglaó, i els serveis que executen Compose
- Kompose i els límits reals de la conversió
- El cost ocult de Kubernetes
- Aurora Libros a tres mides
- No són la mateixa categoria d'eina
Comparar Compose amb Kubernetes és com comparar una recepta amb una cuina industrial. Totes dues coses serveixen per menjar, però una és un document i l'altra és un sistema amb personal.
| Docker Compose | Kubernetes | |
|---|---|---|
| Què és | Un descriptor d'aplicació multicontenidor i una CLI que l'aplica | Un orquestrador distribuït amb pla de control propi |
| On viu | A la teva màquina, parlant amb un daemon | En un clúster de nodes, amb etcd i controladors |
| Què fa quan alguna cosa cau | Reinicia el contenidor segons restart: |
Reprograma la càrrega en un altre node |
| Model d'execució | Un docker compose up que executes tu |
Bucles de reconciliació permanents |
| Estat desitjat | Existeix mentre duri la comanda | Persistent a etcd, vigilat sempre |
| Unitat mínima | El contenidor | El Pod (un o més contenidors) |
La diferència estructural és a la quarta fila. Compose executa el que li demanes i acaba; Kubernetes guarda la teva intenció i no deixa de comparar-la amb la realitat. Aquell bucle és el que et permet que un node caigui a les quatre de la matinada i els Pods reapareguin en un altre sense que ningú es desperti. També és el que t'obliga a mantenir un pla de control.
- La pregunta correcta
No és «quina és millor?». És una bateria de preguntes concretes:
- Et pots permetre que la plataforma estigui caiguda quinze minuts mentre reinicies una màquina?
- Quants nodes tindràs de debò d'aquí a un any: un, tres o trenta?
- Hi ha algú a l'equip que sàpiga depurar un
CrashLoopBackOffsense buscar a Internet? - Qui està de guàrdia a les tres de la matinada, i cobra per estar-hi?
- La teva càrrega és constant o té pics de ×8 que exigeixen autoescalat?
- El pressupost aguanta el pla de control més els nodes amb marge lliure?
Si has respost «quinze minuts són acceptables, un node, ningú, ningú, constant, no» —que és la situació de la majoria de projectes—, Compose és la resposta professional, i dir-ho en veu alta t'estalviarà un any de patiment. Si has respost el contrari en tres preguntes o més, Kubernetes comença a pagar el seu cost.
- Comparativa a fons, dimensió per dimensió
| Dimensió | Docker Compose | Kubernetes |
|---|---|---|
| Model mental | Un fitxer, serveis, up/down |
API declarativa, objectes, controladors, selectors |
| Corba d'aprenentatge | Hores | Setmanes, i mesos per operar-lo bé |
| Abast | Un host (o Swarm, amb deploy:) |
Desenes o milers de nodes |
| Alta disponibilitat | La de l'host: si cau, cau tot | Reprograma en un altre node automàticament |
| Reprogramació davant de caigudes | No existeix | El Deployment la garanteix |
| Escalat manual | --scale api=4 al mateix host |
kubectl scale, a tot el clúster |
| Autoescalat | No | HPA, VPA i Cluster Autoscaler |
| Xarxa | Bridge amb DNS per nom de servei | CNI, Service, NetworkPolicy, malla opcional |
| Descobriment | DNS intern de Docker | DNS del clúster + Service estables |
| Balanceig | Round-robin del DNS o un proxy propi | Service (L4) + Ingress (L7) |
| Emmagatzematge | Volums locals de l'host | PV/PVC, StorageClass, provisió dinàmica |
| Configuració | environment, env_file |
ConfigMap, muntables o injectables |
| Secrets | Fitxer al disc o secrets: (Swarm) |
Secret + integració amb gestors externs |
| Actualitzacions | Recrea el contenidor: hi ha tall | Rolling update amb maxSurge/maxUnavailable |
| Rollback | Tornar a l'etiqueta anterior a mà | kubectl rollout undo, amb historial |
| Sondes | healthcheck (una de sola) |
Liveness, readiness i startup separades |
| Observabilitat | Logs del daemon, Prometheus si el muntes | Mètriques i esdeveniments natius, ecosistema enorme |
| Extensibilitat | Cap de real | CRDs, operadors, webhooks |
| Multitinença | No | Namespaces, RBAC, quotes |
| Cost d'infraestructura | El d'una VM | Pla de control + nodes + marge lliure |
| Cost operatiu | Gairebé zero | Alt i permanent |
| Qui el manté | Qualsevol de l'equip | Algú que en sàpiga, de guàrdia |
| Maduresa d'equip necessària | Un desenvolupador | Almenys una persona amb experiència real |
Les tres últimes files decideixen més projectes que totes les anteriors juntes, i són les que menys apareixen a les comparatives d'Internet.
- Equivalències conceptuals
Gairebé tot el que vas escriure al compose.yaml d'Aurora Libros té traducció. El que canvia no és la idea, sinó quants objectes calen per expressar-la.
| Compose | Kubernetes | Nota |
|---|---|---|
services: api: |
Deployment + Service |
Dos objectes on n'hi havia un |
image: |
spec.containers[].image |
Idèntic; la mateixa imatge OCI |
ports: "8080:8080" |
Service (intern) o Ingress (extern) |
L'exposició es parteix en dues capes |
environment: |
ConfigMap + envFrom |
La configuració surt del descriptor |
secrets: / .env |
Secret (+ gestor extern) |
Secret és base64, no xifrat per defecte |
volumes: (amb nom) |
PersistentVolumeClaim |
Amb StorageClass i mode d'accés |
volumes: (bind mount) |
hostPath (evita'l) o ConfigMap muntat |
Poques vegades és el que vols |
deploy.replicas |
spec.replicas |
Compose només ho respecta a Swarm |
deploy.resources.limits |
resources.requests / limits |
K8s distingeix el que demana del que topa |
healthcheck: |
livenessProbe + readinessProbe + startupProbe |
D'una sonda a tres semàntiques |
depends_on: condition: |
initContainers + readinessProbe |
No hi ha ordre global; hi ha reintents |
restart: unless-stopped |
restartPolicy: Always (implícit) |
El Deployment ja ho garanteix |
networks: |
NetworkPolicy |
A Compose aïlla; a K8s s'ha de declarar |
profiles: |
Overlays de Kustomize | Tots dos activen subconjunts |
compose.prod.yaml (override) |
overlays/prod amb pedaços |
Mateixa idea, mecànica diferent |
docker compose up -d |
kubectl apply -k overlays/prod |
Un aplica i surt; l'altre deixa controladors |
Dues files mereixen un avís. La de depends_on: a Kubernetes no existeix l'arrencada ordenada global; el Pod de l'API arrencarà encara que PostgreSQL no hi sigui, fallarà, i CrashLoopBackOff ho reintentarà fins que la base de dades respongui. És lleig de veure i és el correcte: obliga que l'aplicació toleri que les seves dependències no hi siguin, que és just el que vas aprendre a 06-01. I la de Secret: està codificat en base64, no xifrat; sense xifratge en repòs d'etcd i RBAC ben posat, no és un secret, és un text incòmode de llegir.
- El mateix
aurora-api, en tots dos formats
aurora-api, en tots dos formatsCompose, tal com va quedar després del mòdul 4:
# compose.yaml (fragment)
services:
api:
image: ghcr.io/auroralibros/aurora-api:2.0.0
restart: unless-stopped
environment:
DB_HOST: aurora-db
DB_NAME: aurora_llibres
DB_USER: aurora
REDIS_URL: redis://aurora-cache:6379
LOG_LEVEL: info
secrets: [db_password]
ports: ["8080:8080"]
depends_on:
aurora-db: { condition: service_healthy }
aurora-cache: { condition: service_started }
healthcheck:
test: ["CMD", "node", "-e", "fetch('http://localhost:8080/salut/viu')"]
interval: 10s
timeout: 3s
retries: 3
start_period: 20s
deploy:
replicas: 3
resources:
limits: { cpus: "1.0", memory: 512M }
read_only: true
cap_drop: [ALL]
security_opt: ["no-new-privileges:true"]Vint-i-vuit línies. Ara el mateix a Kubernetes, sense retallar res d'essencial:
# k8s/base/api.yaml
apiVersion: v1
kind: ConfigMap
metadata: { name: aurora-config, namespace: aurora }
data:
DB_HOST: aurora-db
DB_NAME: aurora_llibres
DB_USER: aurora
REDIS_URL: redis://aurora-cache:6379
LOG_LEVEL: info
---
apiVersion: apps/v1
kind: Deployment
metadata: { name: aurora-api, namespace: aurora }
spec:
replicas: 3
selector:
matchLabels: { app: aurora-api }
template:
metadata:
labels: { app: aurora-api }
spec:
securityContext:
runAsNonRoot: true
runAsUser: 10001
containers:
- name: api
image: ghcr.io/auroralibros/aurora-api:2.0.0
ports: [{ containerPort: 8080, name: http }]
envFrom:
- configMapRef: { name: aurora-config }
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef: { name: aurora-secrets, key: db-password }
resources:
requests: { cpu: "250m", memory: "256Mi" }
limits: { cpu: "1000m", memory: "512Mi" }
startupProbe:
httpGet: { path: /salut/viu, port: http }
failureThreshold: 30
periodSeconds: 2
livenessProbe:
httpGet: { path: /salut/viu, port: http }
periodSeconds: 10
readinessProbe:
httpGet: { path: /salut/preparat, port: http }
periodSeconds: 5
securityContext:
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
capabilities: { drop: [ALL] }
---
apiVersion: v1
kind: Service
metadata: { name: aurora-api, namespace: aurora }
spec:
selector: { app: aurora-api }
ports: [{ port: 80, targetPort: http }]| Compose | Kubernetes | |
|---|---|---|
| Línies per al mateix servei | 28 | 63 |
| Objectes declarats | 1 | 3 (ConfigMap, Deployment, Service) |
| Fitxers en un projecte complet | 1 + overrides | Desenes, més els overlays |
| El que hi guanyes | — | Reprogramació, sondes separades, RBAC, HPA |
La proporció de més del doble de YAML no és un detall estètic: es multiplica per cada servei, i amb quatre serveis i tres entorns tens un directori que ja ningú no llegeix sencer. A canvi, cada línia de més compra alguna cosa real. La pregunta és si necessites el que compra.
- Arbre de decisió
graph TD
A["Quant tall toleres?"] -->|"Minuts, sense drama"| B["Més d'un node?"]
A -->|"Segons o cap"| E["Hi ha algú que sàpiga K8s?"]
B -->|No| C["Pics de càrrega imprevisibles?"]
B -->|Sí| E
C -->|No| D["**Compose en un host**<br/>ben muntat"]
C -->|Sí| F["Hi cap en un servei<br/>gestionat de contenidors?"]
F -->|Sí| G["**Cloud Run / Container Apps**<br/>autoescala sense clúster"]
F -->|No| E
E -->|"No, i no es pot contractar"| H["**Gestionat o Compose**<br/>mai K8s autogestionat"]
E -->|Sí| I["Pressupost per a<br/>pla de control + marge?"]
I -->|No| H
I -->|Sí| J["**Kubernetes gestionat**<br/>mòdul 6 tal qual"]
Cinc criteris i cap no és «el que es porta». Fixa't que el camí cap a Kubernetes exigeix dos sís seguits —coneixement i pressupost— i que el node H existeix perquè la pitjor decisió possible és un clúster autogestionat que ningú no sap reparar.
- El camí intermedi: Compose en producció
Hi ha una idea molt estesa i falsa: que Compose «no és per a producció». Compose en un host ben muntat serveix milions de peticions diàries en empreses reals. El que cal és muntar-lo amb criteri:
# compose.prod.yaml — el que converteix una joguina en producció
services:
api:
image: ghcr.io/auroralibros/aurora-api@sha256:9f2c... # digest, no etiqueta
restart: unless-stopped # sobreviu al reinici
logging:
driver: json-file
options: { max-size: "10m", max-file: "3" } # el disc no s'omple
deploy:
resources:
limits: { cpus: "1.0", memory: 512M } # ningú no es menja l'host
healthcheck: { test: ["CMD", "node", "healthcheck.js"], interval: 10s }| Requisit de producció | Com es compleix amb Compose |
|---|---|
| Arrencar després de reiniciar l'host | restart: unless-stopped + Docker amb systemd |
| No perdre dades | Volum aurora-dades + còpia externa provada |
| No omplir el disc | Rotació de logs + docker system prune programat |
| Imatge reproduïble | Referència per digest, mai :latest |
| Actualitzar sense tall llarg | docker compose up -d --pull always (segons) |
| Tornada enrere | El digest anterior a Git; up -d un altre cop |
| Vigilància | cAdvisor + Prometheus + alertes (05-06) |
| Còpia de seguretat | pg_dump programat a emmagatzematge remot |
| Certificat TLS | Caddy o Traefik al davant, amb renovació automàtica |
Els dos buits que no pot tapar: l'host és un punt únic de fallada (si mor la màquina, mor el servei fins que n'arrenquis una altra) i no hi ha autoescalat. Si el negoci tolera aquests dos buits —i moltíssims negocis els toleren—, has resolt la plataforma amb un fitxer, sense pla de control i sense guàrdies.
Una regla honesta de dimensionament: una VM de 4 vCPU i 8 GB amb la pila d'Aurora Libros ben afinada atén amb escreix uns quants centenars de peticions per segon. Abans de donar per fet que necessites un clúster, mesura amb la prova de càrrega de 06-06.
- Swarm com a esglaó, i els serveis que executen Compose
Si el problema és només el punt únic de fallada, hi ha un esglaó intermedi abans del salt gros.
| Opció | Què resol | Què costa | Estat el 2026 |
|---|---|---|---|
| Docker Swarm | Diversos nodes, reprogramació, rolling updates | Aprendre poc: deploy: al mateix fitxer |
Mantingut, gairebé sense evolució |
| Compose + host de reserva | Reposar ràpid després d'una caiguda | Un procediment manual ben assajat | Trivial |
| ECS amb Compose | Executa un compose.yaml a AWS |
Lligar-se al proveïdor | En ús |
| Cloud Run / Container Apps | Autoescalat sense clúster, fins i tot a zero | Menys control de xarxa i d'estat | Molt madurs |
| Kubernetes gestionat | Tot el del mòdul 6 | Cost i coneixement | L'estàndard |
Swarm (06-03) mereix un paràgraf d'honestedat: és senzill, funciona, i portar el compose.yaml a tres nodes costa afegir deploy: i docker stack deploy. Però el seu ecosistema està congelat, contractar algú que el conegui és més difícil cada any i la documentació de tercers escasseja. Com a esglaó temporal és raonable; com a aposta a cinc anys, pensa-t'ho dues vegades.
Els serveis tipus Cloud Run són la novetat que canvia l'arbre de decisió: autoescalen de zero a centenars d'instàncies sense que existeixi cap clúster a mantenir. Per a ghcr.io/auroralibros/aurora-api:2.0.0 —sense estat, amb sondes, dotze factors i aturada ordenada— encaixen sense tocar res. L'estat se'n va a una base de dades gestionada, i el problema de la disponibilitat deixa de ser teu.
- Kompose i els límits reals de la conversió
kompose tradueix un compose.yaml a manifestos de Kubernetes. És útil com a punt de partida i perillós com a resultat final.
kompose convert -f compose.yaml -o k8s/
# INFO Kubernetes file "aurora-api-service.yaml" created
# INFO Kubernetes file "aurora-api-deployment.yaml" created
# WARN Volume mount on the host "./datos" isn't supported - ignoring
# WARN Service "aurora-db" won't be created because 'ports' is not specified| Què converteix bé | Què converteix malament o ignora |
|---|---|
image, command, ports |
depends_on (el perd: no hi ha ordre) |
environment → variables soltes |
healthcheck → no genera les tres sondes |
deploy.replicas |
Bind mounts → advertència i pel teu compte |
restart → restartPolicy |
secrets → els deixa com a fitxers o els perd |
networks (parcialment) |
profiles, extends, develop.watch |
Cap Ingress, HPA, PDB ni NetworkPolicy |
La conclusió pràctica: kompose t'estalvia el primer 60 % del teclejat i no t'estalvia res del pensament. Tot el que fa que un desplegament sigui apte per a producció —sondes separades, requests i limits mesurats, PDB, política de xarxa, Ingress amb TLS— continua sent feina teva. Tracta'l com un esborrany, revisa'l línia a línia i no l'apliquis mai directament contra un clúster real.
- El cost ocult de Kubernetes
El que no surt a les presentacions:
| Cost | Què significa a la pràctica |
|---|---|
| El clúster | Pla de control (gestionat o no) + nodes + marge per reprogramar |
| Recursos ociosos | Necessites capacitat lliure perquè hi càpiguen els Pods d'un node caigut |
| Actualitzacions | Versions noves cada pocs mesos, amb suport limitat i APIs que es retiren |
| El deute de YAML | Desenes de fitxers per entorn; els overlays tapen però no eliminen |
| Modes de fallada nous | CrashLoopBackOff, ImagePullBackOff, Pending per manca de recursos, Evicted per pressió de memòria, PVC que no s'enllaça, DNS del clúster que falla |
| Depuració més difícil | El problema pot ser a l'app, al Pod, al node, al CNI, al CSI o a l'Ingress |
| Eines al voltant | Helm o Kustomize, un GitOps, un gestor de secrets, un sistema de mètriques |
| Formació contínua | L'ecosistema canvia més ràpid del que es consolida el coneixement |
| Les guàrdies | Algú ha de respondre a les tres de la matinada |
L'última fila és la que decideix. Formula-la així a la reunió: «si el clúster es trenca un dissabte a les tres de la matinada, qui l'arregla, en quant de temps i cobrant què?». Si no hi ha una resposta amb un nom propi, Kubernetes encara no és una opció, per molt bé que quedi a l'arquitectura.
I convé dir-ho també a l'inrevés: quan la resposta existeix, Kubernetes torna amb escreix el que costa. Autoescalat real, desplegaments sense tall, reprogramació automàtica, quotes per equip i un ecosistema que resol problemes que ni sabies que tenies. L'error no és triar Kubernetes; és triar-lo abans d'hora.
- Aurora Libros a tres mides
| Botiga petita | En creixement | Amb pics de campanya | |
|---|---|---|---|
| Trànsit | 5-20 req/s | 100-300 req/s | 40 req/s amb pics ×8-15 |
| Equip | 2 desenvolupadors | 6 persones, 1 amb sistemes | 4 desenvolupadors |
| Guàrdies | No | Horari laboral | No |
| Tall tolerable | 30 min | 5 min | Zero en campanya |
| Recomanació | Compose en un host | Kubernetes gestionat | Cloud Run o similar |
| Per què | Un fitxer, zero clúster, cost mínim | El trànsit i l'equip ja ho justifiquen | Autoescala sense clúster a mantenir |
| Base de dades | Al mateix host, amb còpies provades | Gestionada, amb rèplica | Gestionada, obligatori |
| Risc assumit | L'host és punt únic de fallada | Cost operatiu permanent | Dependència del proveïdor |
| Pas següent | Monitoratge i còpies provades | PDB, HPA i pressupost d'errors | Mesurar el cost per petició en pic |
Fixa't en la tercera columna: molt trànsit en pic no implica Kubernetes. Implica autoescalat, i hi ha més d'una manera d'aconseguir-lo. I a la segona, el que inclina la balança no és només el trànsit: és que existeix una persona amb perfil de sistemes. Sense aquella persona, la recomanació seria una altra encara que el trànsit fos el mateix.
Errors Habituals i Consells
- Triar Kubernetes pel currículum. És una raó real i humana, i és la pitjor de totes per al projecte. Si el vols aprendre, munta un clúster de laboratori amb kind, no la plataforma de producció de l'empresa.
- Creure que «Compose no és per a producció». Amb digests, límits, rotació de logs, còpies provades i vigilància, Compose sosté negocis reals. El que no dona és tolerància a la caiguda de l'host ni autoescalat.
- Aplicar la sortida de
komposesense revisar-la. Perddepends_on, no genera les tres sondes ni Ingress, HPA o PDB, i ignora els bind mounts. - Migrar a Kubernetes sense haver mesurat. Abans de justificar un clúster per rendiment, executa la prova de càrrega de 06-06 sobre l'host actual. El límit real sol ser a la base de dades, i un clúster no el mou.
- Traduir
depends_onesperant arrencada ordenada. No existeix. L'aplicació ha de reintentar; si no ho fa, arregla-la abans de migrar. - Tractar els
Secretcom a xifrats. Són base64. Sense xifratge en repòs d'etcd i RBAC estricte, no protegeixen res. - Consell: escriu la decisió i els seus motius en un document breu dins del repositori, amb data. D'aquí a un any voldràs saber per què es va triar, i si les premisses continuen sent certes.
- Consell: mantén el
compose.yamlviu encara que despleguis a Kubernetes. És la millor manera d'aixecar la pila sencera en local per desenvolupar i depurar. - Consell: si dubtes, comença per Compose. Migrar de Compose a Kubernetes amb una imatge ben feta és una feina de dies; desmuntar un clúster que ningú no sap operar costa mesos.
Exercicis
Exercici 1 — Tradueix un servei complet. Pren el servei aurora-cache (redis:7-alpine, sense exposar a l'exterior, amb volum per a la persistència opcional, límit de 256 MB de memòria i un healthcheck amb redis-cli ping) tal com és al compose.yaml. Escriu-lo a Kubernetes: Deployment, Service intern i PersistentVolumeClaim. Indica quin element de l'original no té equivalent directe i com el resols.
Exercici 2 — Aplica l'arbre de decisió. Per a cada escenari, recorre l'arbre de §6, indica el node final i justifica la decisió en tres frases. (a) Una API interna de facturació que fan servir 30 empleats en horari d'oficina, amb un desenvolupador que també fa d'administrador. (b) Una plataforma de venda d'entrades que exhaureix un concert en 90 segons, amb equip de plataforma de cinc persones i guàrdies. (c) Un blog corporatiu amb 400 visites al dia que un proveïdor extern vol desplegar en un clúster gestionat «perquè és l'estàndard».
Exercici 3 — El cost real de la decisió. Aurora Libros creix i la direcció pregunta si «cal passar a Kubernetes». Prepara una comparativa d'una pàgina amb: cost mensual estimat d'infraestructura en tots dos escenaris (fes servir xifres aproximades de proveïdor i explicita els teus supòsits), temps d'aprenentatge i de posada en marxa, quina millora mesurable aporta el clúster, quin risc nou introdueix, i la teva recomanació amb la condició que s'hauria de complir per canviar-la.
Solucions
Solució 1.
apiVersion: v1
kind: PersistentVolumeClaim
metadata: { name: aurora-cache-dades, namespace: aurora }
spec:
accessModes: [ReadWriteOnce]
resources: { requests: { storage: 1Gi } }
---
apiVersion: apps/v1
kind: Deployment
metadata: { name: aurora-cache, namespace: aurora }
spec:
replicas: 1
strategy: { type: Recreate } # un sol PVC ReadWriteOnce
selector: { matchLabels: { app: aurora-cache } }
template:
metadata: { labels: { app: aurora-cache } }
spec:
containers:
- name: redis
image: redis:7-alpine
args: ["--maxmemory", "200mb", "--maxmemory-policy", "allkeys-lru"]
ports: [{ containerPort: 6379, name: redis }]
resources:
requests: { cpu: "50m", memory: "128Mi" }
limits: { cpu: "500m", memory: "256Mi" }
livenessProbe:
exec: { command: ["redis-cli", "ping"] }
periodSeconds: 10
readinessProbe:
exec: { command: ["redis-cli", "ping"] }
periodSeconds: 5
volumeMounts: [{ name: dades, mountPath: /data }]
volumes:
- name: dades
persistentVolumeClaim: { claimName: aurora-cache-dades }
---
apiVersion: v1
kind: Service
metadata: { name: aurora-cache, namespace: aurora }
spec:
selector: { app: aurora-cache }
ports: [{ port: 6379, targetPort: redis }]El que no té equivalent directe és el healthcheck únic de Compose: aquí s'ha desdoblat en liveness i readiness, totes dues amb redis-cli ping però amb períodes diferents, perquè a Kubernetes «està viu» i «pot rebre trànsit» són preguntes separades. Tres decisions més que l'enunciat no donava i que cal raonar: strategy: Recreate en lloc de rolling, perquè un PVC ReadWriteOnce no es pot muntar en dos Pods alhora i el rolling es quedaria bloquejat; el --maxmemory de Redis posat per sota del limits.memory del contenidor, perquè Redis expulsi claus abans que el kernel mati el procés per OOM; i l'absència de ports exposats cap a fora, ja que el Service sense tipus és ClusterIP i només s'hi arriba des de dins del clúster, que és exactament el que es demanava.
Solució 2.
(a) API interna de facturació. Tall tolerable: hores, perquè fora de l'horari d'oficina no hi ha ningú que la faci servir. Un sol node n'hi ha prou i no hi ha pics. Node final: Compose en un host ben muntat. L'únic administrador no pot sostenir un clúster, i un desplegament amb restart: unless-stopped, còpies provades i monitoratge bàsic cobreix el requisit amb escreix. Afegir-hi Kubernetes multiplicaria el cost operatiu sense millorar res perceptible.
(b) Venda d'entrades. El tall tolerable és zero durant els 90 segons que importen, hi ha equip de plataforma i hi ha guàrdies. El pic és brutal però previsible en l'instant, cosa que permet preescalar abans de l'esdeveniment en lloc d'esperar que reaccioni l'HPA. Node final: Kubernetes gestionat. És el cas de llibre: alta disponibilitat real, autoescalat, desplegaments sense tall i un equip que el pot operar. Aquí el clúster torna el que costa.
(c) Blog corporatiu. 400 visites al dia són unes 0,005 peticions per segon de mitjana. El tall tolerable és d'hores. Node final: Compose en un host, o directament allotjament estàtic si el contingut ho permet. Un clúster gestionat per a això costa més al mes del que el mateix blog genera de valor i hi afegeix una dependència que ningú de l'equip no sabrà reparar. Que sigui «l'estàndard» no és un requisit: demana al proveïdor que justifiqui la decisió amb els mateixos criteris de l'arbre i la conversa s'acaba sola.
Solució 3. Estructura de la comparativa (els imports són il·lustratius i s'han de substituir pels del proveïdor i la regió reals):
| Concepte | Compose en un host | Kubernetes gestionat |
|---|---|---|
| Còmput | 1 VM de 4 vCPU / 8 GB | 3 nodes de 2 vCPU / 4 GB + marge |
| Pla de control | 0 | Cost fix mensual del proveïdor |
| Base de dades | A l'host (o gestionada) | Gestionada, obligatòria a la pràctica |
| Balancejador i TLS | Traefik al mateix host | Balancejador del proveïdor, facturat a part |
| Infraestructura | Base | Entre 2,5 i 4 vegades la base |
| Posada en marxa | Ja està feta | 2-4 setmanes de feina real |
| Formació | 0 | 1-3 mesos fins a operar amb soltesa |
| Manteniment | Pedaços de l'host | Pedaços + actualitzacions de clúster |
Millores mesurables del clúster: recuperació automàtica davant de la caiguda d'un node (de «minuts amb intervenció humana» a «segons sense ella»), autoescalat de 3 a 12 rèpliques davant de pics, i desplegaments sense tall amb rollback en una comanda. Riscos nous: dependència d'un coneixement que avui no existeix a l'equip, més superfície de configuració que pot fallar, i cost fix que no baixa quan baixa el trànsit.
Recomanació: continuar amb Compose i revisar la decisió amb un disparador concret, no amb una data. Per exemple: «passem a Kubernetes gestionat quan es compleixin dues d'aquestes tres condicions: superar de manera sostinguda el 60 % de CPU de l'host, que el negoci fixi un objectiu de disponibilitat per damunt del 99,9 %, o que s'incorpori a l'equip una persona amb experiència real operant clústers». Escriure el disparador converteix una discussió d'opinions en una condició verificable, i aquest és el veritable lliurable de l'exercici.
Conclusió
Ja pots defensar la decisió amb criteris en lloc de fer-ho amb modes. Tens clar el primer i el més oblidat: no són la mateixa categoria d'eina. Compose és un descriptor que executes i acaba; Kubernetes guarda la teva intenció a etcd i no deixa de reconciliar-la amb la realitat. D'aquella diferència en surten totes les altres, incloses les bones —reprogramació automàtica, autoescalat, desplegaments sense tall— i les cares.
Tens la comparativa per dimensions, amb les tres files que decideixen més projectes que cap altra: cost d'infraestructura, cost operatiu i maduresa de l'equip. Tens la taula d'equivalències completa, amb els seus dos avisos importants: depends_on no té traducció perquè a Kubernetes no existeix l'arrencada ordenada, i un Secret és base64, no xifrat. I has vist el mateix aurora-api en tots dos formats: 28 línies davant de 63, un objecte davant de tres, amb la pregunta correcta al damunt —necessites el que compren aquelles línies de més?—.
L'arbre de decisió et dona cinc criteris concrets i un detall que convé recordar: arribar a Kubernetes exigeix dos sís seguits, coneixement i pressupost, i la pitjor opció de totes és un clúster autogestionat que ningú no sap reparar. Saps que Compose en producció és una decisió perfectament professional quan l'host està ben muntat —digests, límits, rotació de logs, còpies provades, TLS automàtic—, amb els seus dos buits declarats: punt únic de fallada i absència d'autoescalat. Coneixes els esglaons intermedis: Swarm, honest però congelat; els serveis que executen la teva imatge sense que existeixi cap clúster; i kompose, que t'estalvia el 60 % del teclejat i res del pensament.
I t'endús la pregunta que ordena tota la resta: si el clúster es trenca un dissabte a les tres de la matinada, qui l'arregla, en quant de temps i cobrant què?. Amb les tres versions d'Aurora Libros —la botiga petita amb Compose, la que creix amb Kubernetes gestionat, la de campanya amb autoescalat sense clúster— tens tres respostes de referència i l'hàbit d'escriure la decisió, amb la seva data i el seu disparador de revisió, dins del repositori.
A la lliçó següent baixem de la infraestructura a l'escriptori: Docker Desktop. Què és exactament aquella VM Linux que fas servir sense veure-la, per què explica el rendiment dels bind mounts, quines funcions aporta, quines condicions de llicència té —i per què convé consultar-les abans d'instal·lar-lo a l'empresa— i quines alternatives existeixen a cada sistema operatiu.
Docker: De Principiant a Avançat
Mòdul 1: Introducció a Docker
- Què és Docker?
- Instal·lant Docker
- Arquitectura de Docker
- Comandes Bàsiques de Docker
- Entenent les Imatges de Docker
- Creant el teu Primer Contenidor Docker
- El Projecte del Curs: la Plataforma Aurora Libros
Mòdul 2: Treballant amb Imatges Docker
- Docker Hub i Repositoris
- Construint Imatges Docker
- Conceptes Bàsics de Dockerfile
- Instruccions Avançades del Dockerfile
- Gestionant Imatges Docker
- Etiquetatge i Publicació d'Imatges
Mòdul 3: Contenidors Docker
- Executant Contenidors
- Cicle de Vida del Contenidor
- Gestionant Contenidors
- Inspecció i Depuració de Contenidors
- Xarxes a Docker
- Persistència de Dades amb Volums
- Límits de Recursos i Polítiques de Reinici
Mòdul 4: Docker Compose
- Introducció a Docker Compose
- Definint Serveis a Docker Compose
- Comandes de Docker Compose
- Aplicacions Multi-Contenidor
- Variables d'Entorn a Docker Compose
- Perfils, Overrides i Múltiples Entorns
- Desenvolupament Local amb Docker Compose
Mòdul 5: Conceptes Avançats de Docker
- Aprofundiment en Xarxes Docker
- Opcions d'Emmagatzematge Docker
- Millors Pràctiques de Seguretat a Docker
- Optimitzant Imatges Docker
- Builds Avançades amb BuildKit i Buildx
- Registre i Monitoratge a Docker
- El Runtime per Dins: Namespaces, Cgroups i Capes
Mòdul 6: Docker en Producció
- Preparar una Imatge per a Producció
- CI/CD amb Docker
- Orquestrant Contenidors amb Docker Swarm
- Introducció a Kubernetes
- Desplegant Contenidors Docker a Kubernetes
- Escalat i Balanceig de Càrrega
- Estratègies de Desplegament i Rollback
