A la lliçó anterior vam ensenyar a Kubernetes a distingir un contenidor viu d'una aplicació sana. Rutas Norte ja sap si cada component funciona. El que encara no sap és quant consumeix. I aquesta dada no és cap luxe: a 03-04 vam fixar les requests i els limits de cada component pràcticament a ull, prometent que els calibraríem observant el consum real. Sense aquesta dada, la meitat del nostre clúster està reservant memòria que ningú fa servir mentre l'altra meitat pateix throttling de CPU en silenci.

Aquesta lliçó presenta la primera font de dades de consum real del clúster: metrics-server, un component lleuger que recull l'ús de CPU i memòria de nodes i pods i el publica dins de la mateixa API de Kubernetes. És la peça que fa funcionar kubectl top, i també la que farà funcionar l'autoescalat del mòdul 9. Anem a entendre exactament què mesura, d'on treu les dades, i —tan important com l'anterior— què no pot fer, perquè aquestes limitacions són justament la raó per la qual a la lliçó següent instal·larem Prometheus.

Contingut

  1. Quin lloc ocupa metrics-server a l'ecosistema d'observabilitat
  2. D'on surten les dades: kubelet, cAdvisor i la Summary API
  3. Com es publica a l'API: la capa d'agregació i l'APIService
  4. Instal·lació: l'addon de minikube i el manifest oficial
  5. kubectl top nodes: llegir correctament cada columna
  6. kubectl top pods: --containers, -A, --sort-by i els seus matisos
  7. Les limitacions essencials i per què cal Prometheus
  8. L'ús central: recalibrar les requests i limits de Rutas Norte
  9. Per què l'HPA i el VPA depenen d'aquest component
  10. Diagnòstic dels errors típics
  11. Errors comuns i consells
  12. Exercicis

  1. Quin lloc ocupa metrics-server a l'ecosistema d'observabilitat

Abans d'instal·lar res convé situar la peça, perquè és el component que més confusió genera del mòdul. Molta gent l'instal·la esperant un sistema de monitoratge i s'endú una decepció.

metrics-server no és un sistema de monitoratge. És un component d'infraestructura interna del clúster amb un propòsit molt concret i molt acotat:

Proporcionar a l'API de Kubernetes el consum actual de CPU i memòria de nodes i pods, perquè els mecanismes d'autoescalat del mateix Kubernetes puguin prendre decisions.

Tota la resta —que puguis veure-ho amb kubectl top— és un efecte secundari útil.

Aspecte metrics-server Prometheus (07-03)
Propòsit de disseny Alimentar l'HPA i el VPA Observar, consultar i alertar
Mètriques que recull Només CPU i memòria Qualsevol mètrica exposada
Històric Cap (~1-2 min en memòria) Setmanes o mesos en disc
Consultes No hi ha llenguatge de consulta PromQL complet
Alertes No Sí, amb Alertmanager
Emmagatzematge Memòria volàtil Base de dades de sèries temporals
Consum de recursos Molt baix (~50 Mi) Alt (GB de RAM i disc)
És obligatori? Pràcticament sí No, però imprescindible en producció
Granularitat 15 s per defecte Configurable, típic 15-30 s

Tots dos coexisteixen en qualsevol clúster seriós: metrics-server perquè l'HPA el necessita, Prometheus perquè cal saber què va passar ahir.

Una tercera confusió freqüent: metrics-server no substitueix les sondes de 07-01. Les sondes responen "està sa?"; metrics-server respon "quant gasta?". Un pod pot consumir 5 milicores i estar completament penjat.

  1. D'on surten les dades: kubelet, cAdvisor i la Summary API

Per no tractar metrics-server com una caixa negra, cal seguir el camí de la dada des del kernel fins al teu terminal.

L'origen: els cgroups del kernel

Quan el runtime de contenidors crea el contenidor d'api-reserves, el kernel de Linux el fica en un grup de control (cgroup). El kernel hi comptabilitza, entre altres coses:

  • cpuacct.usage: nanosegons de CPU acumulats per aquell cgroup des que va arrencar.
  • memory.current: bytes de memòria en ús ara mateix per aquell cgroup.

Aquestes són les dades primàries. Tota la resta són capes de transport.

cAdvisor: el lector de cgroups

cAdvisor (Container Advisor) és un component de Google que llegeix els cgroups i els tradueix a mètriques de contenidor amb sentit. Des de fa anys està integrat dins del binari del kubelet: no és un pod a part i no cal instal·lar-lo. Cada kubelet porta el seu propi cAdvisor que examina els contenidors del seu node.

La Summary API del kubelet

El kubelet exposa el que cAdvisor recull en un endpoint HTTPS autenticat:

https://<ip-del-node>:10250/stats/summary

Retorna un JSON amb el consum del node i de cada pod i contenidor. Una porció simplificada:

{
  "node": {
    "nodeName": "rutas-norte-worker-1",
    "cpu": { "time": "2026-08-06T09:14:20Z", "usageNanoCores": 842000000 },
    "memory": { "workingSetBytes": 3221225472 }
  },
  "pods": [
    {
      "podRef": { "name": "api-reserves-7d9f8c4b5-x2klm", "namespace": "rutas-norte-pro" },
      "containers": [
        {
          "name": "api",
          "cpu": { "usageNanoCores": 187000000 },
          "memory": { "workingSetBytes": 312475648 }
        }
      ]
    }
  ]
}

Dos camps mereixen atenció especial, perquè expliquen tot el que veuràs després:

  • usageNanoCores: nanocores consumits. Un core = 1 000 000 000 nanocores. Els 187 000 000 de l'exemple són 187 milicores, és a dir, 187m en la notació de Kubernetes.
  • workingSetBytes: el "conjunt de treball". És la memòria resident menys les pàgines de cau de fitxer que el kernel podria recuperar sense problema. És la mètrica que el kubelet fa servir per decidir a qui desallotjar per pressió de memòria, i és la que veuràs a kubectl top. No és el mateix que el RSS que et dóna ps, i per això de vegades els números no quadren amb el que veus dins del contenidor.

metrics-server: l'agregador

metrics-server és un únic Deployment (una rèplica en clústers petits) que:

  1. Descobreix els nodes consultant l'API de Kubernetes.
  2. Consulta la Summary API de cada kubelet cada 15 segons (paràmetre --metric-resolution).
  3. Desa els dos últims punts de cada sèrie en memòria.
  4. Calcula la taxa de CPU dividint l'increment de nanocores acumulats entre el temps transcorregut.
  5. Serveix aquests valors a través de l'API de Kubernetes.

Punt clau: no escriu res al disc i no desa històric. Si el pod de metrics-server es reinicia, kubectl top deixa de funcionar durant uns 30 segons i després torna, sense cap dada del passat.

