Fins ara, cada peça de Quilòmetre Zero ha corregut en màquines concretes: els tres nodes de Cassandra que Ansible va configurar a 07-05, els brokers de Kafka que es reinicien d'un en un respectant les ISR, el clúster de Patroni amb el seu etcd, el MinIO amb els seus discos, el clúster de Kubernetes sobre el qual es despleguen els sis serveis. Algú ha comprat aquestes màquines, les ha instal·lat en un centre de dades, els ha posat discos i xarxa, i les substitueix quan fallen. I quan a 07-03 es va decidir un pla de recuperació davant de desastres en pilot light amb una "regió secundària", es va deixar oberta la pregunta d'on és aquesta regió i qui l'opera. Aquesta lliçó hi respon canviant la premissa: la infraestructura passa a ser una API que un proveïdor ofereix sota demanda, amb regions i zones de disponibilitat, xarxes virtuals, balancejadors, autoescalat i, sobretot, serveis gestionats que fan per nosaltres el que al curs hem muntat a mà. Veurem els models de servei i de desplegament, els conceptes que canvien el disseny (regions i zones, VPC, elasticitat), la correspondència entre cada component de Quilòmetre Zero i el seu equivalent gestionat a AWS i GCP, els avantatges i els desafiaments (inclòs el que exigeix una revisió legal), la infraestructura com a codi amb Terraform, els pilars d'una arquitectura ben dissenyada, i una introducció a FinOps amb el cost mensual aproximat de la plataforma. La pràctica desplega Quilòmetre Zero a AWS amb Terraform i els manifestos k8s/ de 07-05. Serverless, edge i CDN queden per a 08-04.
Contingut
- Models de servei: IaaS, PaaS, SaaS i la responsabilitat compartida
- Models de desplegament: pública, privada, híbrida i multinúvol
- Regions, zones de disponibilitat i recuperació davant de desastres
- Xarxes al núvol: VPC, subxarxes, balancejadors i autoescalat
- Serveis gestionats: què substitueix cada peça de Quilòmetre Zero
- Avantatges i desafiaments: elasticitat, pagament per ús, lock-in, egress i compliment
- Infraestructura com a codi amb Terraform
- Arquitectura ben dissenyada: els pilars
- FinOps: etiquetes, reserves, spot, pressupostos i el cost de Quilòmetre Zero
- Pràctica: Quilòmetre Zero a AWS amb Terraform i EKS
- Errors Comuns i Consells
- Exercicis
- Conclusió
- Models de servei: IaaS, PaaS, SaaS i la responsabilitat compartida
El núvol es defineix pel que el proveïdor assumeix i el que continua sent responsabilitat del client. Aquesta línia es mou segons el model de servei, i saber on és en cada cas és el que evita tant pagar pel que no s'usa com suposar que "el núvol ho fa" quan no ho fa.
| Capa | Centre de dades propi (el que Quilòmetre Zero té avui) | IaaS (màquines virtuals: EC2, Compute Engine) | PaaS (plataforma: RDS, EKS, App Engine, Cloud Run) | SaaS (aplicació: Keycloak gestionat, Confluent Cloud, Datadog) | FaaS (funcions: Lambda; és 08-04) |
|---|---|---|---|---|---|
| Edifici, energia, xarxa física | Client | Proveïdor | Proveïdor | Proveïdor | Proveïdor |
| Maquinari, hipervisor | Client | Proveïdor | Proveïdor | Proveïdor | Proveïdor |
| Sistema operatiu, pedaços | Client | Client | Proveïdor | Proveïdor | Proveïdor |
| Runtime, middleware (PostgreSQL, Kafka, Kubernetes) | Client | Client | Proveïdor (instal·lació, pedaços, failover) | Proveïdor | Proveïdor |
| Configuració del servei (paràmetres, rèpliques, esquemes) | Client | Client | Client | Parcial | Client |
| Aplicació i el seu codi | Client | Client | Client | Proveïdor | Client (només la funció) |
| Dades: classificació, xifratge, accés, backups lògics | Client | Client | Client | Client | Client |
| Identitats i permisos (IAM) | Client | Client | Client | Client | Client |
Dues files no canvien mai de columna: les dades i les identitats són sempre del client. Aquest és el model de responsabilitat compartida que tots els proveïdors publiquen: el proveïdor respon de la seguretat del núvol (que ningú no accedeixi físicament al disc, que l'hipervisor aïlli), el client de la seguretat al núvol (que el bucket no sigui públic, que el rol IAM no tingui *, que les dades personals estiguin xifrades i a la regió correcta). Un bucket km0-factures accessible sense autenticació és responsabilitat del client en qualsevol model.
Per a Quilòmetre Zero, el repartiment natural és: PaaS per a tot el que té equivalent gestionat (bases de dades, Kafka, Kubernetes, memòria cau, objectes), IaaS només on no n'hi ha o on el control compensa (els nodes de treball de Kubernetes són IaaS per sota, però gestionats com a grup), i SaaS per al que no aporta diferència (identitat, observabilitat si es decideix externalitzar-la).
- Models de desplegament: pública, privada, híbrida i multinúvol
| Model | Què és | Quan té sentit | Cost ocult |
|---|---|---|---|
| Núvol públic | Recursos d'un proveïdor (AWS, GCP, Azure...) compartits entre clients, aïllats lògicament | Càrregues variables, equips petits d'operació, necessitat de serveis gestionats, creixement incert | Lock-in, egress, cost per ús que creix amb l'èxit |
| Núvol privat | La mateixa abstracció (API, autoservei, elasticitat) sobre maquinari propi: OpenStack, VMware, Kubernetes on-premise | Regulació estricta, latència cap a sistemes propis, volum estable que amortitza el maquinari | Cal operar el núvol a més de l'aplicació; sense elasticitat real més enllà del maquinari comprat |
| Híbrid | Part en privat, part en públic, connectats (VPN o enllaç dedicat) | Migració gradual (l'estrangulament de 08-01 aplicat a la infraestructura); dades que s'han de quedar a dins amb còmput elàstic a fora | Latència i cost de l'enllaç; dos models de seguretat i observabilitat |
| Multinúvol | Càrregues repartides entre diversos proveïdors públics | Evitar la dependència d'un de sol, aprofitar serveis únics de cadascun, exigències de clients | El més car d'operar: dos IAM, dues xarxes, dos conjunts de serveis gestionats; l'egress entre núvols; la portabilitat obliga a renunciar al que és gestionat |
Quilòmetre Zero, que avui té el seu propi maquinari, passarà a núvol públic amb un període híbrid durant la migració (l'enllaç VPN entre el centre de dades i la VPC permet que Kafka repliqui amb MirrorMaker i que Patroni tingui una rèplica al núvol abans del tall). El multinúvol es descarta explícitament: amb quatre equips, operar dos proveïdors costaria més que el risc que mitiga, i la portabilitat es manté d'una altra manera, amb Kubernetes com a capa de desplegament i amb contenidors per al que no és gestionat (apartat 6).
- Regions, zones de disponibilitat i recuperació davant de desastres
Un proveïdor organitza la seva infraestructura en regions (una zona geogràfica: Irlanda, Frankfurt, París...) i, dins de cada regió, en diverses zones de disponibilitat (availability zones, AZ): centres de dades físicament separats (quilòmetres de distància, energia i xarxa independents) però connectats amb latència d'1-2 ms. Aquesta estructura es correspon directament amb els dominis de fallada de 07-03:
- Una AZ és un domini de fallada de centre de dades: incendi, tall d'energia, fallada de xarxa de l'edifici. Distribuir les rèpliques entre AZ (els tres nodes de Cassandra en tres AZ; el primari de Patroni i la seva rèplica síncrona en AZ diferents; els brokers de Kafka amb
broker.rack= AZ perquè les rèpliques de cada partició es reparteixin) fa que la pèrdua d'una AZ no sigui un desastre, només un failover. És el que a 07-05 feiatopologySpreadConstraintsamb l'etiqueta de zona. - Una regió és un domini de fallada geogràfic (i regulatori): un desastre natural, una fallada d'un servei regional del proveïdor, o un canvi legal. La regió secundària de 07-03 és una altra regió del mateix proveïdor, a centenars o milers de quilòmetres, amb latència de 10-80 ms, cosa que descarta la replicació síncrona entre elles.
Amb això, les tres estratègies de DR de 07-03 es concreten al núvol:
| Estratègia | Què hi ha a la regió secundària | RPO | RTO | Cost relatiu | Com es fa a AWS |
|---|---|---|---|---|---|
| Pilot light | Dades replicades (rèplica de lectura d'RDS entre regions, replicació S3, MirrorMaker d'MSK); clúster EKS mínim o inexistent; Terraform a punt per crear la resta | Minuts (replicació asíncrona) | 30-60 min (crear nodes, promoure rèplica, canviar DNS) | ~15-20 % de la primària | RDS cross-region read replica; S3 CRR; Route 53 amb failover manual |
| Warm standby | Tot desplegat a escala reduïda (EKS amb pocs nodes, serveis amb 1 rèplica) rebent dades | Minuts | Minuts (escalar i canviar DNS) | ~40-50 % | Igual + EKS actiu amb HPA a punt; Route 53 amb health checks |
| Activa-activa multiregió | Tot a escala completa a totes dues, servint trànsit alhora | Segons o zero (segons la dada) | Segons (el DNS o el balancejador global deixa d'enviar) | ~200 % + complexitat de dades | Aurora Global Database o Cassandra multi-DC; Route 53 latency routing; disseny multilíder de 03-04 |
Quilòmetre Zero manté la decisió de 07-03 (pilot light) per cost, amb una diferència important respecte del centre de dades propi: al núvol, la regió secundària no costa res mentre està buida. Terraform pot crear la infraestructura de la regió secundària en 20 minuts a partir del mateix codi; l'única cosa que ha d'existir per endavant són les dades replicades. L'activa-activa es deixa com a pas següent a 08-05, perquè implica resoldre conflictes d'escriptura entre regions (03-04) i canviaria el model de consistència de l'estoc.
flowchart TB
subgraph R1[Regió eu-west-1, primària]
direction TB
ALB[Balancejador d'aplicació<br/>ALB, públic]
subgraph AZa[AZ a]
EKSa[Nodes EKS<br/>comandes, cataleg...]
RDSa[(RDS primari<br/>km0_inventari)]
MSKa[Broker MSK 1]
CASa[Cassandra 1]
end
subgraph AZb[AZ b]
EKSb[Nodes EKS]
RDSb[(RDS standby<br/>Multi-AZ, síncron)]
MSKb[Broker MSK 2]
CASb[Cassandra 2]
end
subgraph AZc[AZ c]
EKSc[Nodes EKS]
MSKc[Broker MSK 3]
CASc[Cassandra 3]
REDc[(ElastiCache<br/>rèplica)]
end
S3[(S3 km0-fotos<br/>regional, 3+ AZ)]
ALB --> EKSa & EKSb & EKSc
end
subgraph R2[Regió eu-central-1, pilot light]
RDSr[(Rèplica de lectura<br/>asíncrona)]
S3r[(S3 replicat)]
MSKr[MirrorMaker → MSK mínim]
EKSr[EKS: només definit<br/>a Terraform]
end
RDSa -. "replicació asíncrona" .-> RDSr
S3 -. "CRR" .-> S3r
MSKa -. "MirrorMaker" .-> MSKr
DNS[Route 53<br/>km0.example] --> ALB
DNS -. "failover manual" .-> R2
- Xarxes al núvol: VPC, subxarxes, balancejadors i autoescalat
Una VPC (Virtual Private Cloud) és una xarxa privada aïllada dins de la regió, amb el seu rang d'adreces (10.0.0.0/16), dividida en subxarxes que pertanyen cadascuna a una AZ. La convenció que Quilòmetre Zero adopta, i que és l'habitual, és de tres capes per AZ:
| Subxarxa | Què conté | Accés des d'Internet | Sortida a Internet |
|---|---|---|---|
| Pública | Balancejadors, NAT gateway, bastió (si n'hi ha) | Sí (tenen IP pública i ruta a l'Internet Gateway) | Directa |
| Privada d'aplicació | Nodes d'EKS amb els sis serveis, Kong | No | A través del NAT gateway (per cridar la passarel·la de pagaments, descarregar imatges) |
| Privada de dades | RDS, MSK, ElastiCache, nodes de Cassandra | No | Cap (ni entrada ni sortida a Internet) |
Els grups de seguretat són tallafocs amb estat per recurs, i expressen les mateixes regles que les polítiques de xarxa de Kubernetes de 07-05 però a la capa de la VPC: RDS només accepta 5432 des del grup de seguretat dels nodes d'EKS; MSK només 9094 (TLS) des d'EKS; res des de fora. Els serveis gestionats com S3 s'assoleixen per endpoints de VPC, que eviten que el trànsit cap a km0-fotos surti a Internet (i eviten el cost del NAT).
Els balancejadors gestionats substitueixen l'Ingress + Kong de 07-05 en la seva capa externa: un balancejador d'aplicació (ALB a AWS, HTTP(S) Load Balancer a GCP) termina TLS amb certificats gestionats i renovats automàticament, reparteix entre les AZ, fa health checks i exposa una IP a diverses AZ. Kong continua existint al darrere, com a gateway amb els seus plugins (06-05); el balancejador és només la porta de la regió. El WebSocket de 08-02 exigeix que el balancejador suporti Upgrade i tingui un timeout d'inactivitat llarg (l'ALB ho permet; un balancejador de xarxa de capa 4 ho passa sense mirar).
L'autoescalat opera en dos nivells que cal distingir: l'HPA de 07-05 afegeix Pods segons CPU o lag de Kafka, però els Pods necessiten nodes; l'autoescalador del clúster (Cluster Autoscaler o Karpenter a EKS, l'autoescalat de node pools a GKE) afegeix i treu màquines virtuals quan hi ha Pods pendents o nodes buits. Per sota, un grup d'autoescalat de màquines virtuals (Auto Scaling Group) les reemplaça si fallen un health check i les reparteix entre AZ. La Setmana de la Verema amb k6 (07-06) es converteix així en: l'HPA puja comandes de 3 a 12 Pods → 6 Pods pendents per falta de CPU → Karpenter arrenca 2 nodes en 90 s → els Pods es programen. Aquests 90 s són la raó de mantenir marge (nodes amb capacitat lliure) abans d'una campanya anunciada, o d'escalar per calendari.
- Serveis gestionats: què substitueix cada peça de Quilòmetre Zero
Aquesta taula és la correspondència entre el que s'ha construït al curs i el que el proveïdor ofereix gestionat. A cada fila, el que es guanya és el que el proveïdor assumeix (instal·lació, pedaços, failover, backups, escalat) i el que es perd és control i portabilitat.
| Peça de Quilòmetre Zero | Lliçó | AWS | GCP | Què gestiona el proveïdor | Què continua sent nostre |
|---|---|---|---|---|---|
PostgreSQL + Patroni (km0_inventari, km0_analitica) |
03-04, 07-03 | RDS PostgreSQL Multi-AZ (o Aurora) | Cloud SQL amb alta disponibilitat | Failover entre AZ (~60 s), backups automàtics, PITR, pedaços, rèpliques de lectura | Esquema, índexs, paràmetres, pooling de connexions, restauracions de prova |
Kafka (comandes.esdeveniments, repartiment.*) |
02-04 | MSK (o Confluent Cloud) | Confluent Cloud o Pub/Sub (model diferent) | Brokers, ZooKeeper/KRaft, pedaços, rèpliques entre AZ, escalat d'emmagatzematge | Tòpics, particions, retenció, esquemes, consumidors |
Cassandra (km0_comandes) |
04-04 | Keyspaces (API compatible, serverless) o Cassandra a EC2 | Cassandra a GCE o Astra (DataStax) | Nodes, compactacions, reparacions, escalat | Model de dades, nivells de consistència (Keyspaces no suporta tot CQL: les transaccions lleugeres i alguns tipus necessiten revisió) |
| Redis (memòria cau, limitador, pub/sub) | 04-05 | ElastiCache for Redis (rèpliques entre AZ) | Memorystore | Failover, pedaços, rèpliques | Estratègia de memòria cau, TTL, claus |
MinIO (km0-fotos, km0-factures, km0-backups, km0-auditoria) |
04-03 | S3 | GCS | Durabilitat (11 nous), versionat, cicle de vida, replicació entre regions | Polítiques d'accés, xifratge amb claus pròpies, estructura de claus |
| HDFS + Spark + Airflow | 04-02, 05-03, 05-05 | EMR (Spark sobre S3, sense HDFS persistent) + MWAA (Airflow) | Dataproc + Cloud Composer | Clústers efímers, versions d'Spark, Airflow gestionat | Els treballs (vendes_diaries.py), els DAG (km0_vendes_diaries), el particionament del llac a S3 |
Flink (alertes_estoc.py) |
05-04 | Managed Service for Apache Flink | Dataflow (model Beam) o Flink a GKE | Checkpoints, escalat, versions | El codi del treball i el seu estat |
| Kubernetes | 07-05 | EKS | GKE | Pla de control (API server, etcd) amb SLA, actualitzacions | Nodes (grups gestionats), manifestos, operadors, mesh |
| Vault | 06-04 | Secrets Manager + KMS | Secret Manager + Cloud KMS | Emmagatzematge, rotació programada, auditoria | Quins secrets, qui els llegeix (IAM), integració als Pods |
Keycloak (realm km0) |
06-03 | Cognito | Identity Platform | Alta disponibilitat, escalat, federació | Realm, clients, rols, fluxos (amb menys flexibilitat que Keycloak) |
| Prometheus + Grafana + Loki + Tempo | 07-01, 07-02 | CloudWatch (mètriques, logs) + X-Ray, o Amazon Managed Prometheus/Grafana | Cloud Monitoring + Cloud Logging + Cloud Trace | Emmagatzematge, retenció, alertes | Instrumentació (serveis/comu/), dashboards, SLOs |
| Kong | 06-05 | Kong a EKS (o API Gateway gestionat, amb menys plugins) | Kong a GKE (o Apigee) | Si és gestionat: escalat i disponibilitat | Rutes, plugins |
| Mosquitto (08-02) | 08-02 | IoT Core (retirat en alguns proveïdors) o EMQX a EKS | EMQX/HiveMQ a GKE | — | Tot, si s'autogestiona |
Certificats km0-ca, mTLS |
06-04 | ACM (públics) + mesh per a mTLS | Certificate Manager + mesh | Emissió i renovació dels públics | El mTLS intern continua sent del mesh |
Tres notes sobre aquesta taula. Primera: Pub/Sub de GCP no és Kafka: no té particions ni offsets a l'estil Kafka (encara que ofereix ordenació per clau i reproducció), i el codi de consumidors amb grups i commits canvia; si es vol Kafka a GCP, és Confluent Cloud. Segona: Keyspaces és compatible amb CQL però no és Cassandra: el nivell de consistència i les transaccions lleugeres tenen diferències que cal verificar amb el repositori de 04-04 abans de migrar. Tercera: el que és gestionat no elimina l'operació, la canvia: ja no s'apedaça PostgreSQL, però continua calent dimensionar la instància, triar la finestra de manteniment (RDS reinicia per aplicar pedaços majors), provar les restauracions i vigilar les connexions.
- Avantatges i desafiaments: elasticitat, pagament per ús, lock-in, egress i compliment
| Avantatge | Què aporta a Quilòmetre Zero | Condició perquè sigui real |
|---|---|---|
| Elasticitat | La Setmana de la Verema (×15) s'absorbeix amb nodes que existeixen només aquella setmana; la resta de l'any es paga per 1/15 | Que l'aplicació escali horitzontalment (els Mòduls 4 i 7 ho han fet possible) i que l'autoescalat estigui provat (07-06) |
| Pagament per ús | Sense inversió inicial; una regió secundària buida no costa | Disciplina d'apagar el que no s'usa (apartat 9) |
| Serveis gestionats | Patroni, les reparacions de Cassandra, els pedaços de Kafka deixen de ser guàrdies de l'equip de plataforma | Acceptar menys control i algunes diferències funcionals |
| Abast global | Regions a prop de nous mercats; DR en una altra regió amb la mateixa API | Disseny conscient de la latència entre regions |
| Seguretat de base | Centre de dades certificat, xifratge en repòs per defecte, IAM granular, auditoria (CloudTrail) integrada | Configurar-la: la responsabilitat compartida de l'apartat 1 |
| Desafiament | En què consisteix | Com el tracta Quilòmetre Zero |
|---|---|---|
| Lock-in | Com més gestionat, més específic del proveïdor: Keyspaces en lloc de Cassandra, Cognito en lloc de Keycloak, Step Functions (08-04) en lloc de saga_comanda.py. Migrar de proveïdor passa a ser un projecte de mesos |
Portabilitat selectiva: Kubernetes i contenidors per als serveis; APIs estàndard (PostgreSQL, Kafka, S3, Redis, CQL) per a les dades, de manera que el gestionat sigui substituïble per l'autogestionat; acceptar lock-in on el benefici és gran (RDS, S3) i evitar-lo on és petit (Cognito davant de Keycloak a EKS) |
| Cost d'egress | Les dades que surten de la regió es cobren per GB (les que entren solen ser gratuïtes): les fotos servides a l'Anna, la rèplica a la regió secundària, el trànsit entre AZ (també es cobra, encara que menys) | CDN davant de km0-fotos (04-03, 08-04); consumidors de Kafka a la mateixa AZ que el seu broker líder quan sigui possible (client.rack); llac i còmput a la mateixa regió |
| Cost que creix amb l'èxit | A volum estable i alt, el núvol pot costar més que el maquinari propi amortitzat | Reserves i spot (apartat 9); revisar cada any amb números |
| Compliment i residència de dades | Les dades personals (nom, adreça i posició de l'Anna; dades de pagament) estan subjectes a normativa (a la UE, el RGPD) que condiciona on es poden emmagatzemar i processar, qui hi pot accedir (inclòs el proveïdor) i quins contractes calen. Triar una regió fora de la UE, o un servei que replica metadades a una altra regió, pot incomplir-la | Advertència: aquesta decisió exigeix revisió legal, no només tècnica. Quilòmetre Zero tria regions de la UE (eu-west-1, eu-central-1), xifra les dades personals amb claus pròpies a KMS (06-02) i documenta els subencarregats; però quines dades poden sortir de la UE, amb quines clàusules contractuals i amb quina avaluació d'impacte ho decideix el responsable de protecció de dades, no l'arquitecte |
| Complexitat d'IAM | Centenars de rols i polítiques; un s3:* sobre * en un rol de servei és la fuita de dades més comuna |
Mínim privilegi per servei (IAM Roles for Service Accounts a la pràctica); revisió automàtica (Access Analyzer) |
| Dependència d'un tercer | Les regions fallen (passa diverses vegades l'any a cada proveïdor) | Multi-AZ per al quotidià, DR entre regions per a l'excepcional (apartat 3) |
- Infraestructura com a codi amb Terraform
A 07-05 es van distingir les eines de configuració (Ansible: deixar una màquina existent en un estat) de les d'aprovisionament (Terraform: crear la infraestructura mateixa), i es va remetre aquí. Quan la infraestructura és una API, descriure-la com a codi és el que permet revisar-la en pull request, reproduir-la en una altra regió i saber què existeix. Terraform (i la seva bifurcació oberta OpenTofu) és declaratiu: es descriu l'estat desitjat en fitxers .tf (llenguatge HCL) i l'eina calcula i executa les crides a l'API necessàries per arribar-hi, en l'ordre que dicten les dependències.
Quatre conceptes són suficients per llegir i escriure la pràctica de l'apartat 10:
- Proveïdors (providers): plugins que tradueixen recursos a crides d'API (
aws,google,kubernetes,helm,kafka...). Es declaren amb versió fixada. - Recursos i dades:
resource "aws_db_instance" "inventari" { ... }crea;data "aws_availability_zones" "disponibles" {}consulta. Es referencien entre ells (aws_vpc.km0.id), i aquestes referències són el graf de dependències. - Estat remot: Terraform desa en un fitxer d'estat la correspondència entre el que s'ha declarat i el que existeix (ids reals). Aquest fitxer és crític i compartit: es desa en un backend remot (S3 amb versionat, i una taula de DynamoDB com a cadenat perquè dues persones no apliquin alhora; és el mateix problema d'exclusió mútua de 03-03 resolt amb un servei gestionat), es xifra i mai no es puja a Git. Conté secrets (contrasenyes inicials d'RDS), cosa que reforça l'anterior.
- Mòduls: carpetes de
.tfreutilitzables amb variables d'entrada i sortides (module "vpc" { source = "terraform-aws-modules/vpc/aws" ... }). Quilòmetre Zero usa mòduls de la comunitat per a VPC i EKS (centenars de recursos que no val la pena escriure a mà) i mòduls propis per a cada entorn.
El cicle és terraform init (descarrega proveïdors i mòduls, connecta amb l'estat), terraform plan (calcula el diff entre el que s'ha declarat i l'estat i el mostra: + crear, ~ modificar, - destruir, -/+ reemplaçar), i terraform apply (l'executa després de confirmar). El plan és la peça més valuosa: s'executa al pipeline (07-05) i s'enganxa a la pull request; un -/+ sobre aws_db_instance.inventari (reemplaçar la base de dades) és el que una revisió ha d'aturar. En GitOps, apply només l'executa el pipeline després del merge, mai una persona des del seu portàtil.
- Arquitectura ben dissenyada: els pilars
Els proveïdors publiquen marcs d'"arquitectura ben dissenyada" (well-architected) amb pilars que serveixen com a llista de comprovació. Els sis d'AWS (GCP té una llista equivalent) coincideixen gairebé un a un amb mòduls del curs:
| Pilar | Pregunta que fa | On ho ha treballat Quilòmetre Zero |
|---|---|---|
| Excel·lència operativa | S'opera amb codi, s'observa, s'aprèn dels incidents? | IaC (07-05, aquesta lliçó), observabilitat (07-01/07-02), postmortems i runbooks (07-03), GitOps |
| Seguretat | Identitat, mínim privilegi, xifratge, auditoria, defensa en profunditat? | Mòdul 6 complet; IAM i grups de seguretat d'aquesta lliçó |
| Fiabilitat | Sobreviu a fallades de component, AZ i regió? S'ha provat? | Redundància i failover (07-03), resiliència (07-04), caos (07-06), multi-AZ i DR (apartat 3) |
| Eficiència de rendiment | S'usen els recursos adequats a cada càrrega i es mesuren? | Emmagatzematge per càrrega (Mòdul 4), memòria cau (04-05), autoescalat, SLO p99 (07-01) |
| Optimització de costos | Es paga pel que s'usa, es mesura i es revisa? | FinOps (apartat 9) |
| Sostenibilitat | Es minimitza el consum: apagar el que està ociós, regions amb energia neta, eficiència del codi? | Autoescalat a la baixa, clústers efímers d'Spark, retenció de dades (04-02) |
La seva utilitat pràctica és la revisió periòdica: cada semestre, recórrer les preguntes del marc sobre la plataforma i anotar què falta. És un exercici del projecte final (08-05).
- FinOps: etiquetes, reserves, spot, pressupostos i el cost de Quilòmetre Zero
Al núvol, el cost és una mètrica més del sistema, i com qualsevol mètrica cal mesurar-la, atribuir-la i posar-hi alertes. La disciplina s'anomena FinOps i, en el seu nivell bàsic, es redueix a cinc pràctiques:
- Etiquetatge (tagging): tot recurs porta etiquetes
equip,servei,entorn,centre_cost. Sense elles, la factura és un número; amb elles, "l'equip de repartiment va gastar 1 840 € al setembre, el 60 % en MSK". Terraform les aplica per defecte a tot (default_tags). - Reserves i plans d'estalvi: comprometre's a un ús durant 1 o 3 anys a canvi d'un 30-60 % de descompte. S'aplica a la base que sempre està encesa (els nodes mínims d'EKS, RDS, MSK, ElastiCache), mai al pic.
- Instàncies spot: capacitat sobrant del proveïdor amb un 60-90 % de descompte, que pot ser retirada amb 2 minuts d'avís. Ideal per al que tolera interrupcions i es reinicia sol: els executors d'Spark (05-03 ja tolerava la pèrdua d'executors recomputant particions), els nodes d'EKS per a càrregues sense estat amb diverses rèpliques. Mai per a RDS, Cassandra, Kafka ni el pla de control.
- Pressupostos i alertes: un pressupost per equip i entorn, amb alerta al 80 % i al 100 % previstos, i detecció d'anomalies (un NAT gateway que de sobte mou 2 TB perquè algú ha servit les fotos sense CDN). Són alertes com les de 07-01, cap al mateix canal.
- Apagar el que està ociós: entorns de
stagingapagats de nit i el cap de setmana (amb Terraform o amb programacions), clústers d'Spark efímers (EMR arrenca per al DAGkm0_vendes_diariesi es destrueix en acabar), volums i snapshots orfes.
Cost mensual aproximat de Quilòmetre Zero a AWS
Els preus següents són ficticis i orientatius, de l'ordre de magnitud correcte per a una regió europea, i serveixen per al raonament, no com a pressupost. L'exercici útil és veure on és el cost, no la xifra exacta.
| Component | Dimensionament | Cost base mensual (€) | Amb reserves / spot (€) | Observació |
|---|---|---|---|---|
| EKS pla de control | 1 clúster | 70 | 70 | Fix |
| Nodes EKS (serveis, Kong, mesh, observabilitat) | 6 × 4 vCPU/16 GB permanents + fins a 12 en campanya | 900 + 300 (mitjana de pics) | 550 + 120 (reserva base, spot als pics) | Partida més gran de còmput |
RDS PostgreSQL Multi-AZ (km0_inventari) |
2 vCPU/8 GB × 2 (standby), 200 GB | 380 | 250 | Multi-AZ duplica |
RDS PostgreSQL (km0_analitica) |
2 vCPU/8 GB, 500 GB | 210 | 140 | Sense Multi-AZ: tolera RTO d'hores |
| MSK | 3 brokers × 2 vCPU/8 GB, 1 TB total | 650 | 450 | Cost per broker-hora + emmagatzematge |
| Cassandra a EC2 (3 nodes) | 3 × 4 vCPU/16 GB + 3 × 500 GB SSD | 480 | 320 | Keyspaces seria per lectura/escriptura; amb 1,2 M comandes/mes surt similar |
| ElastiCache Redis | 2 nodes 2 GB (primari + rèplica) | 90 | 60 | |
S3 (km0-fotos 30 GB, km0-factures, km0-backups 800 GB, km0-auditoria) |
~1 TB + peticions | 35 | 35 | L'emmagatzematge és barat |
| Egress a Internet (fotos, API) | 3 TB/mes sense CDN | 240 | 240 → ~40 amb CDN (08-04) | La partida que la CDN redueix |
| Trànsit entre AZ | ~2 TB/mes (rèpliques, consumidors) | 40 | 40 | S'oblida sempre |
| NAT gateway | 2 (un per AZ activa) + 500 GB | 110 | 110 | Els endpoints de VPC per a S3 el redueixen |
| ALB | 1 + trànsit | 45 | 45 | |
| EMR (Spark) efímer | 2 h/dia × 6 nodes spot | 180 | 60 | Spot: −70 % |
| MWAA (Airflow) | Entorn petit | 320 | 320 | Car per al que fa: candidat a Airflow a EKS (~40) |
| Flink gestionat | 4 KPU | 420 | 420 | Alternativa: Flink a EKS |
| Secrets Manager + KMS | 60 secrets, 3 claus | 45 | 45 | |
| CloudWatch (logs 200 GB/mes, mètriques) | 180 | 180 | O Loki/Tempo/Prometheus a EKS (cost en nodes) | |
| Regió secundària (pilot light) | Rèplica RDS, S3 CRR, MSK mínim | 350 | 350 | ~10 % de la primària |
| Suport del proveïdor | Pla de negoci | 250 | 250 | |
| Total aproximat | ≈ 5 300 | ≈ 3 900 |
El que la taula ensenya: el còmput (EKS + bases de dades + Kafka) és dos terços del total; les reserves estalvien un 25-30 % sobre la base; l'egress és la partida més sensible al disseny (la CDN de 08-04 la divideix per sis); i dos serveis gestionats (MWAA, Flink gestionat) costen més que els seus equivalents autogestionats al clúster, cosa que il·lustra que "gestionat" no sempre guanya: la decisió depèn de quant costa el temps de l'equip que l'operaria.
- Pràctica: Quilòmetre Zero a AWS amb Terraform i EKS
L'estructura del codi d'infraestructura, que s'afegeix al projecte km0/:
km0/infra/ ├── aws/ │ ├── main.tf # proveïdors, backend d'estat, VPC, EKS, RDS, MSK, ElastiCache, S3, IAM │ ├── variables.tf # region, entorn, mides │ ├── outputs.tf # endpoints que necessiten els manifestos k8s/ │ └── entorns/ │ ├── prod.tfvars │ └── staging.tfvars └── gcp/ # l'equivalent a GCP (només taula en aquesta lliçó)
El que segueix és main.tf explicat bloc a bloc. Està simplificat (hi falten alguns paràmetres de seguretat i de xarxa que un mòdul real inclou), però cada bloc és real i correspon a una decisió de les seccions anteriors.
Bloc 1: proveïdors i estat remot
# km0/infra/aws/main.tf
terraform {
required_version = ">= 1.6"
required_providers {
aws = { source = "hashicorp/aws", version = "~> 5.40" }
kubernetes = { source = "hashicorp/kubernetes", version = "~> 2.27" }
helm = { source = "hashicorp/helm", version = "~> 2.12" }
}
# Estat remot: S3 amb versionat (per recuperar un estat anterior) i
# DynamoDB com a cadenat (dos 'apply' simultanis s'exclouen).
backend "s3" {
bucket = "km0-terraform-estat"
key = "prod/infra.tfstate"
region = "eu-west-1"
dynamodb_table = "km0-terraform-cadenat"
encrypt = true
}
}
provider "aws" {
region = var.region # "eu-west-1": regió de la UE (compliment, apartat 6)
default_tags { # FinOps: tota peça porta aquestes etiquetes
tags = { projecte = "km0", entorn = var.entorn, gestionat_per = "terraform" }
}
}
data "aws_availability_zones" "disponibles" { state = "available" }
locals {
azs = slice(data.aws_availability_zones.disponibles.names, 0, 3) # tres AZ: a, b, c
}Bloc 2: la VPC amb tres capes per AZ
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "~> 5.5"
name = "km0-${var.entorn}"
cidr = "10.0.0.0/16"
azs = local.azs
public_subnets = ["10.0.0.0/24", "10.0.1.0/24", "10.0.2.0/24"] # ALB, NAT
private_subnets = ["10.0.10.0/23", "10.0.12.0/23", "10.0.14.0/23"] # nodes EKS (512 IPs per AZ: els Pods consumeixen IPs)
database_subnets = ["10.0.20.0/24", "10.0.21.0/24", "10.0.22.0/24"] # RDS, MSK, ElastiCache, Cassandra
enable_nat_gateway = true
one_nat_gateway_per_az = true # sense això, un NAT en una sola AZ és un punt únic de fallada per a la sortida
create_database_subnet_group = true
# Etiquetes que EKS necessita per descobrir en quines subxarxes crear balancejadors
public_subnet_tags = { "kubernetes.io/role/elb" = 1 }
private_subnet_tags = { "kubernetes.io/role/internal-elb" = 1 }
}
# Endpoint de VPC per a S3: el trànsit a km0-fotos no surt a Internet ni passa pel NAT (cost i seguretat)
resource "aws_vpc_endpoint" "s3" {
vpc_id = module.vpc.vpc_id
service_name = "com.amazonaws.${var.region}.s3"
route_table_ids = module.vpc.private_route_table_ids
}Bloc 3: EKS amb grups de nodes permanents i spot
module "eks" {
source = "terraform-aws-modules/eks/aws"
version = "~> 20.8"
cluster_name = "km0-${var.entorn}"
cluster_version = "1.29"
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.private_subnets # els nodes mai en subxarxes públiques
cluster_endpoint_public_access = true # kubectl des del pipeline (restringir per CIDR a prod)
enable_irsa = true # IAM Roles for Service Accounts (bloc 6)
eks_managed_node_groups = {
base = { # capacitat permanent: aquí van les reserves
instance_types = ["m6i.xlarge"] # 4 vCPU / 16 GB
min_size = 6, desired_size = 6, max_size = 9
labels = { "km0/pool" = "base" }
}
campanya = { # capacitat elàstica en spot: només Pods sense estat
instance_types = ["m6i.xlarge", "m5.xlarge", "m6a.xlarge"] # diversos tipus: més probabilitat de spot
capacity_type = "SPOT"
min_size = 0, desired_size = 0, max_size = 12
labels = { "km0/pool" = "spot" }
taints = [{ key = "km0/spot", value = "true", effect = "NO_SCHEDULE" }] # només qui ho toleri explícitament
}
}
}Els Pods de comandes i cataleg porten a k8s/comandes-deployment.yaml una toleration per a km0/spot i una affinity que prefereix base, de manera que en campanya desborden a spot; Cassandra, Kafka (si fos autogestionat) i les bases de dades no toleren el taint i mai no cauen en spot. L'autoescalador del clúster (Karpenter, instal·lat amb el proveïdor helm) és qui passa el grup campanya de 0 a 12 segons els Pods pendents.
Bloc 4: RDS PostgreSQL Multi-AZ per a km0_inventari
resource "aws_db_subnet_group" "dades" {
name = "km0-dades"
subnet_ids = module.vpc.database_subnets
}
resource "aws_security_group" "rds" {
name = "km0-rds"
vpc_id = module.vpc.vpc_id
ingress { # només 5432 i només des dels nodes d'EKS
from_port = 5432, to_port = 5432, protocol = "tcp"
security_groups = [module.eks.node_security_group_id]
}
}
resource "aws_db_instance" "inventari" {
identifier = "km0-inventari-${var.entorn}"
engine = "postgres"
engine_version = "16"
instance_class = var.entorn == "prod" ? "db.m6g.large" : "db.t4g.medium"
allocated_storage = 200
storage_encrypted = true
kms_key_id = aws_kms_key.dades.arn # clau pròpia (06-02): la rotació i l'accés els controlem nosaltres
db_name = "km0_inventari"
username = "km0_admin"
manage_master_user_password = true # la contrasenya la genera i desa Secrets Manager
multi_az = var.entorn == "prod" # standby síncron en una altra AZ: substitueix Patroni (07-03)
backup_retention_period = 14 # backups diaris + WAL continu: PITR de 14 dies
backup_window = "02:00-03:00"
maintenance_window = "sun:03:30-sun:04:30" # RDS reinicia per a pedaços majors: finestra coneguda
deletion_protection = var.entorn == "prod" # un 'terraform destroy' accidental no esborra producció
performance_insights_enabled = true
db_subnet_group_name = aws_db_subnet_group.dades.name
vpc_security_group_ids = [aws_security_group.rds.id]
}
# Rèplica de lectura a la regió secundària: la base del pilot light (07-03, apartat 3)
resource "aws_db_instance" "inventari_dr" {
provider = aws.secundaria # un segon proveïdor amb region = "eu-central-1"
identifier = "km0-inventari-dr"
replicate_source_db = aws_db_instance.inventari.arn
instance_class = "db.t4g.medium" # petita: es redimensiona en promoure
kms_key_id = aws_kms_key.dades_dr.arn
skip_final_snapshot = true
}El que aquí substitueix el que s'havia construït a mà: multi_az = true és Patroni + etcd + rèplica síncrona + failover automàtic (RDS canvia el DNS de l'endpoint a l'standby en ~60 s; l'aplicació només necessita reconnectar, que és el que el pool amb reintents de 07-04 ja fa); backup_retention_period és el pgBackRest i l'arxivat de WAL de 07-03. El que no substitueix: la prova de restauració setmanal, que continua sent un treball d'Airflow que restaura l'últim snapshot en una instància temporal i executa comprovacions.
Bloc 5: MSK, ElastiCache i S3
resource "aws_msk_cluster" "esdeveniments" {
cluster_name = "km0-esdeveniments-${var.entorn}"
kafka_version = "3.6.0"
number_of_broker_nodes = 3 # un per AZ: rèpliques de partició repartides
broker_node_group_info {
instance_type = "kafka.m5.large"
client_subnets = module.vpc.database_subnets
security_groups = [aws_security_group.msk.id]
storage_info { ebs_storage_info { volume_size = 350 } } # 3 × 350 GB ≈ 1 TB: retenció de 02-04
}
encryption_info {
encryption_in_transit { client_broker = "TLS", in_cluster = true } # TLS obligatori (06-02)
}
configuration_info {
arn = aws_msk_configuration.esdeveniments.arn
revision = aws_msk_configuration.esdeveniments.latest_revision
}
}
resource "aws_msk_configuration" "esdeveniments" {
name = "km0-esdeveniments"
server_properties = <<-EOT
default.replication.factor=3
min.insync.replicas=2
auto.create.topics.enable=false
EOT # els mateixos valors de 02-04 i 07-03
}
resource "aws_elasticache_replication_group" "cache" {
replication_group_id = "km0-cache-${var.entorn}"
description = "Memòria cau de catàleg, limitador, pub/sub de repartiment"
engine = "redis"
node_type = "cache.t4g.small"
num_cache_clusters = 2 # primari + rèplica en una altra AZ
automatic_failover_enabled = true
multi_az_enabled = true
at_rest_encryption_enabled = true
transit_encryption_enabled = true
subnet_group_name = aws_elasticache_subnet_group.dades.name
security_group_ids = [aws_security_group.redis.id]
}
resource "aws_s3_bucket" "fotos" {
bucket = "km0-fotos-${var.entorn}"
}
resource "aws_s3_bucket_versioning" "fotos" { # versionat, com a MinIO (04-03)
bucket = aws_s3_bucket.fotos.id
versioning_configuration { status = "Enabled" }
}
resource "aws_s3_bucket_public_access_block" "fotos" { # mai públic: se serveix per URL presignada o CDN
bucket = aws_s3_bucket.fotos.id
block_public_acls = true, block_public_policy = true, ignore_public_acls = true, restrict_public_buckets = true
}
resource "aws_s3_bucket_lifecycle_configuration" "fotos" {
bucket = aws_s3_bucket.fotos.id
rule {
id = "versions-antigues"
status = "Enabled"
noncurrent_version_expiration { noncurrent_days = 30 } # la regla de cicle de vida de 04-03
}
}
resource "aws_s3_bucket_replication_configuration" "fotos_dr" { # CRR a la regió secundària (pilot light)
bucket = aws_s3_bucket.fotos.id
role = aws_iam_role.replicacio_s3.arn
rule {
id = "dr"
status = "Enabled"
destination { bucket = aws_s3_bucket.fotos_dr.arn, storage_class = "STANDARD_IA" }
}
}Bloc 6: IAM roles per a service accounts (IRSA)
Els Pods de cataleg necessiten escriure a km0-fotos; els de comandes, llegir els seus secrets. En lloc de credencials de llarga durada en un Secret de Kubernetes (el que 06-04 evitava amb Vault), EKS permet associar un rol IAM a una service account de Kubernetes: el Pod obté credencials temporals automàticament, amb el mínim privilegi, i CloudTrail registra qui ha fet què. És la identitat de càrrega de treball de 06-04 (SPIFFE) amb l'IAM del proveïdor.
data "aws_iam_policy_document" "cataleg_fotos" {
statement {
actions = ["s3:PutObject", "s3:GetObject", "s3:DeleteObject"] # sense s3:* ni ListAllMyBuckets
resources = ["${aws_s3_bucket.fotos.arn}/fotos/*"] # només el prefix de fotos
}
}
module "irsa_cataleg" {
source = "terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts-eks"
version = "~> 5.39"
role_name = "km0-cataleg-${var.entorn}"
role_policy_arns = { fotos = aws_iam_policy.cataleg_fotos.arn }
oidc_providers = {
eks = {
provider_arn = module.eks.oidc_provider_arn
namespace_service_accounts = ["km0-prod:cataleg"] # NOMÉS aquesta service account pot assumir el rol
}
}
}Al manifest k8s/cataleg-deployment.yaml n'hi ha prou amb serviceAccountName: cataleg i l'anotació eks.amazonaws.com/role-arn: <arn del rol> a la ServiceAccount; l'SDK d'AWS al Pod (boto3, el mateix fotos.py de 04-03 apuntant a S3 en lloc de a MinIO) troba les credencials sol.
Bloc 7: sortides per als manifestos
# km0/infra/aws/outputs.tf
output "rds_inventari_endpoint" { value = aws_db_instance.inventari.address }
output "msk_bootstrap_tls" { value = aws_msk_cluster.esdeveniments.bootstrap_brokers_tls }
output "redis_endpoint" { value = aws_elasticache_replication_group.cache.primary_endpoint_address }
output "bucket_fotos" { value = aws_s3_bucket.fotos.bucket }
output "eks_cluster_name" { value = module.eks.cluster_name }Desplegar els manifestos k8s/ de 07-05 a EKS
Els manifestos no canvien de forma: canvien els valors de configuració que apunten a les dependències. A 07-05, comandes-config tenia KAFKA_BOOTSTRAP=kafka-0.kafka:9092; ara el genera el pipeline a partir de les sortides de Terraform:
# km0/infra/aws/desplegar.sh — executat pel pipeline després de 'terraform apply'
set -euo pipefail
cd km0/infra/aws
terraform init -input=false
terraform plan -var-file=entorns/prod.tfvars -out=plan.bin # el pla s'adjunta a la PR
terraform apply -input=false plan.bin
aws eks update-kubeconfig --name "$(terraform output -raw eks_cluster_name)" --region eu-west-1
# ConfigMaps amb els endpoints reals (els manifestos de 07-05 els referencien pel nom)
kubectl -n km0-prod create configmap plataforma-endpoints \
--from-literal=KAFKA_BOOTSTRAP="$(terraform output -raw msk_bootstrap_tls)" \
--from-literal=PG_INVENTARI_HOST="$(terraform output -raw rds_inventari_endpoint)" \
--from-literal=REDIS_URL="rediss://$(terraform output -raw redis_endpoint):6379" \
--from-literal=S3_BUCKET_FOTOS="$(terraform output -raw bucket_fotos)" \
--dry-run=client -o yaml | kubectl apply -f -
# Els mateixos manifestos de 07-05: Deployments, Services, HPA, PDB, NetworkPolicies, canary
kubectl apply -k km0/k8s/overlays/aws-prod # kustomize: la base de 07-05 + pedaços (serviceAccountName, tolerations spot)
kubectl -n km0-prod rollout status deployment/comandes --timeout=300sEl que desapareix de k8s/ en passar a serveis gestionats: els StatefulSets de PostgreSQL amb Patroni, de Kafka i de Redis, i els seus operadors. El que es queda: els sis serveis, Kong, el mesh, Cassandra (si no s'adopta Keyspaces), Prometheus/Loki/Tempo (si no s'adopta CloudWatch) i Mosquitto. L'HPA de 07-05 funciona igual; el que és nou és Karpenter a sota. I les proves de 07-06 es repeteixen contra l'entorn staging desplegat amb staging.tfvars (instàncies petites, sense Multi-AZ, sense DR), que s'apaga a les nits.
L'equivalent a GCP
Recurs a AWS (main.tf) |
Equivalent a GCP (proveïdor google) |
Diferència rellevant |
|---|---|---|
| VPC amb subxarxes per AZ | google_compute_network + google_compute_subnetwork (les subxarxes són regionals, abasten totes les zones) |
Menys subxarxes; la distribució per zona la fa GKE |
| EKS + grups de nodes | GKE (google_container_cluster regional + google_container_node_pool, amb Autopilot com a opció sense nodes) |
GKE regional reparteix el pla de control i els nodes en 3 zones per defecte |
| RDS Multi-AZ | Cloud SQL amb availability_type = "REGIONAL" |
Failover similar (~60 s); PITR amb point_in_time_recovery_enabled |
| MSK | Confluent Cloud (Kafka) o Pub/Sub (model diferent: sense particions ni offsets a l'estil Kafka) | Pub/Sub exigeix reescriure consumidors; Confluent conserva el codi |
| ElastiCache | Memorystore for Redis (tier = "STANDARD_HA") |
Sense mode clúster als nivells bàsics |
| S3 + CRR | GCS amb bucket dual-region o multi-region | La replicació entre regions és una propietat del bucket, no una regla |
| IRSA | Workload Identity (service account de Kubernetes ↔ service account de Google) | Mateix concepte |
| Secrets Manager + KMS | Secret Manager + Cloud KMS | Equivalent |
| EMR / MWAA / Flink gestionat | Dataproc / Cloud Composer / Dataflow | Dataflow usa el model Beam, no l'API de Flink |
| CloudWatch | Cloud Monitoring + Cloud Logging + Cloud Trace | Equivalent |
| Estat remot a S3 + DynamoDB | Backend gcs (el cadenat el dona el mateix bucket) |
Més simple |
Errors Comuns i Consells
- Suposar que "gestionat" significa "sense operar". RDS continua reiniciant a la finestra de manteniment, MSK continua necessitant dimensionar particions, i ningú no prova les restauracions per nosaltres. El treball canvia, no desapareix.
- Una sola AZ "per estalviar". Un NAT, una subxarxa, RDS sense Multi-AZ: la primera incidència d'AZ del proveïdor és una caiguda total. Multi-AZ per a tot el que sigui al camí d'una comanda.
- Oblidar l'egress i el trànsit entre AZ al pressupost. Són les dues partides que sorprenen a la primera factura. CDN per al que és públic, endpoints de VPC per a S3,
client.rackals consumidors de Kafka. - Rols IAM amb
*. Un rol de servei ambs3:*sobre tots els buckets converteix un Pod compromès en una fuita total. Una política per service account, amb accions i recursos concrets (bloc 6). - L'estat de Terraform a Git o en un portàtil. Conté secrets i és l'únic mapa del que existeix. Backend remot xifrat amb versionat i cadenat, sempre.
- Aplicar sense llegir el pla. Un
-/+sobre una base de dades és una destrucció amb recreació. El pla va a la pull request ideletion_protectiona producció. - Triar la regió només per preu o latència. Les dades personals tenen restriccions de residència; la regió és una decisió amb revisió legal, i documentada.
- Comprar reserves per al pic. Les reserves cobreixen la base que sempre està encesa; el pic va a spot o a sota demanda. Comprar de més és pagar per capacitat que no s'usa.
- Consell: desplega primer
stagingamb la mateixa configuració de Terraform i mides petites; el 90 % dels errors de xarxa, IAM i grups de seguretat apareixen allà a cost mínim. - Consell: posa el cost a Grafana al costat de la resta de mètriques (els proveïdors exporten la despesa diària per etiqueta). Un gràfic d'euros per comanda és la mètrica de negoci que més converses útils genera.
Exercicis
Exercici 1: dominis de fallada a la VPC
Revisa el main.tf de l'apartat 10 i respon: (a) si l'AZ b desapareix sencera, quins components de Quilòmetre Zero es veuen afectats, quin mecanisme recupera cadascun i en quant de temps aproximat; (b) què hauria passat amb one_nat_gateway_per_az = false; (c) quin component del main.tf no sobreviuria a la pèrdua de la regió i què caldria executar per recuperar-lo.
Exercici 2: la factura del canvi de decisió
Usant la taula de costos de l'apartat 9 (preus ficticis), calcula l'estalvi o el sobrecost mensual aproximat d'aquestes tres decisions i raona si compensen: (a) substituir MWAA per Airflow a EKS (estimat: 40 € de nodes); (b) passar km0_analitica d'RDS a Multi-AZ; (c) moure els nodes permanents d'EKS de sota demanda a una reserva de 3 anys (descompte estimat 55 % en lloc de 40 %) sabent que l'equip planeja reduir a 4 nodes permanents d'aquí a un any.
Exercici 3: lock-in selectiu
Per a cadascun d'aquests components, decideix si Quilòmetre Zero hauria d'usar el servei gestionat del proveïdor o desplegar-lo a EKS, aplicant el criteri de "lock-in selectiu" de l'apartat 6 (benefici del gestionat davant del cost de la dependència): PostgreSQL, Kafka, Cassandra, Keycloak, Vault, Prometheus/Grafana. Justifica cadascuna en dues frases.
Solucions
Exercici 1.
(a) Amb l'AZ b caiguda: RDS km0_inventari: l'standby era a b (o el primari; RDS ho decideix); si era l'standby, no passa res visible i RDS en crea un de nou en una altra AZ; si era el primari, failover automàtic a l'standby en ~60 s, durant els quals les reserves d'estoc fallen i la saga reintenta (07-04). MSK: el broker 2 cau; les particions el líder de les quals hi era trien nou líder entre les ISR (03-03) en segons; amb min.insync.replicas=2 i RF=3 es continua escrivint. Cassandra: un node de tres; amb QUORUM (2 de 3) es continua llegint i escrivint. ElastiCache: si el primari era a b, failover automàtic a la rèplica (~30 s) i la memòria cau es reomple; si era la rèplica, res. EKS: els nodes de b desapareixen; Kubernetes reprograma els seus Pods a a i c (07-05: topologySpreadConstraints garantia que cap servei no tingués totes les seves rèpliques a b) en 1-3 minuts, i Karpenter afegeix nodes si falta capacitat. ALB: deixa d'enviar a b després de fallar els health checks (segons). NAT: el de b cau, però els nodes de b també, així que ningú no el necessita.
(b) Un sol NAT a, per exemple, l'AZ a: si cau a, els nodes de b i c continuen vius però perden la sortida a Internet: pagaments no assoleix la passarel·la, el pipeline no descarrega imatges. Un component sa queda inutilitzat per un domini de fallada aliè: exactament el que 07-03 anomenava redundància no independent.
(c) Tot el de la regió primària. El que hi ha a la secundària: la rèplica d'RDS (inventari_dr), el bucket replicat i l'MSK mínim amb MirrorMaker. Per recuperar: terraform apply del mateix codi amb region = "eu-central-1" (uns 20-30 min per a VPC + EKS + ElastiCache), promoure la rèplica d'RDS (aws rds promote-read-replica, ~5 min), desplegar els manifestos apuntant als nous endpoints, restaurar Cassandra des dels snapshots replicats a S3 (el pas més llarg i el que fixa l'RPO de comandes), i canviar el registre de Route 53. És el runbook del pilot light de 07-03, i l'RTO real és el que surti al game day, no el de la taula.
Exercici 2.
(a) MWAA 320 € → Airflow a EKS 40 €: estalvi ≈ 280 €/mes (3 360 €/any). Compensa si l'equip de plataforma assumeix operar Airflow (actualitzacions, base de metadades, guàrdia); amb l'operador de Kubernetes i una instància petita d'RDS per a les metadades (~30 € més), continua compensant, i a més evita una dependència específica del proveïdor. És l'exemple que el gestionat no sempre guanya.
(b) 210 € → aproximadament el doble, ≈ 420 €: sobrecost ≈ 210 €/mes. Per a km0_analitica, la pèrdua temporal de la qual no impedeix vendre (RTO d'hores a 07-03, es reconstrueix des del llac), no compensa; la decisió de 07-03 continua sent vàlida.
(c) Base de nodes: 900 € sota demanda; amb reserva d'1 any al 40 %: 540 €; amb reserva de 3 anys al 55 %: 405 €. Diferència a favor de 3 anys: 135 €/mes. Però la reserva de 3 anys cobreix 6 nodes i d'aquí a un any només se'n faran servir 4: es pagarien 2 nodes reservats sense usar durant 2 anys (≈ 2 × 67 € × 24 mesos ≈ 3 200 €), davant d'un estalvi de 135 × 12 = 1 620 € el primer any. No compensa: reserva d'1 any, renegociable quan el dimensionament canviï. Les reserves es compren per a la base estable, i "estable" inclou el futur previsible.
Exercici 3.
- PostgreSQL → RDS (gestionat). Benefici alt (Multi-AZ, PITR, pedaços substitueixen el clúster de Patroni complet) i lock-in baix: és PostgreSQL estàndard, un
pg_dumpel mou a qualsevol lloc. - Kafka → MSK (gestionat). Benefici alt (el rolling de brokers de 07-05 i la gestió de discos desapareixen) i lock-in baix: protocol Kafka estàndard, MirrorMaker el replica a qualsevol Kafka. A GCP, Confluent abans que Pub/Sub per la mateixa raó.
- Cassandra → a EKS (o EC2), no Keyspaces. Keyspaces canvia la semàntica (transaccions lleugeres, alguns tipus, model de cost per petició) i el repositori de 04-04 necessitaria revisió: lock-in alt per a un benefici mitjà. Es manté autogestionat amb l'operador de 07-05, i es revisa si l'equip de plataforma no dona l'abast.
- Keycloak → a EKS, no Cognito. Cognito és més limitat en fluxos i personalització, i migrar usuaris i clients d'un proveïdor d'identitat és dolorós: lock-in alt. Keycloak en dues rèpliques amb RDS al darrere és fàcil d'operar.
- Vault → Secrets Manager (gestionat), amb matís. Per als secrets estàtics i la seva rotació, Secrets Manager amb IRSA és més simple i s'integra amb IAM. Les credencials dinàmiques de base de dades i la PKI per a mTLS que Vault donava a 06-04 no tenen equivalent directe: si el mesh assumeix el mTLS (08-01), Vault es pot retirar; si no, es manté Vault a EKS només per a això.
- Prometheus/Grafana → a EKS. La instrumentació de
serveis/comu/és estàndard (OpenTelemetry, exposició Prometheus) i els dashboards i alertes de 07-01 ja existeixen; CloudWatch costaria més i canviaria el llenguatge de consulta (PromQL). Lock-in evitable a cost baix. Els serveis gestionats de Prometheus/Grafana del proveïdor són un punt mitjà acceptable si l'emmagatzematge de mètriques creix.
Conclusió
El núvol converteix la infraestructura en una API, i amb això canvia tres coses en el disseny de Quilòmetre Zero. La primera és la responsabilitat: IaaS, PaaS, SaaS i FaaS mouen la línia entre el que fa el proveïdor i el que fa el client, però les dades i les identitats queden sempre en aquest costat. La segona és la geografia: regions i zones de disponibilitat són dominis de fallada amb nom, les AZ absorbeixen les fallades quotidianes amb Multi-AZ en tot el que toca una comanda, i la regió secundària del pilot light de 07-03 passa a ser codi de Terraform que no costa res mentre no s'executa. La tercera és la substitució: RDS per Patroni, MSK pels brokers d'Ansible, S3 per MinIO, EKS pel clúster propi, amb una taula que diu què es guanya i què es perd a cada fila, i un criteri de lock-in selectiu (gestionat on el benefici és alt i l'API estàndard, propi on la dependència costaria més que l'operació). Terraform descriu la VPC de tres capes per AZ, EKS amb nodes base i spot, RDS Multi-AZ amb la seva rèplica en una altra regió, MSK, ElastiCache, S3 amb versionat i replicació, i IRSA perquè cada Pod tingui només els permisos que necessita; els manifestos de 07-05 es despleguen gairebé sense canvis, i el pla de Terraform es revisa a la pull request com qualsevol codi. Els pilars de l'arquitectura ben dissenyada resumeixen el curs com a llista de comprovació, i FinOps hi afegeix el cost com a mètrica: etiquetes, reserves per a la base, spot per a Spark i els pics, pressupostos amb alerta, i una taula que mostra que el còmput és dos terços de la factura, que dos serveis gestionats costen més que els seus equivalents al clúster, i que l'egress és la partida que el disseny més pot reduir.
Precisament aquesta partida, i dues preguntes més, obren la lliçó següent. Cal un servei a Kubernetes, amb les seves rèpliques, les seves sondes i la seva guàrdia, per generar una miniatura cada vegada que la Formatgeria Montblanc puja una foto, o per produir un PDF quan arriba un pagament.confirmat? I per què les fotos de formatge-curat han de viatjar des d'Irlanda fins al mòbil de l'Anna a València a cada visita, quan podrien ser a vint quilòmetres d'ella? Funcions que existeixen només mentre hi ha un esdeveniment per processar, i còmput i memòria cau a la vora de la xarxa: Arquitectures Serverless i Edge Computing.
Curs d'Arquitectures Distribuïdes
Mòdul 1: Introducció als Sistemes Distribuïts
- Conceptes Bàsics de Sistemes Distribuïts
- Models de Sistemes Distribuïts
- Avantatges i Desafiaments dels Sistemes Distribuïts
- Les Fal·làcies de la Computació Distribuïda
- Temps, Rellotges i Ordenació d'Esdeveniments
- Del Monòlit a la Plataforma Distribuïda: el Cas Quilòmetre Zero
Mòdul 2: Comunicació en Sistemes Distribuïts
- Protocols de Comunicació
- RPC i RMI
- gRPC i Serialització de Dades
- Missatgeria i Cues de Missatges
- Patrons de Comunicació Asíncrona
Mòdul 3: Consistència i Replicació
- Models de Consistència
- El Teorema CAP i PACELC
- Algorismes de Consens
- Replicació de Dades
- Transaccions Distribuïdes i Sagues
Mòdul 4: Emmagatzematge Distribuït
- Particionament de Dades i Hashing Consistent
- Sistemes de Fitxers Distribuïts
- Emmagatzematge d'Objectes
- Bases de Dades Distribuïdes
- Memòries Cau Distribuïdes
Mòdul 5: Computació Distribuïda
- Models de Computació Distribuïda
- MapReduce i Hadoop
- Spark i Computació en Memòria
- Processament de Fluxos de Dades
- Planificació de Treballs i Pipelines de Dades
Mòdul 6: Seguretat en Sistemes Distribuïts
- Autenticació i Autorització
- Xifratge i Protecció de Dades
- Gestió d'Identitats
- Seguretat entre Serveis: mTLS i Gestió de Secrets
- Passarel·les d'API, Limitació de Taxa i Auditoria
Mòdul 7: Monitoratge i Manteniment
- Monitoratge de Sistemes Distribuïts
- Logs Centralitzats i Traçabilitat Distribuïda
- Gestió de Fallades i Recuperació
- Patrons de Resiliència: Timeouts, Reintents i Circuit Breaker
- Automatització i Orquestració
- Proves en Sistemes Distribuïts i Enginyeria del Caos
