Lesson  in  Kubernetes 101

Métricas de recursos con kubectl top

Qué está consumiendo de verdad tu clúster. Descubre la API metrics.k8s.io y quién la sirve, mide Pods y nodos con kubectl top, y aprende la diferencia entre lo que un Pod pide, lo que puede usar y lo que realmente usa.

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 ni requests ni limits. 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:

  1. Cada 15 segundos, pregunta a todos los kubelets del clúster.
  2. 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).
  3. 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.

Note

💡 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é esQuién lo usaDónde se ve
requestsLo que el Pod reservaEl scheduler, para decidir si cabe en un nodokubectl describe pod
limitsLo que el Pod puede llegar a usarEl kubelet y el kernel: throttling de CPU, OOMKill de memoriakubectl describe pod
uso realLo que el Pod está consumiendo ahoraNadie. Es información, no es una reglakubectl 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.

Note

⚠️ 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 requests a 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 top no 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.io la 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.
  • requestslimits ≠ uso real. El nodo se llena con los requests. Un clúster puede estar lleno para el scheduler y vacío en la realidad.
  • Ajustar los requests al uso real (rightsizing) libera capacidad sin tocar la aplicación. Es lo que el VPA automatiza.
  • kubectl top responde al "qué pasa ahora". Para el "qué pasó anoche" y el "avísame cuando" hace falta otra cosa.