Aquesta divisió també explica per què la CPU triga a aparèixer: com que és una taxa, calen dues mostres. Un pod acabat de crear no mostra CPU fins que metrics-server en té dues lectures.

  1. Com es publica a l'API: la capa d'agregació i l'APIService

Aquí hi ha la part elegant del disseny. metrics-server no exposa cap port propi al qual tu et connectis. En comptes d'això, es registra dins de l'API de Kubernetes mitjançant la capa d'agregació (API Aggregation Layer).

El mecanisme és el mateix que vam veure a 06-06 per a les CRDs, però per una altra via: en lloc que l'API Server desi els objectes a etcd, delega les peticions d'un grup d'API concret a un servei extern.

apiVersion: apiregistration.k8s.io/v1
kind: APIService
metadata:
  name: v1beta1.metrics.k8s.io
spec:
  group: metrics.k8s.io          # el grup d'API que es delega
  version: v1beta1
  groupPriorityMinimum: 100
  versionPriority: 100
  service:
    name: metrics-server         # a quin Service es reenvien les peticions
    namespace: kube-system
    port: 443
  insecureSkipTLSVerify: true    # en clústers de prova; en producció, caBundle

Això significa que quan executes:

kubectl top pods -n rutas-norte-pro

el que passa per sota és una petició REST normal i corrent a l'API de Kubernetes:

kubectl get --raw "/apis/metrics.k8s.io/v1beta1/namespaces/rutas-norte-pro/pods" | jq

L'API Server veu que la ruta pertany al grup metrics.k8s.io, consulta la seva taula d'APIService, i reenvia la petició al Service metrics-server de kube-system. La resposta torna al client com si l'hagués generat el mateix API Server.

flowchart TD
    U["kubectl top pods"] --> API[API Server]
    API -->|"grup metrics.k8s.io<br/>delegat per APIService"| MS[metrics-server<br/>Deployment a kube-system]
    MS -->|"HTTPS :10250<br/>/stats/summary<br/>cada 15 s"| K1[kubelet node 1]
    MS -->|"HTTPS :10250"| K2[kubelet node 2]
    MS -->|"HTTPS :10250"| K3[kubelet node 3]
    K1 --> CA1[cAdvisor integrat]
    K2 --> CA2[cAdvisor integrat]
    K3 --> CA3[cAdvisor integrat]
    CA1 --> CG1[(cgroups del kernel)]
    CA2 --> CG2[(cgroups del kernel)]
    CA3 --> CG3[(cgroups del kernel)]
    API -.->|"mateixa API"| HPA[HorizontalPodAutoscaler]

Les conseqüències pràctiques d'aquest disseny són importants:

  • Autenticació i autorització unificades: el RBAC que estudiarem a 08-01 s'aplica igual a kubectl top que a kubectl get pods. Qui no tingui permís get sobre pods.metrics.k8s.io no veurà res.
  • Un sol punt d'entrada: no cal obrir ports ni exposar serveis addicionals.
  • Fragilitat concreta: si l'APIService està False (per exemple, perquè el pod de metrics-server no arrenca), algunes operacions de descobriment de l'API s'alenteixen per a tot el clúster. Veuràs avisos com couldn't get resource list for metrics.k8s.io/v1beta1. És un efecte secundari molest que convé reconèixer.

Comprovar l'estat de l'APIService:

kubectl get apiservice v1beta1.metrics.k8s.io
NAME                     SERVICE                      AVAILABLE   AGE
v1beta1.metrics.k8s.io   kube-system/metrics-server   True        41d

AVAILABLE: True és la senyal que tot està bé. Si posa False (MissingEndpoints) o False (FailedDiscoveryCheck), ves directe a l'apartat 10.

  1. Instal·lació: l'addon de minikube i el manifest oficial

Al nostre clúster de pràctiques

Des del mòdul 1 anem treballant amb minikube al perfil rutas-norte, i ja vam declarar metrics-server entre els addons necessaris. Si encara no l'has activat:

# Activar l'addon al nostre perfil
minikube addons enable metrics-server -p rutas-norte

# Comprovar que l'addon apareix habilitat
minikube addons list -p rutas-norte | grep metrics-server
| metrics-server              | rutas-norte | enabled ✅   | Kubernetes |

L'addon desplega el Deployment a kube-system amb la configuració ja adaptada a minikube (inclòs el flag de l'apartat següent).

kubectl -n kube-system get deploy,pod -l k8s-app=metrics-server
NAME                             READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/metrics-server   1/1     1            1           2m18s

NAME                                  READY   STATUS    RESTARTS   AGE
pod/metrics-server-7bf7d58749-qk4hn   1/1     Running   0          2m18s

Espera entre 30 i 60 segons abans d'esperar dades: metrics-server necessita almenys dos cicles de recol·lecció.

En un clúster real

En un clúster que no sigui minikube s'instal·la aplicant el manifest oficial del projecte:

kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

Aquest manifest crea, a kube-system: un ServiceAccount, un ClusterRole amb permisos de lectura sobre nodes i pods, els ClusterRoleBinding corresponents (inclosa la delegació d'autenticació a l'API Server), el Service, el Deployment i l'APIService que hem vist abans.

El flag --kubelet-insecure-tls i el seu advertiment

Aquest és el punt que més vegades bloqueja una instal·lació. metrics-server es connecta per HTTPS al port 10250 de cada kubelet. Per defecte verifica el certificat del kubelet contra la CA del clúster. El problema: en moltes instal·lacions (minikube, kubeadm sense rotació de certificats de servidor del kubelet, alguns clústers gestionats) el kubelet fa servir un certificat autosignat que no està signat per la CA del clúster, o el nom del qual no coincideix amb la IP del node.

Resultat: metrics-server no s'hi pot connectar i kubectl top no retorna res. La solució que apareix a tots els fòrums:

# Fragment del Deployment de metrics-server
spec:
  template:
    spec:
      containers:
        - name: metrics-server
          args:
            - --cert-dir=/tmp
            - --secure-port=10250
            - --kubelet-preferred-address-types=InternalIP,Hostname,InternalDNS,ExternalDNS
            - --kubelet-use-node-status-port
            - --metric-resolution=15s
            - --kubelet-insecure-tls        # <-- el flag en qüestió

Advertiment de seguretat. --kubelet-insecure-tls desactiva la verificació del certificat del kubelet. La connexió continua xifrada, però metrics-server ja no comprova que l'interlocutor sigui realment el kubelet legítim del node. Un atacant amb capacitat d'interposar-se a la xarxa del pla de control podria suplantar un kubelet i retornar mètriques falses. Això, en un clúster amb HPA, és un vector d'atac real: mètriques de CPU inventades poden provocar un escalat massiu (cost) o impedir un escalat necessari (denegació de servei).

