Métricas de recursos con kubectl top
Los Events te cuentan lo que pasa. Las métricas te cuentan lo que se consume. Son preguntas distintas y necesitan herramientas distintas.
En este clúster hay tres Pods esperándote, y sus nombres son un spoiler:
kubectl get pods -l escenario=metricas
api: quema CPU sin parar en un bucle infinito.holgazan: reserva 800m de CPU y medio giga de RAM, y no hace absolutamente nada.anonimo: no declara nirequestsnilimits. Para el scheduler, no existe.
Paso 1: ¿De dónde salen las métricas?
Kubernetes no guarda métricas. El API server no sabe cuánta CPU consume un Pod, y no le interesa: su trabajo es guardar el estado deseado, no medir el mundo.
Lo que sí tiene es un mecanismo para que otro componente sirva esa información como si fuera parte de la API. Se llama API Aggregation, y se ve así:
kubectl get apiservice v1beta1.metrics.k8s.io
kubectl get apiservice v1beta1.metrics.k8s.io -o yaml
Fíjate en spec.service: el grupo metrics.k8s.io no lo sirve el kube-apiserver. Lo sirve un Service, en un namespace, como cualquier otra aplicación. El API server hace de proxy hacia él.
Esa aplicación es metrics-server, y su funcionamiento es más humilde de lo que la gente supone:
- Cada 15 segundos, pregunta a todos los kubelets del clúster.
- Cada kubelet le devuelve el consumo de CPU y memoria de sus contenedores (que a su vez saca de los cgroups del kernel, vía cAdvisor).
- metrics-server lo guarda en memoria.
No hay base de datos. No hay histórico. Si reinicias metrics-server, se pierde todo, y solo sabe lo que ha pasado en los últimos segundos.
💡 Esto explica un error que verás en clústeres reales: error: Metrics API not available. No es un fallo de kubectl ni de Kubernetes: es que nadie ha instalado metrics-server. Muchas distribuciones (k3s entre ellas) lo traen de serie; kubeadm, por ejemplo, no.
Paso 2: kubectl top
Ahora que sabes de dónde salen los datos, mídelos:
kubectl top nodes
kubectl top pods
kubectl top pods --containers
kubectl top pods --sort-by=cpu
api está clavado en su límite de CPU. El holgazan y el anonimo consumen migajas.
Guarda el listado ordenado por CPU:
kubectl top pods --sort-by=cpu > /home/laborant/consumo.txt
cat /home/laborant/consumo.txt
Paso 3: Las tres cifras que no son la misma cifra
Aquí está la lección de esta unidad, y es la que más dinero ahorra de todo el curso.
Para un mismo contenedor hay tres números distintos, y confundirlos es el error más caro y más común en Kubernetes:
| Qué es | Quién lo usa | Dónde se ve | |
|---|---|---|---|
requests | Lo que el Pod reserva | El scheduler, para decidir si cabe en un nodo | kubectl describe pod |
limits | Lo que el Pod puede llegar a usar | El kubelet y el kernel: throttling de CPU, OOMKill de memoria | kubectl describe pod |
| uso real | Lo que el Pod está consumiendo ahora | Nadie. Es información, no es una regla | kubectl top |
Y ahora lo importante: el nodo se llena con los requests, no con el uso real.
Compruébalo. Mira lo que el nodo tiene reservado:
kubectl describe node | grep -A12 "Allocated resources"
Y compáralo con lo que se usa de verdad:
kubectl top node
kubectl top pods
Los dos números no se parecen en nada. El holgazan tiene 800m de CPU reservados y no consume prácticamente nada: esos 800m están apartados para él, y ningún otro Pod puede usarlos. El nodo puede rechazar un Pod nuevo por falta de CPU mientras está al 5 % de uso real.
Esto es, exactamente, por qué un clúster puede estar simultáneamente lleno y vacío. Y por qué existe el VPA.
⚠️ Cuidado con el extremo opuesto: el Pod anonimo no reserva nada. Para el scheduler ocupa cero, así que cabe en cualquier sitio, siempre. Suena estupendo hasta que el nodo se satura y el kubelet tiene que desalojar Pods: al no tener requests, su clase QoS es BestEffort y es el primero en caer. No poner requests no es ahorrar: es renunciar a cualquier garantía.
Paso 4: Arregla al holgazán
Ya tienes el dato. Ahora úsalo: crea un holgazan-ajustado con los requests que kubectl top dice que necesita de verdad.
cat << 'EOF' > holgazan-ajustado.yaml
apiVersion: v1
kind: Pod
metadata:
name: holgazan-ajustado
spec:
containers:
- name: web
image: ghcr.io/iximiuz/labs/nginx:alpine
resources:
requests:
cpu: "20m" # <- lo que kubectl top dice de verdad
memory: "32Mi"
limits:
cpu: "200m" # margen para picos
memory: "128Mi"
EOF
kubectl apply -f holgazan-ajustado.yaml
kubectl describe node | grep -A12 "Allocated resources"
Fíjate en lo que acaba de pasar: has liberado 780m de CPU del nodo sin cambiar una línea de la aplicación. Ese es el trabajo, poco glamuroso y muy rentable, del rightsizing.
Paso 5: Los límites de kubectl top
kubectl top es la herramienta correcta para tres preguntas:
- ¿Qué está consumiendo ahora mismo?
- ¿Qué Pod se ha desbocado?
- ¿Se parecen mis
requestsa la realidad?
Y es completamente inútil para estas otras:
- ¿Qué pasó anoche a las 3:00?
- ¿Este consumo es normal para un lunes?
- ¿Cuántas peticiones por segundo atiende mi API? (
kubectl topno sabe nada de tu aplicación: solo ve CPU y memoria) - Avísame cuando algo vaya mal.
Cuatro preguntas, un único hueco: no hay histórico, no hay métricas de aplicación y no hay alertas. Eso es exactamente lo que vas a montar en la lección siguiente.
Resumen
- Kubernetes no guarda métricas. La API
metrics.k8s.iola sirve metrics-server, agregada a la API del clúster, y guarda los datos en memoria: sin histórico. - Sin metrics-server no hay
kubectl top, y tampoco hay HPA ni VPA. requests≠limits≠ uso real. El nodo se llena con losrequests. Un clúster puede estar lleno para el scheduler y vacío en la realidad.- Ajustar los
requestsal uso real (rightsizing) libera capacidad sin tocar la aplicación. Es lo que el VPA automatiza. kubectl topresponde al "qué pasa ahora". Para el "qué pasó anoche" y el "avísame cuando" hace falta otra cosa.
- Previous lesson
- Events, la primera línea de diagnóstico
- Next lesson
- Despliega un stack de observabilidad