A 10-02 vam muntar un clúster amb kubeadm i vam descobrir tot el que implica: preparar màquines, configurar containerd, generar certificats que caduquen a l'any, mantenir el quòrum d'etcd, assajar restauracions i actualitzar node a node. Vam acabar amb un advertiment clar: operar això en producció exigeix un equip dedicat amb guàrdia.
A 10-05 vam muntar GitOps, i ara tot l'estat de la plataforma Rutas Norte viu a Git. Això planteja una pregunta natural: si el clúster és reemplaçable i es reconstrueix sol, per què l'hauríem de mantenir nosaltres?
Aquesta lliçó respon a aquesta pregunta. Veurem què gestiona el proveïdor i què continua sent teu, compararem EKS, AKS i GKE en els criteris que de debò decideixen, tancarem la federació d'identitat que vam deixar pendent a 03-06, aprofitarem les instàncies interrompibles per a les càrregues tolerants de Rutas Norte, i acabarem amb una recomanació raonada.
Contingut
- El model de responsabilitat compartida
- Comparació d'EKS, AKS i GKE
- Identitat: IRSA i Workload Identity
- Nodes: grups gestionats, plantilles i instàncies interrompibles
- Què canvia en el que ja saps
- Actualització de versió d'un clúster gestionat
- Cost real i palanques d'estalvi
- Portabilitat i dependència del proveïdor
- La decisió per a Rutas Norte
- Errors comuns i consells
- Exercicis
- Conclusió
- El model de responsabilitat compartida
Un clúster gestionat no és "Kubernetes sense feina". És una frontera diferent entre el que fa el proveïdor i el que fas tu.
flowchart TB
subgraph prov["Responsabilitat del proveïdor"]
P1[apiserver, scheduler,<br/>controller-manager]
P2[etcd: rèpliques,<br/>còpies, xifratge]
P3[Certificats<br/>del pla de control]
P4[Alta disponibilitat<br/>entre zones]
P5[Pedaços del pla<br/>de control]
end
subgraph teva["Responsabilitat teva"]
T1[Càrregues de treball<br/>i els seus recursos]
T2[Nodes: tipus, mida,<br/>pedaços del SO]
T3[Xarxa: VPC, subxarxes,<br/>NetworkPolicies]
T4[RBAC, PSS,<br/>secrets]
T5[Cost]
T6[Còpies de les DADES]
end
style prov fill:#e8ffe8
style teva fill:#fff4e8
La taula completa, contrastada amb kubeadm
| Responsabilitat | kubeadm (10-02) | Gestionat |
|---|---|---|
| Màquines del pla de control | Teva | Del proveïdor |
| apiserver, scheduler, controller-manager | Teva | Del proveïdor |
| etcd: desplegament, quòrum, còpies | Teva (etcdctl snapshot) |
Del proveïdor |
| Certificats del pla de control | Teva (kubeadm certs renew, caduquen a l'any) |
Del proveïdor |
| Alta disponibilitat del pla de control | Teva (HAProxy, 3 nodes) | Del proveïdor |
| Actualització del pla de control | Teva (kubeadm upgrade apply) |
Del proveïdor (tu tries quan) |
| Escalat del pla de control amb la càrrega | Teva | Del proveïdor |
| Registre d'auditoria de l'apiserver | Teva (configurar) | Del proveïdor (tu l'actives) |
| Sistema operatiu dels nodes | Teva | Teva (imatges del proveïdor, tu apliques) |
| Actualització del kubelet als nodes | Teva | Teva (assistida) |
| CNI | Teva (instal·lar Calico) | Del proveïdor per defecte, canviable per tu |
| Càrregues de treball, sondes, recursos | Teva | Teva |
| RBAC, Pod Security Standards, polítiques | Teva | Teva |
| NetworkPolicies | Teva | Teva |
| Secrets i la seva gestió | Teva | Teva |
| Còpies de les dades de les aplicacions | Teva (Velero, 05-06) | Teva (Velero) |
| Monitoratge de les aplicacions | Teva (Prometheus, 07-03) | Teva |
| Cost | Teva | Teva |
| Compliment normatiu i dades personals | Teva | Teva |
El que cal entendre
El pla de control desapareix de les teves preocupacions. Els certificats que caduquen a l'any, el quòrum d'etcd, els snapshots, l'HAProxy davant dels tres nodes de control: tot això se'n va. És aproximadament la meitat de la lliçó 10-02.
Tota la resta continua igual. Els nodes continuen sent teus, amb el seu sistema operatiu que cal pedaçar. El RBAC continua sent teu. Les NetworkPolicies continuen sent teves. I si postgres-reserves perd dades, és el teu problema, no el del proveïdor.
Un error molt freqüent: "està gestionat, així que les còpies estan fetes". Fals. El proveïdor fa còpia d'etcd (la definició dels objectes), no dels volums de les teves aplicacions. De les dades de clients de postgres-reserves en fas la còpia tu, amb Velero o amb els snapshots del proveïdor. Ho vam veure a 05-06 i continua sent així.
La regla d'or: un clúster gestionat et treu la meitat de la feina d'operació de Kubernetes. L'altra meitat, la que has estudiat als mòduls 2 a 9, continua sent íntegrament teva.
- Comparació d'EKS, AKS i GKE
Cost del pla de control
| EKS | AKS | GKE | |
|---|---|---|---|
| Cost mensual del pla de control | ~73 $ per clúster | 0 $ al nivell gratuït; ~73 $ amb SLA | ~73 $ per clúster (un de gratuït per compte) |
| SLA inclòs | 99,95 % | Només amb el nivell estàndard | 99,95 % (regional) / 99,5 % (zonal) |
| S'aplica a cada clúster? | Sí | Sí | Sí, tret del primer |
Amb tres entorns separats en clústers diferents, això són uns 220 $/mes només per existir. És una de les raons per les quals moltes empreses separen entorns per namespace dins d'un clúster (com fa Rutas Norte) en comptes de per clúster.
Avís: el nivell gratuït d'AKS no té SLA financer. Per a rutas-norte-pro això pot ser inacceptable, i llavors el cost s'iguala.
Cicle de versions i finestra de suport
| EKS | AKS | GKE | |
|---|---|---|---|
| Versions menors suportades | ~4 simultànies | ~3 | Depèn del canal |
| Suport estàndard | 14 mesos | 12 mesos | 14 mesos (canal normal) |
| Suport estès (de pagament) | Sí, fins a 26 mesos | Sí | Sí |
| Actualització automàtica | Només del pedaç | Configurable | Sí, per canals |
| Canals de versió | No | No | Ràpid, normal, estable |
El sistema de canals de GKE és una diferència real d'operació: tries "estable" i Google manté el clúster en una versió provada, actualitzant-lo a la finestra de manteniment que li indiquis. És el més a prop que s'està de no pensar en versions.
A EKS i AKS, el cicle és més manual. I si deixes caducar la versió, tots dos acaben forçant l'actualització, cosa que és pitjor que planificar-la.
Model de xarxa i assignació d'IP als pods
Aquesta és la diferència tècnica més important i menys coneguda, i la que provoca sorpreses serioses en producció.
| EKS (VPC CNI) | AKS (Azure CNI) | AKS (kubenet) | GKE (natiu de VPC) | |
|---|---|---|---|---|
| IP del pod | Real de la VPC | Real de la xarxa virtual | Superposada amb NAT | Real de la VPC (àlies) |
| Consumeix IP de la teva xarxa? | Sí, una per pod | Sí, una per pod | No | Sí, d'un rang secundari |
| Pods per node | Limitat pel tipus d'instància | Configurable, reserva per endavant | Alt | Configurable |
| Rendiment | Natiu, sense superposició | Natiu | NAT, més latència | Natiu |
| Recursos externs arriben al pod directament | Sí | Sí | No | Sí |
El problema que això causa a la pràctica: a EKS, cada pod consumeix una IP real de la teva VPC. Una instància t3.medium admet 3 interfícies de xarxa amb 6 IP cadascuna: 17 pods màxim, independentment que tingui CPU i memòria lliures. Si la teva subxarxa és un /24 (254 adreces), et quedes sense IP per a pods molt abans de quedar-te sense CPU.
# A EKS: comprovar el límit real de pods d'un node
kubectl get node ip-10-0-1-42.eu-west-1.compute.internal \
-o jsonpath='{.status.allocatable.pods}{"\n"}'I el símptoma quan s'esgota:
Warning FailedCreatePodSandBox 2m kubelet
Failed to create pod sandbox: plugin type="aws-cni" failed:
add cmd: failed to assign an IP address to containerUn pod Pending sense que falti CPU ni memòria. Desconcertant si no coneixes el model.
Mitigacions a EKS: activar el mode de prefixos delegats (ENABLE_PREFIX_DELEGATION), que multiplica per 16 les IP disponibles per interfície; fer servir instàncies més grans; o planificar rangs de VPC generosos des del principi (un /16, no un /24).
A AKS amb Azure CNI clàssic, cal reservar per endavant maxPods × nombre de nodes adreces. Si planifiques malament, no pots escalar. La variant "superposició" (Azure CNI Overlay) resol això i és la recomanada avui.
A GKE amb natiu de VPC, es fan servir rangs secundaris d'IP àlies, cosa que separa l'adreçament de pods del de nodes. És el model més net dels tres.
Integració d'identitat
| EKS | AKS | GKE | |
|---|---|---|---|
| Mecanisme | IRSA (IAM Roles for Service Accounts) o Pod Identity | Workload Identity (basat en Entra ID) | Workload Identity Federation |
| Base | Token OIDC projectat al pod | Token OIDC | Token OIDC |
| Maduresa | Molt alta (des de 2019) | Alta | Molt alta (el més antic) |
| Complexitat de configuració | Mitjana | Mitjana | Baixa |
Els tres han convergit en el mateix mecanisme: OIDC. El detallem a l'apartat 3.
Grups de nodes i modes automàtics
| EKS | AKS | GKE | |
|---|---|---|---|
| Grups gestionats | Sí | Sí (agrupacions de nodes) | Sí (agrupacions) |
| Mode sense gestió de nodes | Fargate (per pod) | Nodes virtuals (ACI) | Autopilot |
| Autoescalador de nodes | Cluster Autoscaler o Karpenter | Cluster Autoscaler o NAP | Integrat o aprovisionament automàtic |
| Aprovisionament automàtic de tipus | Amb Karpenter | Sí (NAP) | Sí |
GKE Autopilot mereix menció a part: és un mode en què no hi ha nodes en absolut des del teu punt de vista. Declares pods amb les seves requests i pagues exactament per això. No hi ha nodes per pedaçar ni per dimensionar, no hi ha DaemonSets propis, no hi ha hostPath ni privilegis. És Kubernetes reduït a la seva interfície de càrregues de treball.
- A favor: zero operació de nodes, facturació exacta pel sol·licitat, seguretat reforçada per defecte.
- En contra: restriccions fortes (no pots executar Falco de 08-06 tal com és, ni certs DaemonSets), cost per unitat més gran si els teus pods estan mal dimensionats, menys control.
AWS Fargate és similar però més limitat: no admet DaemonSets en absolut, no admet emmagatzematge persistent en bloc, ni privileged. Per a worker-notificacions pot encaixar; per a postgres-reserves, no.
Autoescalat
| EKS | AKS | GKE | |
|---|---|---|---|
| Cluster Autoscaler | L'instal·les tu | Integrat, s'activa | Integrat |
| Alternativa avançada | Karpenter (recomanada) | NAP | Aprovisionament automàtic |
| Velocitat d'arrencada de node | 40-90 s (Karpenter: ~40 s) | 60-120 s | 40-80 s |
| Elecció automàtica del tipus d'instància | Karpenter sí | NAP sí | Sí |
Recordant 09-03: Karpenter no treballa amb grups de nodes predefinits, sinó que tria el tipus d'instància òptim per als pods pendents. Si informes-ocupacio necessita 8 CPU un cop per nit, Karpenter aixeca la instància justa, la fa servir i la retira. És una diferència notable de cost i de velocitat.
Complements gestionats i ecosistema
| Complement | EKS | AKS | GKE |
|---|---|---|---|
| CNI | Gestionat (VPC CNI) | Gestionat | Gestionat |
| CoreDNS, kube-proxy | Gestionats | Gestionats | Gestionats |
| Controlador CSI | Gestionat | Gestionat | Gestionat |
| Controlador d'Ingress | AWS Load Balancer Controller (l'instal·les) | Application Gateway (gestionat) | GKE Ingress (natiu) |
| Mètriques i registres | CloudWatch Container Insights | Azure Monitor | Cloud Operations (el més integrat) |
| Malla de serveis | App Mesh (en retirada) / Istio | Istio gestionat | Anthos Service Mesh |
| Escaneig d'imatges | ECR scanning | Defender for Containers | Artifact Analysis |
| Política | Cap de nativa | Azure Policy | Policy Controller |
Taula resum
| Criteri | EKS | AKS | GKE |
|---|---|---|---|
| Cost del pla de control | Mitjà | Baix (gratis sense SLA) | Mitjà (1 de gratuït) |
| Finestra de suport | Llarga (14 m) | Mitjana (12 m) | Llarga (14 m) |
| Model de xarxa | IP real, límit per instància | Flexible, requereix planificació | El més net |
| Identitat | IRSA, molt madur | Workload Identity | El més senzill |
| Autoescalat | Karpenter, el millor | Bo | Molt bo |
| Mode sense nodes | Fargate (limitat) | Nodes virtuals | Autopilot, el millor |
| Facilitat d'operació | Mitjana | Mitjana-alta | Alta |
| Ecosistema i eines | El més gran | Bo | Molt bo |
| Integració amb la resta del núvol | Molt bona | Excel·lent si ja fas servir Microsoft | Molt bona |
| Corba d'aprenentatge | Alta (IAM d'AWS) | Mitjana | Baixa |
Conclusió honesta: la millor elecció gairebé sempre és el núvol on ja hi ha la resta de la teva infraestructura. La diferència tècnica entre els tres és menor que el cost d'operar en dos núvols alhora. Si comences de zero i només mires Kubernetes, GKE és el més polit; si la teva empresa ja viu a AWS, EKS amb Karpenter és excel·lent; si la teva empresa és un entorn Microsoft, AKS s'integra sense fricció.
- Identitat: IRSA i Workload Identity
Tanquem aquí el que va quedar anunciat a 03-06.
El problema
api-reserves necessita llegir un fitxer de tarifes d'un bucket d'emmagatzematge i publicar missatges en una cua. La forma tradicional:
# LA FORMA DOLENTA. No ho facis.
apiVersion: v1
kind: Secret
metadata:
name: credencials-nuvol
stringData:
ACCES_ID: "AKIAIOSFODNN7EXAMPLE"
ACCES_SECRET: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"Problemes: la credencial és permanent, cal rotar-la a mà, està en un Secret (base64, no xifrat, 03-02), i si es filtra serveix des de qualsevol lloc del món.
La solució: federació OIDC
Els tres proveïdors convergeixen en el mateix mecanisme. El clúster exposa un emissor OIDC; el kubelet projecta al pod un token signat de curta durada amb la identitat de la ServiceAccount; el proveïdor de núvol confia en aquest emissor i bescanvia el token per credencials temporals.
sequenceDiagram
participant P as Pod api-reserves
participant K as kubelet
participant O as Emissor OIDC<br/>del clúster
participant I as IAM del proveïdor
participant S as Bucket / Cua
K->>O: sol·licita token per a la SA
O-->>K: token JWT signat (1 h)
K->>P: el projecta a<br/>/var/run/secrets/.../token
P->>I: "bescanvia aquest token per credencials"
I->>O: verifica la signatura contra les claus públiques
I-->>P: credencials temporals (15 min - 1 h)
P->>S: hi accedeix amb aquestes credencials
Cap credencial permanent. Res a rotar. El token es renova sol i només serveix per a aquella ServiceAccount en aquell clúster.
IRSA a EKS
# 1. Crear el proveïdor d'identitat OIDC del clúster (una sola vegada)
eksctl utils associate-iam-oidc-provider --cluster rutas-norte-pro --approve
# 2. Crear el rol i associar-lo a la ServiceAccount
eksctl create iamserviceaccount --name api-reserves --namespace rutas-norte-pro \
--cluster rutas-norte-pro \
--attach-policy-arn arn:aws:iam::123456789012:policy/RutasNorteTarifesLectura --approveLa màgia és a la política de confiança del rol, la condició de la qual limita qui el pot assumir:
"Condition": { "StringEquals": {
"oidc.eks.eu-west-1.amazonaws.com/id/EXAMPLE...:sub":
"system:serviceaccount:rutas-norte-pro:api-reserves",
"oidc.eks.eu-west-1.amazonaws.com/id/EXAMPLE...:aud": "sts.amazonaws.com"
}}Fixa't en sub: només la ServiceAccount api-reserves del namespace rutas-norte-pro pot assumir aquest rol. Ni una altra SA, ni la mateixa SA en un altre namespace.
# El manifest que va a Git: una anotació, cap secret
apiVersion: v1
kind: ServiceAccount
metadata:
name: api-reserves
namespace: rutas-norte-pro
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/RutasNorteApiReservesAl Deployment n'hi ha prou amb serviceAccountName: api-reserves: sense variables de credencials, perquè l'SDK del proveïdor detecta el token projectat automàticament. Pots verificar-ho amb kubectl exec ... -- ls /var/run/secrets/eks.amazonaws.com/serviceaccount/.
Nota: AWS ha introduït EKS Pod Identity, més senzill (una associació a l'API d'EKS, sense proveïdor OIDC ni anotació). És l'opció recomanada per a clústers nous; IRSA continua sent necessària si la càrrega corre fora d'EKS.
Workload Identity a GKE i a AKS
El mecanisme és el mateix; canvien les ordres i l'anotació.
# --- GKE ---
gcloud container clusters update rutas-norte-pro \
--workload-pool=rutas-norte-projecte.svc.id.goog --region=europe-west1
gcloud iam service-accounts create rn-api-reserves
gcloud iam service-accounts add-iam-policy-binding \
[email protected] \
--role roles/iam.workloadIdentityUser \
--member "serviceAccount:rutas-norte-projecte.svc.id.goog[rutas-norte-pro/api-reserves]"
# --- AKS ---
az aks update -g rutas-norte -n rutas-norte-pro --enable-oidc-issuer --enable-workload-identity
EMISSOR=$(az aks show -g rutas-norte -n rutas-norte-pro --query "oidcIssuerProfile.issuerUrl" -otsv)
az identity create -g rutas-norte -n rn-api-reserves
az identity federated-credential create --name rn-api-reserves-fed \
--identity-name rn-api-reserves --resource-group rutas-norte --issuer "${EMISSOR}" \
--subject "system:serviceaccount:rutas-norte-pro:api-reserves"| EKS (IRSA) | AKS | GKE | |
|---|---|---|---|
| Anotació a la SA | eks.amazonaws.com/role-arn |
azure.workload.identity/client-id |
iam.gke.io/gcp-service-account |
| Requisit extra al pod | Cap | Etiqueta azure.workload.identity/use: "true" |
Cap |
| Passos de configuració | 3 | 4 | 3 |
| Durada de les credencials | 15 min - 12 h | 1 h | 1 h |
| Alternativa més simple | EKS Pod Identity | — | — |
L'important per a tu: en els tres casos, el manifest que va a Git conté una anotació amb un identificador, mai un secret. És exactament el model que buscàvem a 03-06 i que encaixa perfectament amb GitOps (10-05).
- Nodes: grups gestionats, plantilles i instàncies interrompibles
Grups de nodes gestionats
Un grup de nodes gestionat és un conjunt de màquines homogènies que el proveïdor manté: les crea, les uneix al clúster, les actualitza de forma gradual i les substitueix si fallen.
# Exemple amb eksctl per a Rutas Norte
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata: { name: rutas-norte-pro, region: eu-west-1, version: "1.30" }
managedNodeGroups:
# Grup general: càrregues que serveixen trànsit de clients
- name: general
instanceType: m6i.large
minSize: 3
maxSize: 12
desiredCapacity: 4
availabilityZones: [eu-west-1a, eu-west-1b, eu-west-1c] # repartiment real (09-05)
volumeSize: 60
volumeType: gp3
updateConfig: { maxUnavailablePercentage: 25 }
# Grup interrompible: càrregues tolerants a interrupció
- name: interrompible
instanceTypes: [m6i.large, m5.large, m5a.large, m6a.large]
spot: true # <-- instàncies interrompibles
minSize: 0
maxSize: 20
labels: { rutasnorte.example/interrompible: "true" }
taints:
# Res no es planifica aquí tret que ho toleri explícitament
- { key: rutasnorte.example/interrompible, value: "true", effect: NoSchedule }Fixa't en instanceTypes amb quatre tipus al grup interrompible: com més tipus acceptes, menor és la probabilitat que el proveïdor no tingui capacitat i t'ho interrompi tot alhora.
Instàncies interrompibles (spot)
Són capacitat sobrant del proveïdor a un 60-90 % de descompte, amb una contrapartida: el proveïdor la pot reclamar amb un avís de 2 minuts (AWS), 30 segons (Azure) o 30 segons (GCP).
| Càrrega de Rutas Norte | Apta per a spot? | Per què |
|---|---|---|
botiga-web |
No | De cara al client; una interrupció és una venda perduda |
api-reserves |
No | Igual, i a més manté sessions de reserva |
postgres-reserves |
Rotundament no | Estat crític; una interrupció durant una escriptura és un risc |
redis-cache |
Amb compte | És memòria cau, però perdre-la de cop provoca una allau sobre la base de dades |
worker-notificacions |
Sí | Processa una cua; si un pod mor, el missatge torna a la cua |
informes-ocupacio |
Sí | CronJob nocturn; si falla, reintenta |
Els manifestos, amb el que hem après a 06-05 i 09-05 (el detall complet és a la solució de l'exercici 1):
spec:
# 1. TOLERAR el taint del grup interrompible
tolerations:
- { key: rutasnorte.example/interrompible, operator: Equal,
value: "true", effect: NoSchedule }
# 2. PREFERIR nodes interrompibles, però acceptar els normals si no
# hi ha capacitat (preferredDuringScheduling, NO required)
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- { key: rutasnorte.example/interrompible, operator: In, values: ["true"] }
# 3. REPARTIR entre zones: una zona sencera es pot quedar sense
# capacitat interrompible de cop
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels: { app: worker-notificacions }
# 4. Marge per acabar el missatge en curs dins de l'avís
terminationGracePeriodSeconds: 90
containers:
- name: worker
lifecycle:
preStop:
exec: { command: ["/app/drenar", "--espera", "60s"] }I un PDB amb minAvailable: 1, perquè encara que siguin interrompibles, no volem que caiguin tots alhora (09-05).
Matís important sobre el PDB: un PodDisruptionBudget protegeix davant d'interrupcions voluntàries (drenatge d'un node per actualitzar-lo). Una interrupció d'una instància spot és involuntària: el proveïdor s'emporta la màquina, amb PDB o sense. El PDB ajuda perquè els gestors de terminació (AWS Node Termination Handler, o el maneig natiu de Karpenter) cordonen i drenen el node en rebre l'avís, i aquell drenatge sí que respecta el PDB.
informes-ocupacio, en ser un CronJob nocturn (06-03), és un cas encara més clar: a més de la toleration pot portar un nodeSelector dur sobre rutasnorte.example/interrompible: "true" —si no hi ha capacitat, esperar és acceptable— i un backoffLimit: 6 generós, perquè la interrupció és esperable.
Karpenter: l'alternativa moderna a EKS
En lloc de definir grups amb tipus fixos, declares restriccions i Karpenter tria:
apiVersion: karpenter.sh/v1
kind: NodePool
metadata: { name: rutas-norte-lots }
spec:
template:
spec:
taints:
- { key: rutasnorte.example/interrompible, value: "true", effect: NoSchedule }
requirements:
- { key: karpenter.sh/capacity-type, operator: In, values: ["spot"] }
- { key: kubernetes.io/arch, operator: In, values: ["amd64", "arm64"] } # ARM és més barat
- { key: karpenter.k8s.aws/instance-category, operator: In, values: ["c", "m", "r"] }
- { key: topology.kubernetes.io/zone, operator: In,
values: ["eu-west-1a", "eu-west-1b", "eu-west-1c"] }
nodeClassRef: { group: karpenter.k8s.aws, kind: EC2NodeClass, name: predeterminat }
limits: { cpu: "200", memory: 400Gi }
disruption:
# Consolidar: si els pods caben en menys nodes, migrar-los i
# retirar els sobrants. Estalvi directe.
consolidationPolicy: WhenEmptyOrUnderutilized
consolidateAfter: 60s
expireAfter: 720h # renovar nodes cada 30 diesDiferències amb el Cluster Autoscaler (09-03):
| Cluster Autoscaler | Karpenter | |
|---|---|---|
| Com decideix | Escala grups predefinits | Tria la instància òptima per als pods pendents |
| Tipus d'instància | Els del grup | Centenars, segons les restriccions |
| Velocitat | 60-120 s | ~40 s |
| Consolidació | Limitada | Activa i agressiva |
| Interrupció de spot | Amb un manejador a part | Integrada |
| Disponibilitat | Els tres proveïdors | Només AWS (i Azure en desenvolupament) |
- Què canvia en el que ja saps
Aquest apartat repassa les lliçons anteriors del curs i assenyala què és diferent al núvol.
La StorageClass (05-04)
A minikube fèiem servir standard, un directori del node. Al núvol:
# EKS amb EBS gp3
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata: { name: rutas-norte-ssd }
provisioner: ebs.csi.aws.com
parameters: { type: gp3, iops: "6000", throughput: "250", encrypted: "true" }
allowVolumeExpansion: true
# CRÍTIC: el volum no es crea fins que el pod es planifica,
# perquè es creï a la MATEIXA zona que el node.
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Retain| Aspecte | Local | Núvol |
|---|---|---|
| Modes d'accés | Tot "funciona" amb un node | ReadWriteOnce de debò: un disc de bloc només es munta en una màquina |
ReadWriteMany |
Amb hostPath, sí | Requereix sistema de fitxers compartit (EFS, Azure Files, Filestore), més car i més lent |
| Zones | No existeixen | Un disc pertany a una zona. Si el pod es planifica en una altra, no arrenca |
| Expansió | De vegades no | Sí, en calent |
| Xifratge en repòs | No | Sí, amb claus gestionades |
| Cost | 0 | Per GB/mes i per IOPS |
L'error clàssic: postgres-reserves amb volumeBindingMode: Immediate crea el disc a eu-west-1a; el planificador col·loca el pod a eu-west-1c; el pod es queda Pending per sempre amb volume node affinity conflict. Solució: WaitForFirstConsumer, que és el valor que porten per defecte les StorageClass dels tres proveïdors.
El Service de tipus LoadBalancer (04-02)
En local es quedava a <pending> i calia minikube tunnel. Al núvol funciona de debò:
apiVersion: v1
kind: Service
metadata:
name: ingress-nginx-controller
namespace: ingress-nginx
annotations:
# Balancejador de xarxa (capa 4), més ràpid i barat que el de capa 7
service.beta.kubernetes.io/aws-load-balancer-type: "external"
service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: "ip"
service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing"
spec:
type: LoadBalancer
# Conservar la IP real del client. Sense això, els registres i el
# limitador de taxa veuen la IP del node, no la de l'usuari.
externalTrafficPolicy: LocalCoses per aprendre:
- Cada Service de tipus LoadBalancer costa diners (uns 20-25 $/mes més el trànsit). Per això se'n fa servir un de sol per al controlador d'Ingress i tota la resta va per regles d'Ingress (04-04).
- Les anotacions són específiques de cada proveïdor. Són la part menys portable dels teus manifestos (apartat 8).
- Esborrar el Service esborra el balancejador. I si el balancejador té un registre DNS apuntant-hi, es trenca.
externalTrafficPolicy: Localconserva la IP del client però requereix que hi hagi un pod a cada node amb endpoints; si no, el trànsit a aquell node es descarta.
Els tres proveïdors ofereixen a més un controlador d'Ingress gestionat (AWS Load Balancer Controller, Application Gateway Ingress Controller, GKE Ingress) que crea un balancejador de capa 7 directament des de l'objecte Ingress. És còmode, però et lliga més al proveïdor que ingress-nginx.
Registres d'imatges (08-05)
| Proveïdor | Registre | Escaneig | Autenticació des del clúster |
|---|---|---|---|
| AWS | ECR | Bàsic o millorat (Inspector) | Per rol del node o IRSA, sense imagePullSecrets |
| Azure | ACR | Defender for Containers | Vinculació directa amb AKS |
| GCP | Artifact Registry | Artifact Analysis | Per compte de servei del node |
L'avantatge pràctic: desapareix l'imagePullSecrets. El node s'autentica amb la seva identitat de núvol. Un Secret menys per gestionar.
I s'integra amb el de 08-05: la signatura amb Cosign i la política d'admissió funcionen igual, amb l'avantatge que els tres registres ofereixen escaneig automàtic que alimenta el que hem après a 08-06.
Mètriques i registres (07-03, 07-05)
| Prometheus propi | Servei del proveïdor | |
|---|---|---|
| Cost | El de l'emmagatzematge i els nodes | Per mètrica o per GB ingerit |
| Retenció llarga | Requereix Thanos o Mimir | Inclosa |
| Consultes PromQL | Sí | AWS i GCP sí (compatibles); Azure amb KQL |
| Portabilitat | Total | Nul·la |
| Operació | Teva | Del proveïdor |
| Correlació amb la resta del núvol | Manual | Nativa |
Consell pragmàtic: mantenir Prometheus (07-03) per a les mètriques de les aplicacions, perquè les teves alertes i panells són portables, i fer servir el servei del proveïdor per als registres (07-05), perquè operar EFK a escala és car i dolorós, i el cost del servei gestionat sol sortir a compte. És la combinació que tria la majoria d'equips.
Compte amb el cost dels registres: api-reserves amb LOG_LEVEL=debug en producció pot generar centenars de GB al mes. Els tres proveïdors cobren per ingesta.
- Actualització de versió d'un clúster gestionat
Comparat amb el procediment de kubeadm (10-02), això és un passeig. Però continua exigint planificació, i qui ho tracta com un botó s'emporta un disgust.
# EKS: pla de control i grups de nodes, per separat
aws eks update-cluster-version --name rutas-norte-pro --kubernetes-version 1.31
aws eks update-nodegroup-version --cluster-name rutas-norte-pro --nodegroup-name general
# AKS
az aks upgrade -g rutas-norte -n rutas-norte-pro --kubernetes-version 1.31.1
# GKE
gcloud container clusters upgrade rutas-norte-pro --master --cluster-version 1.31.1
gcloud container clusters upgrade rutas-norte-pro --node-pool generalPer què continua exigint planificació
1. Les APIs eliminades continuen sent el teu problema. Si un manifest de k8s/base fa servir una API que desapareix a 1.31, el clúster s'actualitza i la teva aplicació deixa de desplegar-se.
# Abans d'actualitzar, SEMPRE
kubectl get --raw /metrics | grep apiserver_requested_deprecated_apis
# I escanejar els manifestos
kubent --context rutas-norte-pro
pluto detect-files -d k8s/2. Els complements de tercers tenen les seves pròpies matrius de compatibilitat. cert-manager, ingress-nginx, KEDA, Prometheus Operator, el controlador CSI: cadascun suporta un rang de versions. Una actualització del clúster sense actualitzar-los els pot trencar.
| Complement | Comprovar abans |
|---|---|
| cert-manager | Matriu de compatibilitat del projecte |
| ingress-nginx | Taula de versions suportades |
| KEDA | Versió mínima de Kubernetes |
| Prometheus Operator | Versió de les CRDs |
| Argo CD | Versió suportada de l'apiserver |
| Controlador CSI del proveïdor | Versió del complement gestionat |
3. L'actualització dels nodes reinicia tots els pods. El proveïdor drena cada node per torns. Això exercita:
- Els teus PodDisruptionBudgets (09-05): si estan mal configurats, el drenatge es bloqueja o, pitjor, se salta amb
--force. - Les teves sondes de readiness (07-01): si
api-reservestriga 45 segons a estar llest i el drenatge va ràpid, hi ha tall. - El teu
terminationGracePeriodSecondsi el teu hookpreStop. - La teva capacitat d'absorbir la pèrdua temporal d'un node: si el clúster està al 95 % d'ocupació, drenar un node deixa pods
Pending.
4. El pla de control i els nodes s'actualitzen per separat, i cal respectar el desfasament de versions (10-02): nodes com a molt 3 menors per sota de l'apiserver, i mai per sobre.
Procediment recomanat per a Rutas Norte
1. Llegir les notes de la versió i les APIs eliminades.
2. Executar kubent/pluto sobre k8s/ i corregir el que surti.
3. Revisar la matriu de compatibilitat de cada complement;
actualitzar els que calgui ABANS.
4. Actualitzar rutas-norte-dev. Esperar una setmana d'ús normal.
5. Actualitzar rutas-norte-pre. Executar les proves de càrrega amb k6 (09-06).
6. Verificar que els PDB permeten el drenatge:
kubectl get pdb -A -o wide
kubectl drain <un-node> --dry-run=server
7. Finestra de manteniment a rutas-norte-pro:
a. Pla de control primer.
b. Verificar que tot continua Synced i Healthy a Argo CD.
c. Un grup de nodes cada vegada, amb maxUnavailable baix.
d. Vigilar els panells de Grafana durant el procés.
8. Actualitzar la versió declarada a l'script local de 10-01
perquè l'equip desenvolupi contra la mateixa versió.Aquest últim punt tanca el cercle amb la primera lliçó del mòdul: l'entorn local ha de seguir producció.
- Cost real i palanques d'estalvi
De què es compon la factura
| Concepte | Pes típic | Comentari |
|---|---|---|
| Nodes (còmput) | 50-70 % | La partida gran, gairebé sempre |
| Emmagatzematge | 10-20 % | Discos dels PV, snapshots, registres |
| Trànsit de xarxa | 5-20 % | Sortida a internet i entre zones |
| Balancejadors | 5-10 % | ~20-25 $/mes cadascun |
| Pla de control | 2-5 % | ~73 $/mes per clúster |
| Serveis gestionats | Variable | Mètriques, registres, escaneig |
Una sorpresa habitual: el trànsit entre zones de disponibilitat es cobra. Si api-reserves és a la zona A i postgres-reserves a la zona B, cada consulta creua una frontera facturada. Amb volum alt, això són centenars d'euros al mes. És un argument a favor de l'afinitat de zona... que xoca amb l'alta disponibilitat de 09-05. És un compromís real que cal decidir conscientment.
Les palanques, per ordre de rendibilitat
1. Dimensionar bé (el que hem après a 09-02). És la palanca amb millor relació esforç/estalvi, i gairebé ningú la fa servir. El patró típic: algú va posar requests: {cpu: 1, memory: 2Gi} "per si de cas" i el pod fa servir 80m i 200Mi. El planificador reserva el que s'ha demanat, així que estàs pagant 12 vegades el que fas servir.
kubectl top pods -n rutas-norte-pro --sort-by=memory
kubectl describe vpa api-reserves -n rutas-norte-pro # VPA en mode Off: recomana sense tocarAjustar requests a la recomanació a tota la plataforma sol reduir la factura de còmput entre un 30 i un 50 %.
2. Autoescalat real (09-01 i 09-03). Amb l'HPA ajustant pods i Karpenter o el Cluster Autoscaler ajustant nodes, pagues per la càrrega real i no pel pic anual. Rutas Norte té pics als ponts: sense autoescalat, o dimensiones per al pont tot l'any, o caus el dia del pont.
3. Instàncies interrompibles. 60-90 % de descompte a worker-notificacions i informes-ocupacio.
4. Apagar els entorns que no es fan servir de nit. rutas-norte-dev no fa res de les 20:00 a les 8:00 ni els caps de setmana. Això són 128 de 168 hores setmanals: un 76 % d'estalvi en aquell entorn.
# CronJob que escala a zero durant la nit (06-03). El d'encesa és
# idèntic amb schedule "0 8 * * 1-5" i --replicas=1.
apiVersion: batch/v1
kind: CronJob
metadata: { name: apagar-dev, namespace: rutas-norte-dev }
spec:
schedule: "0 20 * * 1-5"
jobTemplate:
spec:
template:
spec:
serviceAccountName: escalador-entorn
restartPolicy: OnFailure
containers:
- name: kubectl
image: bitnami/kubectl:1.30.4
command: ["sh", "-c", "kubectl scale deploy,statefulset --all --replicas=0 -n rutas-norte-dev"]Atenció amb GitOps: si Argo CD té selfHeal actiu a rutas-norte-dev, revertirà l'escalat a zero en tres minuts. Per això a la solució de l'exercici 1 de 10-05 vam deixar selfHeal: false a dev. L'alternativa neta és escalar el grup de nodes en comptes dels Deployments, o fer servir una finestra de sincronització de l'AppProject.
5. Compromisos d'ús. Els tres proveïdors descompten un 30-55 % a canvi de comprometre una despesa o una capacitat durant 1 o 3 anys (Savings Plans i Reserved Instances a AWS, Reservations a Azure, Committed Use Discounts a GCP).
Estratègia recomanada: comprometre només la base estable (els nodes que estan encesos sempre), deixar el pic sota demanda i les càrregues tolerants en spot.
flowchart TB
A["Càrrega total"] --> B["Base estable<br/>compromís 1-3 anys<br/>-40%"]
A --> C["Pics<br/>sota demanda<br/>preu complet"]
A --> D["Càrregues tolerants<br/>interrompibles<br/>-70%"]
style B fill:#e8ffe8
style D fill:#e8f4ff
6. Visibilitat del cost per equip. Eines com OpenCost o Kubecost reparteixen la despesa per namespace, etiqueta o equip. Sense això, ningú sap que informes-ocupacio costa 400 €/mes i ningú té incentiu per arreglar-ho. Les etiquetes de 02-07 (app.kubernetes.io/part-of, entorn) són la base d'aquell repartiment.
Resum de palanques
| Palanca | Estalvi típic | Esforç | Risc |
|---|---|---|---|
Ajustar requests amb el VPA |
30-50 % del còmput | Baix | Baix si es fa per fases |
| Autoescalat de pods i nodes | 20-40 % | Mitjà | Baix |
| Instàncies interrompibles | 60-90 % de les càrregues aptes | Mitjà | Mitjà (cal preparar l'app) |
| Apagar entorns de nit | 60-75 % de dev/pre | Baix | Molt baix |
| Compromisos d'ús | 30-55 % de la base | Baix | Mitjà (compromís a anys) |
| Reduir trànsit entre zones | 5-15 % | Alt | Xoca amb l'HA |
| Revisar retenció de registres | 10-30 % d'observabilitat | Baix | Baix |
- Portabilitat i dependència del proveïdor
Tot això val de poc si d'aquí a dos anys vols canviar de núvol i no pots. Serem precisos sobre què és portable a Rutas Norte.
Què és portable
| Element | Portable | Comentari |
|---|---|---|
| Deployment, StatefulSet, DaemonSet, Job, CronJob | Total | API estàndard |
| Service, Ingress (regles) | Total | Les regles sí; les anotacions no |
| ConfigMap, Secret | Total | |
| RBAC, ServiceAccount | Total | Tret de les anotacions d'identitat |
HPA, PDB, topologySpreadConstraints |
Total | |
| NetworkPolicy | Total | Si el CNI destí les implementa |
| PVC (nom de la classe) | Alta | El PVC és portable; la StorageClass cal redefinir-la |
| Manifestos de Kustomize | Total | |
| Charts de Helm | Total | |
| Applications d'Argo CD | Total | |
| Panells i alertes de Prometheus | Total | Si fas servir Prometheus i no el servei del proveïdor |
Què NO és portable
| Element | Per què | Cost de migrar |
|---|---|---|
Anotacions de Service LoadBalancer |
service.beta.kubernetes.io/aws-* no existeix a Azure |
Baix: reescriure un bloc |
parameters de la StorageClass |
ebs.csi.aws.com davant de disk.csi.azure.com |
Baix: un fitxer |
| Anotació d'identitat a la SA | IRSA / Workload Identity | Baix: una anotació |
| IngressClass del proveïdor | ALB, Application Gateway, GKE Ingress | Mitjà |
| Serveis de dades gestionats (RDS, Cloud SQL) | Fora de Kubernetes | Alt |
| Cues i missatgeria gestionades (SQS, Service Bus) | Fora de Kubernetes | Alt |
| Mètriques i registres del proveïdor | Consultes i panells propietaris | Alt |
| Infraestructura com a codi específica | CloudFormation, ARM, Deployment Manager | Mitjà (Terraform ho mitiga) |
El patró evident: el que està dins de Kubernetes és portable; el que està fora no ho és. La dependència del proveïdor no ve d'EKS, AKS o GKE, sinó dels serveis que envolten el clúster.
Com minimitzar la dependència
1. Aïlla el que no és portable a les superposicions de Kustomize. Ja ho tens muntat des de 10-04:
k8s/
├── base/ <- 100 % portable
├── components/
│ ├── proveidor-aws/ <- StorageClass, anotacions IRSA, ALB
│ ├── proveidor-azure/
│ └── proveidor-gcp/
└── entorns/pro/
└── kustomization.yaml <- activa el component del proveïdor actualCanviar de núvol és canviar una línia a components:. La base no es toca.
2. Fes servir ingress-nginx en comptes del controlador del proveïdor. És una capa d'abstracció que costa una mica de rendiment i estalvia una migració sencera. Les regles d'Ingress i les anotacions de nginx funcionen igual als tres núvols.
3. Fes servir Prometheus per a les mètriques. Les teves alertes i panells són el coneixement operatiu acumulat d'anys. En PromQL són portables; en el llenguatge de consulta del proveïdor, no.
4. Terraform en comptes de l'eina nativa. No fa la infraestructura portable, però sí el model mental i els fluxos de treball.
5. Decideix conscientment sobre les bases de dades. Executar postgres-reserves com a StatefulSet amb un operador (06-01, 06-07) és portable; fer servir el servei gestionat del proveïdor és més còmode i menys portable. Totes dues són decisions defensables; el que no val és prendre-la sense adonar-se'n.
| PostgreSQL a Kubernetes | Servei gestionat | |
|---|---|---|
| Portabilitat | Alta | Baixa |
| Operació (còpies, rèpliques, pedaços) | Teva, amb l'operador | Del proveïdor |
| Cost | Menor | Major |
| Rendiment a gran escala | Requereix ajust | Optimitzat |
| Risc de pèrdua de dades | Depèn de la teva diligència | Menor |
6. Sigues realista. La portabilitat total costa diners i complexitat, i moltes empreses mai canvien de núvol. Un objectiu sensat: "podríem migrar en tres mesos amb esforç, no en tres dies". Això et dona poder de negociació i et protegeix d'un canvi de preus abusiu, sense pagar l'impost de l'abstracció total.
- La decisió per a Rutas Norte
Les dades del cas
- Empresa petita: dues persones a
plataforma, sis adesenvolupament, tres asuport. - Cap cobertura de guàrdia 24×7.
- Trànsit amb pics forts i previsibles: ponts i vacances, 8-10 vegades la càrrega base.
- Dades personals de clients a
postgres-reserves: exigències del RGPD sobre localització i xifratge. - Pressupost ajustat.
- Ja fa servir emmagatzematge d'objectes i correu transaccional d'AWS per a altres coses.
Descartem el clúster autogestionat
Amb dues persones a plataforma i sense guàrdia, kubeadm (10-02) queda descartat. La pregunta decisiva és: qui restaura etcd un diumenge a les 4 de la matinada? Si la resposta és "esperem al dilluns", no es pot operar rutas-norte-pro amb un clúster propi. L'estalvi del pla de control (uns 220 €/mes amb tres clústers) no compensa ni de bon tros el risc.
L'elecció: EKS
| Criteri | Pes | Valoració |
|---|---|---|
| Ja fan servir AWS per a altres serveis | Alt | Un sol núvol, una sola facturació, una sola identitat |
| Karpenter per als pics dels ponts | Alt | El millor autoescalat de nodes dels tres |
Spot per a worker-notificacions i informes-ocupacio |
Alt | Estalvi directe sobre càrregues ja identificades com a tolerants |
| IRSA molt madur | Mitjà | Tanca 03-06 sense credencials a Secrets |
| Regions europees (RGPD) | Alt | eu-west-1 compleix |
| Finestra de suport de 14 mesos | Mitjà | Amb un equip petit, més temps entre actualitzacions és valuós |
| Cost del pla de control | Baix | 73 $/mes és assumible |
| Corba d'aprenentatge d'IAM | Mitjà (en contra) | És el punt fluix, però l'equip ja el coneix |
Si Rutas Norte no fes servir ja AWS, la recomanació seria GKE: el model de xarxa més net, Workload Identity més senzilla, canals de versió que redueixen la feina d'actualització, i Autopilot com a opció per als entorns no productius.
El disseny concret
Compte d'AWS, regió eu-west-1
CLÚSTER 1: rutas-norte-pro
Kubernetes 1.30, pla de control regional (3 zones)
Grups de nodes:
- general: m6i.large, 3-12 nodes, sota demanda,
3 zones, amb compromís d'ús sobre 3 nodes
- interrompible: gestionat per Karpenter, spot, 0-20,
amb taint rutasnorte.example/interrompible
Càrregues:
botiga-web, api-reserves, postgres-reserves, redis-cache -> general
worker-notificacions, informes-ocupacio -> interrompible
CLÚSTER 2: rutas-norte-no-productiu
Namespaces rutas-norte-dev i rutas-norte-pre
Grup únic: m6i.large, 2-6 nodes, MAJORIA SPOT
Apagada automàtica de 20:00 a 8:00 i caps de setmana
PLATAFORMA (als dos clústers, per GitOps):
Argo CD, cert-manager, ingress-nginx, KEDA,
kube-prometheus-stack, External Secrets Operator, Velero
DADES:
postgres-reserves com a StatefulSet amb operador (portabilitat)
Còpies amb Velero + snapshots d'EBS, replicades a una altra regióDos clústers, no tres. Separar pro de la resta és una frontera de seguretat real; separar dev de pre no ho justifica: els namespaces amb quotes (03-04) i NetworkPolicies (04-06) són suficients, i estalvien 73 $/mes més l'operació.
El cost estimat
| Concepte | Mensual |
|---|---|
| Pla de control × 2 clústers | 146 $ |
Nodes de pro: 3 sota demanda amb compromís + 1 de mitjana |
~210 $ |
Nodes interrompibles de pro (mitjana 2) |
~35 $ |
| Nodes no productius (spot, 40 h/setmana) | ~45 $ |
| Emmagatzematge EBS (300 GB gp3 + snapshots) | ~45 $ |
| Balancejadors (1 per clúster) | ~50 $ |
| Trànsit de sortida i entre zones | ~60 $ |
| Registre i mètriques gestionades | ~40 $ |
| Total aproximat | ~630 $/mes |
Sense les palanques d'estalvi (tot sota demanda, sense spot, sense apagada nocturna, sense compromisos, amb requests sobredimensionades) la mateixa plataforma costaria de l'ordre de 1.400-1.600 $/mes. Les palanques de l'apartat 7 no són teoria: són més de la meitat de la factura.
La conclusió honesta
Un clúster gestionat no és més barat que un de propi en cost d'infraestructura pura. És més barat en cost total, perquè inclou la feina que no has de fer i el risc que no assumeixes. Per a Rutas Norte S.L., amb dues persones a plataforma i sense guàrdia, és l'única opció defensable.
I hi ha una simetria que convé notar: gràcies a GitOps (10-05), la decisió és reversible. Tot l'estat de la plataforma és a Git. Si demà hi ha una raó per canviar de núvol o per muntar un clúster propi, s'aixeca el clúster nou, s'instal·la Argo CD, s'aplica l'Application arrel i en vint minuts la plataforma està dempeus. Les dades es migren a part, que és la part difícil, però la plataforma es reconstrueix sola.
Errors Comuns i Consells
1. Creure que "gestionat" inclou les còpies de les teves dades. El proveïdor fa còpia d'etcd, no dels teus volums. postgres-reserves és la teva responsabilitat: Velero (05-06) i snapshots, amb restauració assajada.
2. No planificar l'adreçament IP. A EKS amb VPC CNI, cada pod consumeix una IP real de la VPC. Un /24 s'esgota de seguida i el símptoma (FailedCreatePodSandBox) no menciona les IP de forma òbvia. Planifica rangs generosos i activa la delegació de prefixos.
3. Un Service de tipus LoadBalancer per aplicació. Cadascun costa 20-25 $/mes. Fes servir-ne un per al controlador d'Ingress i encamina amb regles d'Ingress (04-04).
4. StorageClass amb volumeBindingMode: Immediate en un clúster multizona. El disc es crea en una zona, el pod es planifica en una altra, i el pod no arrenca mai. Fes servir WaitForFirstConsumer.
5. Posar càrregues amb estat en instàncies interrompibles. postgres-reserves en spot és una recepta per perdre dades. Només càrregues que tolerin morir sense avís, amb terminationGracePeriodSeconds i hook preStop adequats.
6. Un sol tipus d'instància al grup interrompible. Si el proveïdor es queda sense aquell tipus, s'emporta tots els teus nodes alhora. Declara 4-6 tipus equivalents.
7. Continuar fent servir credencials estàtiques a Secrets. IRSA, Workload Identity i el seu equivalent a Azure eliminen les credencials permanents. És de les millores de seguretat amb millor relació cost/benefici que existeixen.
8. Actualitzar la versió sense comprovar les APIs eliminades ni els complements. El clúster s'actualitza sense problema i la teva aplicació deixa de desplegar-se, o ingress-nginx deixa d'arrencar. kubent i les matrius de compatibilitat, abans de tocar res.
9. requests sobredimensionades "per si de cas". És la principal causa de sobrecost a Kubernetes. El VPA en mode Off (09-02) et dona els números reals en una setmana.
10. Ignorar el trànsit entre zones. En aplicacions molt xerraires pot ser una partida important. Mesura-ho abans de decidir; és un compromís real amb l'alta disponibilitat de 09-05.
11. No etiquetar per al repartiment de costos. Sense entorn, app.kubernetes.io/part-of i una etiqueta d'equip, la factura és un número global que ningú pot reduir. Les etiquetes de 02-07 són la base d'OpenCost o Kubecost.
12. Adoptar Autopilot o Fargate sense comprovar les restriccions. Falco (08-06), alguns DaemonSets de xarxa i tot el que necessiti privilegis poden no funcionar. Prova primer en un entorn no productiu.
13. Confondre "menys operació" amb "sense operació". Continues sent responsable dels nodes, del RBAC, de les polítiques, dels secrets, de l'observabilitat i del cost. Els mòduls 2 a 9 d'aquest curs continuen sent enterament aplicables.
Exercicis
Exercici 1: manifestos per a instàncies interrompibles
Escriu el conjunt complet de manifestos que permet executar worker-notificacions en un grup de nodes interrompibles marcat amb el taint rutasnorte.example/interrompible=true:NoSchedule, sense deixar de funcionar si no hi ha capacitat spot. Ha d'incloure: tolerations, afinitat de node preferent, distribució topològica, terminationGracePeriodSeconds amb hook preStop, un PDB i un ScaledObject de KEDA. Explica per què fas servir afinitat preferent i no nodeSelector, i què protegeix realment el PDB davant d'una interrupció de spot.
Exercici 2: component de proveïdor amb Kustomize
Dissenya el component k8s/components/proveidor-aws/ que contingui tot l'específic d'AWS que Rutas Norte necessita: la StorageClass rutas-norte-ssd amb EBS gp3 xifrat, un pedaç que afegeixi l'anotació d'IRSA a les ServiceAccounts d'api-reserves i worker-notificacions, i un pedaç que afegeixi les anotacions de balancejador de xarxa al Service del controlador d'Ingress. Explica com s'activaria des de la superposició de pro i què caldria canviar per migrar a Azure.
Exercici 3: pla de reducció de costos
La factura de rutas-norte-pro és de 1.450 $/mes: 980 $ de còmput, 180 $ d'emmagatzematge, 120 $ de balancejadors (5 Services de tipus LoadBalancer), 90 $ de trànsit i 80 $ de registres. Tots els pods tenen requests: {cpu: 500m, memory: 1Gi} i kubectl top mostra un ús mitjà de 90m i 220Mi. No hi ha instàncies interrompibles ni compromisos. Proposa un pla prioritzat amb les ordres de diagnòstic, l'estalvi estimat de cada mesura i el risc associat.
Solucions
Solució 1
apiVersion: apps/v1
kind: Deployment
metadata:
name: worker-notificacions
namespace: rutas-norte-pro
spec:
selector:
matchLabels: { app: worker-notificacions }
template:
metadata:
labels:
app: worker-notificacions
app.kubernetes.io/part-of: rutas-norte
spec:
tolerations:
- key: rutasnorte.example/interrompible
operator: Equal
value: "true"
effect: NoSchedule
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- { key: rutasnorte.example/interrompible, operator: In, values: ["true"] }
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels: { app: worker-notificacions }
terminationGracePeriodSeconds: 90
containers:
- name: worker
image: registry.rutasnorte.example/worker-notificacions:1.8.4
lifecycle:
preStop:
exec: { command: ["/app/drenar", "--espera", "60s"] }
resources:
requests: { cpu: 200m, memory: 256Mi }
limits: { memory: 512Mi }
---
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata: { name: worker-notificacions, namespace: rutas-norte-pro }
spec:
minAvailable: 1
selector:
matchLabels: { app: worker-notificacions }
---
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata: { name: worker-notificacions, namespace: rutas-norte-pro }
spec:
scaleTargetRef: { name: worker-notificacions }
minReplicaCount: 1
maxReplicaCount: 30
triggers:
- type: redis
metadata:
address: redis-cache:6379
listName: cua-correus
listLength: "20"Afinitat preferent i no nodeSelector: nodeSelector és una restricció dura. Si no hi ha capacitat spot a la regió —cosa que passa precisament als pics, quan més falta fa— els pods es quedarien Pending indefinidament. Amb preferredDuringScheduling, el planificador intenta el node interrompible i, si no n'hi ha, en fa servir un de sota demanda: es paga més, però el servei no s'atura.
Què protegeix el PDB: res davant de la interrupció en si (el proveïdor s'emporta la màquina). Protegeix durant el drenatge que el manejador de terminació (o Karpenter) executa en rebre l'avís de 2 minuts: aquell drenatge respecta el PDB, així que no es buiden dos nodes simultàniament deixant la cua sense consumidors.
Solució 2
# k8s/components/proveidor-aws/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1alpha1
kind: Component
resources:
- storageclass.yaml
patches:
- path: irsa-patch.yaml
target: { kind: ServiceAccount, name: "api-reserves|worker-notificacions" }
- path: lb-patch.yaml
target: { kind: Service, name: ingress-nginx-controller }storageclass.yaml és el de l'apartat 5 (provisioner ebs.csi.aws.com, gp3 xifrat, WaitForFirstConsumer). Els dos pedaços són fusions estratègiques mínimes; el target s'encarrega de a qui s'apliquen, així que el metadata.name del pedaç és irrellevant:
# irsa-patch.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: IGNORAT
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/RutasNortePro
---
# lb-patch.yaml
apiVersion: v1
kind: Service
metadata:
name: ingress-nginx-controller
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: "external"
service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: "ip"
spec:
externalTrafficPolicy: Local# k8s/entorns/pro/kustomization.yaml
components:
- ../../components/politiques-xarxa
- ../../components/alta-disponibilitat
- ../../components/proveidor-aws # <-- una líniaMigrar a Azure: crear k8s/components/proveidor-azure/ amb provisioner: disk.csi.azure.com, l'anotació azure.workload.identity/client-id (més l'etiqueta azure.workload.identity/use: "true" als pods) i les anotacions de balancejador d'Azure. Després, canviar aquella única línia. k8s/base/ no es toca en absolut.
Solució 3
| Prioritat | Mesura | Diagnòstic | Estalvi | Risc |
|---|---|---|---|---|
| 1 | Ajustar requests a 150m/320Mi |
kubectl top pods, VPA en mode Off |
~450 $ | Baix, per fases |
| 2 | Consolidar 5 balancejadors en 1 + Ingress | kubectl get svc -A --field-selector spec.type=LoadBalancer |
~96 $ | Mitjà (canvi de DNS) |
| 3 | Spot per a worker i informes | Ja identificades com a tolerants | ~80 $ | Mitjà |
| 4 | Compromís d'ús sobre la base | Mitjana de nodes de 90 dies | ~130 $ | Mitjà (1-3 anys) |
| 5 | Retenció de registres de 30 a 7 dies; LOG_LEVEL=warn |
Volum ingerit per servei | ~50 $ | Baix |
| 6 | Revisar PV orfes i snapshots vells | kubectl get pv --field-selector status.phase=Released |
~40 $ | Baix |
| Total | ~846 $ | Factura de ~1.450 a ~604 $ |
# Ordres de diagnòstic
kubectl top pods -A --sort-by=cpu
kubectl get vpa -A -o custom-columns='NS:.metadata.namespace,NOM:.metadata.name,CPU:.status.recommendation.containerRecommendations[0].target.cpu,MEM:.status.recommendation.containerRecommendations[0].target.memory'
kubectl get svc -A --field-selector spec.type=LoadBalancer
kubectl get pv --field-selector status.phase=ReleasedOrdre i risc: es comença per l'ajust de requests perquè és el de més estalvi i menys risc, aplicant-lo primer a pre, verificant amb k6 (09-06) i després a pro component a component. El compromís d'ús va l'últim a propòsit: només té sentit comprometre's a una capacitat després d'haver-la reduït, o estaries pagant per endavant el sobredimensionament.
Conclusió
Es tanca aquí el mòdul 10. L'essencial d'aquesta lliçó:
- El model de responsabilitat compartida et treu el pla de control sencer —etcd, certificats, quòrum, actualitzacions, alta disponibilitat—, és a dir, aproximadament la meitat de la feina de 10-02. Tota la resta, inclosos els nodes, el RBAC, les polítiques, els secrets, l'observabilitat, les còpies de les teves dades i el cost, continua sent teu.
- EKS, AKS i GKE s'assemblen més que no pas es diferencien. Les diferències que de debò decideixen són el model de xarxa i l'assignació d'IP als pods, el cicle de versions, l'autoescalat (Karpenter destaca) i els modes automàtics (Autopilot destaca). I per damunt de tot: el núvol on ja és la teva infraestructura.
- La federació d'identitat —IRSA, Workload Identity i el seu equivalent a Azure— elimina les credencials permanents dels Secrets. El manifest que va a Git porta una anotació, no un secret. Tanca el que es va prometre a 03-06.
- Les instàncies interrompibles són estalvi real per a
worker-notificacionsiinformes-ocupacio, si s'acompanyen de tolerations, afinitat preferent, distribució topològica,preStopi PDB. - El que ja sabies canvia de forma concreta: la StorageClass és del proveïdor i necessita
WaitForFirstConsumer, el LoadBalancer per fi obté IP (i factura), el registre s'autentica amb la identitat del node, i les mètriques i registres es poden delegar. - L'actualització continua exigint planificació: APIs eliminades, matrius de compatibilitat dels complements, PDB que permetin drenar i sondes que aguantin el reinici.
- El cost es domina amb sis palanques, i les dues primeres —ajustar
requestsamb el VPA i apagar el que no es fa servir— són les de millor relació esforç/benefici. - I la portabilitat depèn del que posis fora de Kubernetes, no de quin gestionat triïs. Aïllar l'específic del proveïdor en un component de Kustomize deixa la base 100 % portable.
Per a Rutas Norte S.L., la recomanació és EKS a eu-west-1, amb dos clústers, Karpenter, instàncies interrompibles per a les càrregues tolerants i les palanques d'estalvi aplicades des del primer dia. I gràcies a GitOps, aquesta decisió és reversible.
Amb això acaba el recorregut per l'ecosistema. Ja tens totes les peces: clústers locals i propis, empaquetat amb Helm, superposicions amb Kustomize, desplegament continu amb GitOps i una plataforma gestionada on recolzar-ho tot. Sumades als nou mòduls anteriors —pods, serveis, configuració, xarxa, emmagatzematge, patrons avançats, observabilitat, seguretat i escalat—, ja coneixes totes les peces per separat.
El que falta és veure-les funcionar juntes. Al Mòdul 11: Estudis de Cas i Aplicacions del Món Real recorrerem escenaris complets de principi a fi: el desplegament d'una aplicació web des de zero, l'execució d'aplicacions amb estat, una canalització de CI/CD completa, les estratègies de desplegament blue-green i canary, la gestió multi-clúster i, per tancar, l'operació en producció de debò: incidències, runbooks i control de costos. Aquí és on el coneixement es converteix en criteri.
Curs de Kubernetes
Mòdul 1: Introducció a Kubernetes
- Què és Kubernetes?
- Arquitectura de Kubernetes
- Conceptes i Terminologia Clau
- Configuració d'un Clúster de Kubernetes
- La CLI de Kubernetes: kubectl
- Objectes, Manifests YAML i el Model Declaratiu
- El Projecte del Curs: la Plataforma Rutas Norte
Mòdul 2: Components Principals de Kubernetes
- Pods
- ReplicaSets
- Deployments
- Actualitzacions, Rollbacks i Estratègies de Desplegament
- Serveis
- Namespaces
- Etiquetes, Selectors i Anotacions
Mòdul 3: Gestió de Configuració i Secrets
- ConfigMaps
- Secrets
- Variables d'Entorn
- Quotes i Límits de Recursos
- LimitRanges i Classes de Qualitat de Servei (QoS)
- ServiceAccounts i Accés a l'API des dels Pods
Mòdul 4: Xarxes a Kubernetes
- Xarxes de Clúster
- Tipus de Serveis
- DNS Intern i Descobriment de Serveis
- Controladors d'Ingress
- TLS i Gestió de Certificats amb cert-manager
- Polítiques de Xarxa
Mòdul 5: Emmagatzematge a Kubernetes
- Volums
- Volums Persistents
- Reclamacions de Volums Persistents
- Classes d'Emmagatzematge
- Aprovisionament Dinàmic, Expansió i Snapshots
- Còpies de Seguretat i Restauració de Dades
Mòdul 6: Conceptes Avançats de Kubernetes
- StatefulSets
- DaemonSets
- Treballs i CronJobs
- Init Containers, Sidecars i Patrons Multicontenidor
- Planificació: Afinitat, Taints i Toleracions
- Definicions de Recursos Personalitzats (CRDs)
- Operadors i el Patró Controlador
Mòdul 7: Monitoratge i Registre
- Verificacions de Salut i Sondes
- Servidor de Mètriques i kubectl top
- Monitoratge amb Prometheus
- Visualització i Alertes amb Grafana i Alertmanager
- Registre Centralitzat amb Elasticsearch, Fluentd i Kibana (EFK)
- Depuració d'Aplicacions i Esdeveniments del Clúster
Mòdul 8: Seguretat a Kubernetes
- Control d'Accés Basat en Rols (RBAC)
- Contextos de Seguretat i Enduriment del Contenidor
- Polítiques de Seguretat de Pods i Pod Security Standards
- Seguretat de Xarxa
- Seguretat d'Imatges
- Auditoria, Escaneig i Gestió de Vulnerabilitats
Mòdul 9: Escalat i Rendiment
- Autoescalat Horitzontal de Pods
- Autoescalat Vertical de Pods
- Autoescalat de Clúster
- Escalat per Esdeveniments i Mètriques Personalitzades amb KEDA
- Alta Disponibilitat: PodDisruptionBudgets i Topologia
- Ajust de Rendiment
Mòdul 10: Ecosistema i Eines de Kubernetes
- Minikube i Entorns Locals amb kind
- Kubeadm
- Helm
- Kustomize
- GitOps amb Argo CD i Flux
- Kubernetes Gestionat: EKS, AKS i GKE
Mòdul 11: Estudis de Cas i Aplicacions del Món Real
- Desplegament d'una Aplicació Web
- Execució d'Aplicacions amb Estat
- CI/CD amb Kubernetes
- Estratègies de Desplegament: Blue-Green i Canary
- Gestió Multi-Clúster
- Operació en Producció: Incidències, Runbooks i Costos