És acceptable a minikube i en entorns de desenvolupament. No ho és a rutas-norte-pro. La solució correcta en producció és habilitar la rotació de certificats de servidor del kubelet (--rotate-server-certificates=true al kubelet i aprovació de les CSR kubernetes.io/kubelet-serving), de manera que els certificats els signi la CA del clúster i la verificació funcioni. En un clúster gestionat (EKS, AKS, GKE, que veurem a 10-06), el proveïdor ja ho porta resolt i el flag no cal.

La resta d'arguments, breument:

Argument Per a què serveix
--metric-resolution=15s Cada quant es consulten els kubelets. No baixar de 10 s: satura els kubelets
--kubelet-preferred-address-types En quin ordre intentar adreçar el node. InternalIP primer sol ser el correcte
--kubelet-use-node-status-port Fer servir el port que el propi node declara al seu estat, en lloc d'assumir 10250
--cert-dir=/tmp On desa el seu certificat de servei propi

  1. kubectl top nodes: llegir correctament cada columna

Amb metrics-server funcionant, ja podem mirar.

kubectl top nodes
NAME                     CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%
rutas-norte-control      412m         20%    1854Mi          48%
rutas-norte-worker-1     1834m        45%    5218Mi          67%
rutas-norte-worker-2     2701m        67%    6944Mi          89%
rutas-norte-worker-3     287m         7%     1102Mi          14%

Com es llegeix això correctament, columna a columna:

  • CPU(cores): milicores consumits ara mateix per tot el que corre al node (pods del sistema inclosos). 1834m significa 1,834 nuclis ocupats de manera contínua.
  • CPU%: el percentatge sobre la capacitat assignable del node (node.status.allocatable.cpu), no sobre la capacitat total ni sobre la suma de requests. És un detall important: allocatable = capacitat total menys el que està reservat per al sistema operatiu i per al kubelet.
  • MEMORY(bytes): el workingSetBytes del node. Repeteixo el matís de l'apartat 2: no inclou el cau de pàgina recuperable, així que gairebé sempre és menor que el que mostra free -m dins del node.
  • MEMORY%: percentatge sobre allocatable.memory.

Comprovar l'allocatable d'un node per verificar el càlcul:

kubectl get node rutas-norte-worker-2 \
  -o jsonpath='{.status.allocatable.cpu}{"\t"}{.status.allocatable.memory}{"\n"}'
4        7808036Ki

Amb 4 nuclis assignables i 2701m consumits: 2701 / 4000 = 67,5 %. Quadra.

Lectura operativa de la taula anterior per a Rutas Norte:

  • rutas-norte-worker-2 està al 89 % de memòria. Perillós: quan el kubelet detecta pressió de memòria comença a desallotjar pods, començant pels de QoS BestEffort i Burstable que excedeixen les seves requests (repassa 03-05). Cal investigar què hi corre i probablement reequilibrar.
  • rutas-norte-worker-3 està pràcticament buit al 7 % i 14 %. Això apunta a un problema de planificació: potser té un taint que no havíem previst, o els pods tenen regles d'afinitat que l'exclouen (06-05).

Flags útils:

# Ordenar per consum de CPU descendent
kubectl top nodes --sort-by=cpu

# Ordenar per memòria
kubectl top nodes --sort-by=memory

# Només els nodes amb una etiqueta concreta
kubectl top nodes -l node-role.kubernetes.io/worker=

# Sense capçaleres, per processar amb scripts
kubectl top nodes --no-headers

  1. kubectl top pods: --containers, -A, --sort-by i els seus matisos

kubectl top pods -n rutas-norte-pro
NAME                                      CPU(cores)   MEMORY(bytes)
api-reserves-7d9f8c4b5-x2klm              187m         305Mi
api-reserves-7d9f8c4b5-mn8pq              203m         318Mi
api-reserves-7d9f8c4b5-vr4tz              174m         297Mi
postgres-reserves-0                       340m         1720Mi
redis-cache-0                             28m          412Mi
botiga-web-6c8b9d7f4-hj3ks                12m          38Mi
botiga-web-6c8b9d7f4-lp9wx                9m           36Mi
worker-notificacions-5f7c8b9d4-tz2mv      45m          186Mi

Diferència crítica respecte a top nodes: aquí NO hi ha columnes de percentatge. kubectl top pods no mostra cap %, perquè no sabria respecte a què calcular-lo (sobre el limit? sobre la request? sobre el node?). Aquesta comparació l'has de fer tu, i a l'apartat 8 la farem.

--containers: desglossament per contenidor

Amb l'arribada dels sidecars a 06-04, un pod ja no és un contenidor. postgres-reserves-0 té el contenidor de PostgreSQL i l'exportador de mètriques; worker-notificacions té el worker i l'adaptador de logs. Sumar-los amaga informació valuosa:

kubectl top pods -n rutas-norte-pro --containers
POD                                     NAME              CPU(cores)   MEMORY(bytes)
postgres-reserves-0                     postgres          327m         1698Mi
postgres-reserves-0                     exportador-pg     13m          22Mi
worker-notificacions-5f7c8b9d4-tz2mv    worker            41m          171Mi
worker-notificacions-5f7c8b9d4-tz2mv    adaptador-logs    4m           15Mi
api-reserves-7d9f8c4b5-x2klm            api               187m         305Mi

Ara sabem que el sidecar exportador costa 13m de CPU i 22Mi: barat, com esperàvem. I que l'adaptador de logs costa 4m i 15Mi. Aquests números importen perquè, multiplicats pel nombre de rèpliques, un sidecar aparentment innocu pot consumir un node sencer en un clúster gran.

Altres opcions

# Tots els namespaces del clúster, ordenat per memòria descendent
kubectl top pods -A --sort-by=memory

# Només els pods d'un component concret (fes servir el selector d'etiquetes de 02-07)
kubectl top pods -n rutas-norte-pro -l app=api-reserves

# Tots els components de la plataforma, als tres entorns
kubectl top pods -A -l app.kubernetes.io/part-of=rutas-norte --sort-by=cpu

# Un pod concret, desglossat
kubectl top pod postgres-reserves-0 -n rutas-norte-pro --containers

# Sense capçaleres i ordenat, per a un script d'informe
kubectl top pods -n rutas-norte-pro --no-headers --sort-by=memory

--sort-by només admet cpu o memory. Compte amb un comportament poc intuïtiu: l'ordenació es fa sobre els valors numèrics, però la sortida s'imprimeix en les unitats de Kubernetes, i 1024Mi va després de 2Gi alfabèticament encara que sigui menor. Confia en l'ordre que dóna --sort-by, no en la lectura visual.

Comparativa ràpida d'ordres

Ordre Què respon
kubectl top nodes Quins nodes estan saturats? Hi ha desequilibri?
kubectl top pods -A --sort-by=memory Qui s'està menjant la memòria del clúster?
kubectl top pods -n X --containers Quant costa cada sidecar?
kubectl top pods -l app=api-reserves Consumeixen igual totes les rèpliques d'un component?

Aquesta última pregunta és més útil del que sembla. Si de sis rèpliques d'api-reserves una consumeix 800m i les altres 190m, tens un problema de repartiment de trànsit o una petició patològica atesa per aquell pod concret.

  1. Les limitacions essencials i per què cal Prometheus

Aquest apartat és el més important de la lliçó, perquè defineix quan no has de fer servir aquesta eina.

Limitació 1: no hi ha històric. Cap.

metrics-server desa els dos últims punts de cada sèrie en memòria. No hi ha base de dades, no hi ha fitxer, no hi ha retenció configurable. Preguntes que no pots respondre amb kubectl top:

  • "Quanta memòria consumia api-reserves ahir a la nit a les 03:00, quan va caure?"
  • "Ha anat creixent el consum de postgres-reserves les últimes dues setmanes?"
  • "Quin va ser el pic de CPU durant el pont de maig?"

Totes elles són exactament les preguntes que es fan després d'un incident, i per a totes la resposta de metrics-server és silenci.

Limitació 2: són dades instantànies amb resolució gruixuda

Amb --metric-resolution=15s i finestres de càlcul de la taxa de CPU de desenes de segons, un pic de CPU de 3 segons no apareix. Es promitja i desapareix. Per a api-reserves, els pics de latència del qual es mesuren en segons, aquesta resolució és insuficient per diagnosticar.

També significa que dues execucions consecutives de kubectl top poden donar el mateix valor: si totes dues cauen dins del mateix cicle de recol·lecció, estàs llegint la mateixa mostra.

Limitació 3: només CPU i memòria

Res de disc, res de xarxa, res de mètriques d'aplicació. No sabràs quantes peticions per segon atén api-reserves, ni quantes reserves s'han confirmat, ni quantes connexions té obertes PostgreSQL. Res del negoci.

Limitació 4: no es pot alertar

No hi ha consultes, no hi ha llindars, no hi ha notificacions. kubectl top és una eina interactiva: algú ha de ser-hi al davant escrivint-la. A les tres de la matinada no hi ha ningú al davant.

Limitació 5: no distingeix el throttling

A 03-04 vam veure que un contenidor que arriba al seu limits.cpu no es mata: se l'estrangula (throttling). El símptoma és latència alta amb un consum de CPU que es queda enganxat al límit. kubectl top et mostra els milicores, però no el comptador de períodes estrangulats (container_cpu_cfs_throttled_periods_total), que és la dada que confirma el diagnòstic. Aquest comptador només el veuràs a Prometheus.

Taula resum: què preguntar a qui

Pregunta metrics-server Prometheus
Quant consumeix api-reserves ara?
Quant consumia ahir a les 03:00?
Està creixent el seu consum amb el temps?
Quantes peticions per segon atén?
Està patint throttling de CPU?
Quin és el percentil 95 de latència?
Avisa'm si puja de X
Escalar automàticament per CPU ✅ (via adaptador)
Quin node està més carregat ara mateix?
Cost d'instal·lació i operació Trivial Considerable

La conclusió honesta: metrics-server és una fotografia; Prometheus és la pel·lícula. Necessites les dues coses, i per raons diferents. La foto és gratis i sempre hi és; la pel·lícula costa diners, disc i manteniment, però és l'única que et diu què va passar.

  1. L'ús central: recalibrar les requests i limits de Rutas Norte

Aquest és l'ús legítim i de més valor de kubectl top, i el que tanca la promesa de 03-04.

Recordatori de per què importa

  • requests: el que el planificador reserva al node. Determina on cap el pod i quin QoS té. Reservar de més malbarata clúster (nodes amb el 30 % d'ús real i "plens" segons el planificador); reservar de menys fa que els pods vagin a nodes on realment no caben i pateixin.
  • limits: el sostre. Superar-lo en CPU provoca throttling; superar-lo en memòria provoca OOMKilled.

El mètode de recalibració

No es recalibren les requests mirant una sola vegada. El procediment honest:

  1. Observar durant un període representatiu: almenys una setmana, incloent-hi un pic. Per a Rutas Norte cal incloure un pont o l'inici de les vacances.
  2. Prendre mostres periòdiques, no una sola lectura. Com que metrics-server no desa històric, això significa un script que executi kubectl top cada pocs minuts i acumuli.
  3. Calcular percentils, no mitjanes. La mitjana menteix quan hi ha pics.
  4. Aplicar els criteris:
Recurs Criteri de càlcul
requests.cpu Percentil 50-70 de l'ús observat. No cal reservar el pic: la CPU és comprimible
limits.cpu 2-4 vegades la request, o sense límit si el component tolera bé la variabilitat
requests.memory Percentil 95-99 de l'ús observat, més marge. La memòria no és comprimible
limits.memory Igual o molt propera a la request, més un 20-30 % de marge

L'asimetria entre CPU i memòria és fonamental i cal entendre-la: si et passes de CPU, el sistema t'alenteix i sobrevius. Si et passes de memòria, el kernel et mata. Per això la memòria es dimensiona pel percentil alt i la CPU pel central.

Script de recol·lecció per a una setmana

#!/bin/bash
# recull-consum.sh
# Mostreja el consum dels pods de Rutas Norte cada 2 minuts.
# Limitació deliberada: això és un apedaçament perquè metrics-server no desa
# històric. A 07-03 el substituirem per Prometheus, que fa això de sèrie.

SORTIDA="/var/log/rutasnorte/consum-$(date +%Y%m%d).csv"
echo "marca_temps,namespace,pod,contenidor,cpu_milicores,memoria_mib" > "$SORTIDA"

while true; do
  ARA=$(date --iso-8601=seconds)
  kubectl top pods -A --containers --no-headers \
    -l app.kubernetes.io/part-of=rutas-norte 2>/dev/null |
  while read -r ns pod contenidor cpu mem; do
    # Netejar sufixos: 187m -> 187, 305Mi -> 305
    cpu_num="${cpu%m}"
    mem_num="${mem%Mi}"
    echo "$ARA,$ns,$pod,$contenidor,$cpu_num,$mem_num" >> "$SORTIDA"
  done
  sleep 120
done

Nota important per a principiants: l'ordre anterior amb -A retorna el namespace com a primera columna, per això read pren cinc camps. Si l'executes sense -A, treu la variable ns.

I l'anàlisi de les dades recollides:

# Percentil 95 de memòria d'api-reserves durant la setmana
awk -F, '$4=="api" {print $6}' /var/log/rutasnorte/consum-*.csv |
  sort -n |
  awk '{v[NR]=$1} END {print "p95 memoria: " v[int(NR*0.95)] " Mi"}'

# Percentil 70 de CPU d'api-reserves
awk -F, '$4=="api" {print $5}' /var/log/rutasnorte/consum-*.csv |
  sort -n |
  awk '{v[NR]=$1} END {print "p70 CPU: " v[int(NR*0.70)] "m"}'

L'abans i el després de Rutas Norte

Després de dues setmanes d'observació (inclòs el pont de l'1 de maig), aquestes són les dades i les decisions:

Component requests de 03-04 Ús p50 Ús p95 requests noves Veredicte
botiga-web cpu 200m / mem 256Mi 11m / 37Mi 24m / 42Mi cpu 50m / mem 64Mi Sobredimensionat 4x. nginx servint estàtics gasta molt poc
api-reserves cpu 100m / mem 128Mi 185m / 302Mi 640m / 458Mi cpu 200m / mem 512Mi Infradimensionat. Explica el throttling que ningú sabia diagnosticar
postgres-reserves cpu 500m / mem 1Gi 335m / 1710Mi 1250m / 1980Mi cpu 500m / mem 2560Mi Memòria molt curta: risc real d'OOMKilled en pics
redis-cache cpu 100m / mem 512Mi 27m / 410Mi 55m / 486Mi cpu 50m / mem 768Mi CPU de sobres; memòria justa i creixent amb les places cauades
worker-notificacions cpu 200m / mem 256Mi 43m / 180Mi 380m / 240Mi cpu 100m / mem 320Mi Molt variable: ràfegues en enviar lots de correus
informes-ocupacio (CronJob) cpu 500m / mem 512Mi 890m / 720Mi 1100m / 810Mi cpu 1 / mem 1Gi Es quedava curt: els informes trigaven el doble per throttling

Tres troballes que val la pena comentar, perquè són les típiques:

  1. api-reserves demanava 100m i feia servir 185m de mitjana. Amb QoS Burstable, això funciona mentre el node tingui lloc, però el planificador estava col·locant pods com si cadascun ocupés 100m: sobrevenia el node. I el limits.cpu de 500m provocava throttling als pics de 640m, cosa que explica els pics de latència que ningú sabia atribuir. Aquesta és la troballa més valuosa de tot l'exercici.
  2. botiga-web reservava 4 vegades el que fa servir. Multiplicat per les seves rèpliques i per tres entorns, això són uns quants nuclis i uns quants GB de clúster reservats per a res, comptant a més contra la ResourceQuota del namespace (03-04).
  3. El CronJob informes-ocupacio patia throttling silenciós. El seu limits.cpu de 1000m amb un ús de 1100m desitjats feia que l'informe nocturn trigués 40 minuts en lloc de 18. Ningú es queixava perquè ningú estava despert.

Els manifests recalibrats

# k8s/entorns/pro/api-reserves-recursos.yaml
# Valors basats en dues setmanes d'observació amb kubectl top
# CPU: p70 observat com a request; limit generós per absorbir pics
# Memòria: p95 + 12% de marge, amb limit igual a request (QoS Guaranteed
# per al component crític del negoci)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-reserves
  namespace: rutas-norte-pro
spec:
  template:
    spec:
      containers:
        - name: api
          resources:
            requests:
              cpu: "200m"          # abans 100m — p50 observat 185m
              memory: "512Mi"      # abans 128Mi — p95 observat 458Mi
            limits:
              cpu: "1500m"         # abans 500m — permetia arribar als 640m del p95
              memory: "512Mi"      # igual que request → QoS Guaranteed
# k8s/entorns/pro/botiga-web-recursos.yaml
# Component sobredimensionat: alliberem clúster reduint les requests
apiVersion: apps/v1
kind: Deployment
metadata:
  name: botiga-web
  namespace: rutas-norte-pro
spec:
  template:
    spec:
      containers:
        - name: nginx
          resources:
            requests:
              cpu: "50m"           # abans 200m — p95 observat 24m
              memory: "64Mi"       # abans 256Mi — p95 observat 42Mi
            limits:
              cpu: "300m"
              memory: "128Mi"

Un advertiment sobre el procés: recalibra a rutas-norte-pre primer, amb càrrega sintètica representativa, i només després porta els valors a rutas-norte-pro. Baixar una requests.memory de cop en producció pot provocar que el planificador fiqui més pods en un node dels que realment hi caben, amb desallotjaments posteriors.

I no ho facis a mà indefinidament. A 09-02 veurem el VPA (Vertical Pod Autoscaler), que fa exactament aquesta anàlisi de manera contínua i pot recomanar o aplicar els valors automàticament.

  1. Per què l'HPA i el VPA depenen d'aquest component

Encara que el mòdul 9 desenvolupa l'autoescalat, cal deixar clara aquí la dependència, perquè és la raó de ser de metrics-server.

Quan a 09-01 escriguem un HorizontalPodAutoscaler com aquest:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: api-reserves
  namespace: rutas-norte-pro
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api-reserves
  minReplicas: 4
  maxReplicas: 20
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70      # 70 % de la REQUEST, no del limit

el controlador de l'HPA, que viu dins del kube-controller-manager, consulta exactament la mateixa API que kubectl top:

GET /apis/metrics.k8s.io/v1beta1/namespaces/rutas-norte-pro/pods

Cada 15 segons per defecte. Amb el resultat, calcula l'ús mitjà de CPU dels pods del Deployment, el divideix entre la suma de les seves requests per obtenir el percentatge d'utilització, i decideix quantes rèpliques hi ha d'haver.

Dues conseqüències que cal gravar a foc:

Conseqüència 1: sense metrics-server, l'HPA no funciona. No falla sorollosament: es queda amb l'estat unknown i no escala. El símptoma:

kubectl -n rutas-norte-pro get hpa api-reserves
NAME           REFERENCE                 TARGETS              MINPODS   MAXPODS   REPLICAS   AGE
api-reserves   Deployment/api-reserves   <unknown>/70%        4         20        4          12m

Aquest <unknown> és la signatura que metrics-server no està disponible. I kubectl describe hpa ho confirma:

Conditions:
  Type            Status  Reason                   Message
  ----            ------  ------                   -------
  AbleToScale     True    SucceededGetScale        the HPA controller was able to get the target's current scale
  ScalingActive   False   FailedGetResourceMetric  failed to get cpu utilization: unable to get metrics for
                                                   resource cpu: unable to fetch metrics from resource metrics
                                                   API: the server could not find the requested resource

Durant el pont de maig, amb l'HPA "instal·lat" però sense metrics-server, api-reserves s'hauria quedat en 4 rèpliques mentre el trànsit es multiplicava per sis.

Conseqüència 2: el percentatge de l'HPA es calcula sobre les requests. Un averageUtilization: 70 amb requests.cpu: 100m significa escalar en arribar a 70 milicores. Si recalibres la request a 200m, el mateix HPA escalarà en arribar a 140 milicores. Canviar les requests canvia el comportament de l'autoescalat. Per això l'ordre correcte és: primer calibrar amb kubectl top (aquesta lliçó), després configurar l'HPA (09-01).

El VPA (09-02) fa servir la mateixa font, però amb un històric propi que ell mateix manté, precisament perquè metrics-server no en té.

  1. Diagnòstic dels errors típics

error: Metrics API not available

kubectl top nodes
error: Metrics API not available

Significa que l'API Server no pot servir el grup metrics.k8s.io. Seqüència de diagnòstic:

# 1. Existeix i està disponible l'APIService?
kubectl get apiservice v1beta1.metrics.k8s.io
NAME                     SERVICE                      AVAILABLE                  AGE
v1beta1.metrics.k8s.io   kube-system/metrics-server   False (MissingEndpoints)   3m
# 2. Està el pod corrent i llest?
kubectl -n kube-system get pods -l k8s-app=metrics-server
NAME                              READY   STATUS    RESTARTS   AGE
metrics-server-7bf7d58749-qk4hn   0/1     Running   4          3m

0/1 amb reinicis: el pod arrenca però la seva pròpia readiness falla. Al log:

kubectl -n kube-system logs -l k8s-app=metrics-server --tail=30

Error de certificat del kubelet

E0806 09:22:14.882134  1 scraper.go:149] "Failed to scrape node" err="Get
\"https://192.168.49.2:10250/metrics/resource\": tls: failed to verify certificate:
x509: cannot validate certificate for 192.168.49.2 because it doesn't contain any IP SANs"
node="rutas-norte-worker-1"

Aquest és el cas descrit a l'apartat 4. Solució en desenvolupament:

kubectl -n kube-system patch deployment metrics-server --type=json \
  -p='[{"op":"add","path":"/spec/template/spec/containers/0/args/-","value":"--kubelet-insecure-tls"}]'

Recorda l'advertiment: a rutas-norte-pro, la solució correcta és la rotació de certificats de servidor del kubelet, no aquest pedaç.

Valors buits acabat d'arrencar

kubectl top pods -n rutas-norte-pro
W0806 09:15:02.114 Metrics not available for pod rutas-norte-pro/api-reserves-7d9f8c4b5-x2klm, age: 22.4s
error: metrics not available yet

No és cap error. És el comportament esperat durant els primers 30-60 segons després d'arrencar metrics-server o després de crear un pod nou: calen dues mostres per calcular la taxa de CPU. Espera un minut i torna-ho a provar. Moltíssima gent reinstal·la metrics-server innecessàriament per no esperar.

El node no és accessible

E0806 09:24:01 "Failed to scrape node" err="Get \"https://rutas-norte-worker-3:10250/metrics/resource\":
dial tcp: lookup rutas-norte-worker-3 on 10.96.0.10:53: no such host" node="rutas-norte-worker-3"

metrics-server intenta arribar al node pel seu nom d'amfitrió i el DNS no el resol. Solució: forçar l'ús de la IP interna.

args:
  - --kubelet-preferred-address-types=InternalIP,Hostname,InternalDNS,ExternalDNS

Un pod concret no apareix

Causes habituals, per ordre de freqüència:

  1. El pod fa menys de 30 segons que és viu.
  2. El pod està en Pending: no té contenidors executant-se, així que no hi ha res a mesurar.
  3. El node on viu el pod no és accessible per a metrics-server (mira els logs).
  4. No tens permisos RBAC sobre aquell namespace.

Taula resum de diagnòstic

Símptoma Causa probable Comprovació
Metrics API not available Pod caigut o APIService no disponible kubectl get apiservice v1beta1.metrics.k8s.io
metrics not available yet Menys de 60 s des de l'arrencada Esperar i reintentar
x509: cannot validate certificate Certificat autosignat del kubelet Logs de metrics-server; flag --kubelet-insecure-tls
no such host en escanejar el node Resolució DNS del nom del node --kubelet-preferred-address-types=InternalIP,...
HPA amb <unknown> metrics-server no respon kubectl top pods al mateix namespace
Falta un pod concret Pod nou o en Pending kubectl get pod <nom> -o wide
Error from server (Forbidden) RBAC insuficient kubectl auth can-i get pods.metrics.k8s.io -n <ns>

Errors Comuns i Consells

1. Esperar que metrics-server sigui un sistema de monitoratge. És la confusió número u. No desa històric, no alerta i només mesura dues coses. Instal·lar metrics-server i donar l'observabilitat per resolta és deixar la plataforma gairebé tan cega com abans.

2. Confondre kubectl top amb kubectl describe node. Són dades completament diferents i responen a preguntes diferents:

kubectl describe node rutas-norte-worker-2 | grep -A 8 "Allocated resources"
Allocated resources:
  Resource           Requests      Limits
  --------           --------      ------
  cpu                3200m (80%)   6500m (162%)
  memory             6144Mi (78%)  9216Mi (118%)

Això són requests i limits declarats, és a dir, el que el planificador té reservat. kubectl top mostra el consum real. Un node pot estar al 80 % de reserves i al 20 % d'ús real: això és precisament el que estem corregint a l'apartat 8.

3. Recalibrar amb una sola lectura. Un kubectl top un dimarts a les 11:00 no et diu res sobre el pont de maig. Mesura durant almenys una setmana i fes servir percentils.

4. Baixar --metric-resolution per sota de 10 s. Se satura la Summary API dels kubelets, que en clústers grans és una operació cara. No millora la qualitat de les dades i sí que pot degradar el node.

5. Deixar --kubelet-insecure-tls en producció. Ho repeteixo perquè es fa constantment: es posa per desencallar la instal·lació i ningú torna a treure'l. A rutas-norte-pro és un risc real, no teòric.

6. Executar més d'una rèplica de metrics-server sense ajustar la configuració. Amb alta disponibilitat cal afegir --enable-aggregator-routing=true a l'API Server i ajustar l'antiafinitat. Amb una rèplica, l'única conseqüència que caigui és perdre kubectl top uns segons: acceptable en la majoria de casos.

7. Interpretar MEMORY(bytes) com el RSS del procés. És workingSetBytes, que exclou el cau de pàgina recuperable. No quadrarà amb ps ni amb free dins del contenidor, i això és normal.

8. Fer servir kubectl top per investigar un incident passat. No hi ha passat. Si l'incident s'ha acabat, kubectl top t'ensenya el present sa i no aporta res. Aquesta és literalment la raó de la propera lliçó.

9. Oblidar que les requests afecten l'HPA. Canviar requests.cpu sense revisar l'averageUtilization de l'HPA canvia silenciosament el llindar d'escalat.

10. No comprovar els sidecars amb --containers. Des de 06-04 tenim sidecars en diversos components. Sumar-los al contenidor principal amaga el seu cost i complica el dimensionament.

Exercicis

Exercici 1 — Instal·lar, verificar i recórrer el camí de la dada

Al teu minikube rutas-norte:

  1. Activa l'addon metrics-server i verifica que l'APIService queda AVAILABLE: True.
  2. Obtén les mètriques d'api-reserves sense fer servir kubectl top, parlant directament amb l'API agregada.
  3. Explica d'on va sortir exactament aquell número: quin component el va llegir, d'on i per quina ruta va arribar al teu terminal.

Exercici 2 — Detectar el desequilibri i proposar una recalibració

Aquestes són les dades de dues setmanes de worker-notificacions a rutas-norte-pro:

Percentil 50 CPU:    43m       Percentil 50 memòria:    180Mi
Percentil 70 CPU:    95m       Percentil 95 memòria:    240Mi
Percentil 95 CPU:   380m       Percentil 99 memòria:    268Mi
Percentil 99 CPU:   520m       Màxim memòria:           291Mi

La seva configuració actual:

resources:
  requests:
    cpu: "200m"
    memory: "256Mi"
  limits:
    cpu: "250m"
    memory: "256Mi"
  1. Quina classe de QoS té ara aquest pod? (repassa 03-05)
  2. Identifica dos problemes greus en aquesta configuració a la vista de les dades.
  3. Proposa una configuració nova i justifica cada valor.

Exercici 3 — Diagnosticar un HPA que no escala

Durant un pic de trànsit, api-reserves continua en 4 rèpliques tot i tenir un HPA configurat. Un company et passa aquesta informació:

$ kubectl -n rutas-norte-pro get hpa
NAME           REFERENCE                 TARGETS         MINPODS   MAXPODS   REPLICAS   AGE
api-reserves   Deployment/api-reserves   <unknown>/70%   4         20        4          2d

$ kubectl top pods -n rutas-norte-pro
error: Metrics API not available

$ kubectl -n kube-system get pods -l k8s-app=metrics-server
NAME                              READY   STATUS    RESTARTS      AGE
metrics-server-7bf7d58749-qk4hn   0/1     Running   0             18m
  1. Quina és la relació de causalitat entre els tres símptomes?
  2. Escriu la seqüència d'ordres que executaries per arribar a la causa arrel.
  3. Suposant que el log mostri x509: cannot validate certificate ... because it doesn't contain any IP SANs, què faries a rutas-norte-dev i què faries a rutas-norte-pro?

Solucions

Solució 1

1. Activació i verificació.

minikube addons enable metrics-server -p rutas-norte

# Esperar que el pod estigui llest
kubectl -n kube-system wait --for=condition=Ready pod \
  -l k8s-app=metrics-server --timeout=120s

# Verificar l'APIService
kubectl get apiservice v1beta1.metrics.k8s.io
NAME                     SERVICE                      AVAILABLE   AGE
v1beta1.metrics.k8s.io   kube-system/metrics-server   True        58s

2. Consulta directa a l'API agregada.

kubectl get --raw "/apis/metrics.k8s.io/v1beta1/namespaces/rutas-norte-pro/pods" \
  | jq '.items[] | select(.metadata.name | startswith("api-reserves")) |
        {pod: .metadata.name,
         cpu: .containers[0].usage.cpu,
         memoria: .containers[0].usage.memory}'
{
  "pod": "api-reserves-7d9f8c4b5-x2klm",
  "cpu": "187m",
  "memoria": "312476Ki"
}

També es pot consultar un pod concret:

kubectl get --raw \
  "/apis/metrics.k8s.io/v1beta1/namespaces/rutas-norte-pro/pods/api-reserves-7d9f8c4b5-x2klm" | jq

3. El camí de la dada, pas a pas.

  1. El kernel de Linux comptabilitza l'ús del cgroup del contenidor api a cpuacct.usage i memory.current.
  2. cAdvisor, integrat al binari del kubelet del node on viu aquell pod, llegeix aquells fitxers de cgroup.
  3. El kubelet exposa l'agregat a https://<ip-node>:10250/stats/summary.
  4. metrics-server consulta aquell endpoint cada 15 segons, desa les dues últimes mostres en memòria i calcula la taxa de CPU com (nanocores_t2 - nanocores_t1) / (t2 - t1).
  5. metrics-server serveix el resultat al grup d'API metrics.k8s.io/v1beta1, exposat a través d'un Service a kube-system.
  6. L'APIService v1beta1.metrics.k8s.io fa que l'API Server delegui en aquell Service qualsevol petició a aquell grup.
  7. kubectl demana /apis/metrics.k8s.io/v1beta1/... a l'API Server, que actua de proxy, i retorna el JSON.

El detall essencial: per a kubectl això és indistingible d'un kubectl get pods. Mateix endpoint, mateixa autenticació, mateix RBAC.

Solució 2

1. Classe de QoS.

Perquè un pod sigui Guaranteed, requests i limits han de coincidir en tots els recursos de tots els seus contenidors. Aquí la memòria sí que coincideix (256Mi = 256Mi), però la CPU no (200m ≠ 250m). Per tant la classe de QoS és Burstable: en cas de pressió de memòria al node, aquest pod és candidat al desallotjament abans que qualsevol pod Guaranteed.

2. Els dos problemes greus.

Problema A: throttling sever de CPU. El limits.cpu és 250m, però el percentil 95 de l'ús desitjat és 380m i el percentil 99 arriba a 520m. Això significa que en el 5 % del temps el worker està estrangulat, i en aquest 5 % és precisament quan envia les ràfegues de correus de confirmació. Efecte real per al negoci: els correus de confirmació de compra es retarden justament quan hi ha més compres. A més, kubectl top mostraria el consum enganxat a 250m sense dir que hi ha estrangulament: caldria Prometheus per confirmar-ho.

Problema B: risc d'OOMKilled i request de CPU inflada. El limits.memory és 256Mi i el màxim observat és 291Mi. Ja s'ha superat el límit: aquell worker està sent mort per OOM periòdicament, probablement sense que ningú ho relacioni amb els correus que no arriben. I en l'altre sentit, la requests.cpu: 200m està molt per sobre del p50 de 43m: es reserven 200m dels quals se'n fan servir 43m de mitjana, malbaratant clúster.

3. Configuració proposada.

resources:
  requests:
    # CPU: p70 observat = 95m. La CPU és comprimible: reservar el central
    # i deixar que el limit absorbeixi les ràfegues d'enviament de correus.
    cpu: "100m"
    # Memòria: p99 = 268Mi, màxim 291Mi. Reservem per sobre del màxim
    # observat perquè la memòria NO és comprimible.
    memory: "320Mi"
  limits:
    # 6x la request: cobreix folgadament el p99 de 520m i dóna marge a les
    # ràfegues. En ser comprimible, no hi ha risc que "gasti de més".
    cpu: "600m"
    # Un 20% sobre la request: marge sobre el màxim observat (291Mi)
    # sense permetre una fuita descontrolada.
    memory: "384Mi"

Justificació resumida:

  • requests.cpu baixa de 200m a 100m → s'alliberen 100m per rèplica a la ResourceQuota del namespace.
  • limits.cpu puja de 250m a 600m → desapareix el throttling a les ràfegues.
  • requests.memory puja de 256Mi a 320Mi → per sobre del màxim observat de 291Mi: s'acaben els OOMKilled.
  • limits.memory a 384Mi → marge del 20 % que absorbeix un pic inesperat però talla una fuita de memòria abans que afecti el node.

Nota de procés: aplicar-ho primer a rutas-norte-pre i confirmar amb kubectl top pods --containers durant una setmana que el consum es manté en el rang previst. Confirmar també que el comptador de reinicis (RESTARTS) es queda a zero, que és la prova que els OOMKilled han cessat.

Solució 3

1. Relació de causalitat.

Els tres símptomes són el mateix problema vist des de tres llocs, i la cadena va de baix a dalt:

metrics-server 0/1 (no llest, no pot escanejar els kubelets)
        ↓
El Service de metrics-server no té Endpoints (readiness fallant)
        ↓
L'APIService v1beta1.metrics.k8s.io passa a AVAILABLE: False
        ↓
kubectl top → "Metrics API not available"
        ↓
El controlador de l'HPA no pot llegir les mètriques de CPU
        ↓
HPA amb TARGETS <unknown> → NO ESCALA
        ↓
api-reserves es queda en 4 rèpliques durant el pic de trànsit

Detall important: l'HPA no falla sorollosament. No genera cap esdeveniment d'error visible al Deployment ni deixa l'objecte en estat d'error obvi. Simplement no fa res. Aquesta és la raó per la qual a 07-04 configurarem una alerta específica sobre la condició ScalingActive de l'HPA.

2. Seqüència de diagnòstic.

# 1. Confirmar l'estat de l'APIService (la connexió entre símptomes)
kubectl get apiservice v1beta1.metrics.k8s.io

# 2. Veure per què el pod no està llest: els esdeveniments i la condició Ready
kubectl -n kube-system describe pod -l k8s-app=metrics-server | tail -25

# 3. La causa arrel sol ser al log
kubectl -n kube-system logs -l k8s-app=metrics-server --tail=50

# 4. Confirmar què està dient l'HPA exactament
kubectl -n rutas-norte-pro describe hpa api-reserves | grep -A 10 Conditions

# 5. Verificar connectivitat al kubelet des de dins del clúster (opcional)
kubectl -n kube-system exec deploy/metrics-server -- \
  wget -q -O- --no-check-certificate https://192.168.49.2:10250/healthz

3. Actuació diferenciada per entorn.

A rutas-norte-dev — desbloquejar ràpid, risc acceptable:

kubectl -n kube-system patch deployment metrics-server --type=json \
  -p='[{"op":"add","path":"/spec/template/spec/containers/0/args/-","value":"--kubelet-insecure-tls"}]'

kubectl -n kube-system rollout status deployment/metrics-server
sleep 45
kubectl top nodes

A rutas-norte-pro — el flag no és acceptable. La solució correcta és que el certificat del kubelet el signi la CA del clúster:

  1. Habilitar a cada kubelet la rotació de certificats de servidor:
# /var/lib/kubelet/config.yaml a cada node
serverTLSBootstrap: true
rotateCertificates: true
  1. Reiniciar el kubelet a cada node (systemctl restart kubelet), cosa que genera una CSR per node.

  2. Aprovar les CSR pendents de tipus kubernetes.io/kubelet-serving:

kubectl get csr
kubectl certificate approve <nom-de-la-csr>

En un clúster real això s'automatitza amb un aprovador (per exemple, kubelet-csr-approver), perquè les CSR es renoven periòdicament.

  1. Verificar que metrics-server funciona sense el flag insegur:
kubectl -n kube-system get deploy metrics-server \
  -o jsonpath='{.spec.template.spec.containers[0].args}' | tr ',' '\n'
# No hi ha d'aparèixer --kubelet-insecure-tls

kubectl top nodes

Mesura preventiva imprescindible: que aquest error passés 18 minuts desapercebut durant un pic de trànsit és el veritable problema. A 07-04 crearem una alerta que dispari quan l'APIService de mètriques no estigui disponible o quan un HPA porti més de cinc minuts amb ScalingActive=False. Ningú hauria d'assabentar-se d'això perquè el trànsit cau.

Conclusió

En aquesta lliçó hem instal·lat la primera font de dades de consum real de Rutas Norte i hem après a llegir-la amb criteri:

  • metrics-server no és un sistema de monitoratge, sinó un component d'infraestructura el propòsit del qual és alimentar l'HPA i el VPA. Que kubectl top funcioni és una conseqüència agradable.
  • La dada viatja des dels cgroups del kernelcAdvisor dins del kubelet → la Summary API al port 10250 → metrics-server cada 15 segons → l'APIService de la capa d'agregació → el teu terminal. Entendre aquest camí converteix cada missatge d'error en un diagnòstic.
  • kubectl top nodes dóna percentatges sobre l'allocatable del node; kubectl top pods no dóna percentatges i el desglossament per contenidor amb --containers és imprescindible des que tenim sidecars.
  • El seu ús més valuós avui ha estat tancar el deute de 03-04: hem recalibrat les requests i els limits dels sis components amb dades reals, descobrint que api-reserves estava infradimensionada i patint throttling, que botiga-web reservava quatre vegades el que fa servir, i que el CronJob nocturn trigava el doble del necessari per un límit massa baix.
  • I hem vist els seus límits infranquejables: sense històric, sense consultes, sense alertes, només CPU i memòria, amb una resolució de desenes de segons. Per a "què va passar ahir a la nit a les tres?" no serveix.

Aquesta última limitació és exactament l'esquer de la propera lliçó. Rutas Norte necessita un sistema que recordi, que permeti preguntar i que sàpiga avisar. A 07-03 desplegarem Prometheus amb l'operador que vam anunciar a 06-07, connectarem per fi el sidecar exportador de mètriques de postgres-reserves que vam afegir a 06-04, instrumentarem api-reserves amb mètriques de negoci, i aprendrem PromQL per respondre a preguntes que avui no podem ni formular: quantes reserves per minut es confirmen, quin és el percentil 95 de latència i quant falta perquè s'ompli el disc de la base de dades.

Curs de Kubernetes

Mòdul 1: Introducció a Kubernetes

Mòdul 2: Components Principals de Kubernetes

Mòdul 3: Gestió de Configuració i Secrets

Mòdul 4: Xarxes a Kubernetes

Mòdul 5: Emmagatzematge a Kubernetes

Mòdul 6: Conceptes Avançats de Kubernetes

Mòdul 7: Monitoratge i Registre

Mòdul 8: Seguretat a Kubernetes

Mòdul 9: Escalat i Rendiment

Mòdul 10: Ecosistema i Eines de Kubernetes

Mòdul 11: Estudis de Cas i Aplicacions del Món Real

Mòdul 12: Preparació per a la Certificació de Kubernetes

© Copyright 2026. Tots els drets reservats