---
title: "Medir la energía en producción: Kepler, DCGM y el stack práctico (precisión y overhead)"
url: https://blog.lo0.es/posts/herramientas-energia-deploy-precision-overhead/
markdown: https://blog.lo0.es/posts/herramientas-energia-deploy-precision-overhead/index.md
lang: es
date: 2026-06-14
lastmod: 2026-08-30
author: "José Manuel Román"
description: "Deep dive práctico de las herramientas de energía: cómo se despliega el stack de medición en Kubernetes (DCGM exporter + Kepler eBPF + Prometheus + Grafana), de qué fuentes saca cada una el dato, qué precisión tiene frente a un vatímetro, cuánto overhead añade, cómo se atribuye la energía por pod y MIG, y cómo elegir el stack. Con comandos y fuentes."
tags: ["energia","kepler","dcgm","ebpf","prometheus","zeus","kubernetes","carbono","serie-datos"]
translations:
  en: https://blog.lo0.es/en/posts/measuring-energy-in-production-kepler-dcgm-stack/index.md
---

# Medir la energía en producción: Kepler, DCGM y el stack práctico (precisión y overhead)


> Notación: importes en **euros (N €)**, decimales con coma. No se usa el símbolo de dólar
> (en este sitio es delimitador de fórmula).

## Qué cubre este artículo

Tercer artículo del track de **energía** (C3). En C1 se hizo el inventario conceptual de las
herramientas; aquí entramos en lo **práctico**: cómo se **despliega** el stack de medición en
Kubernetes, de dónde saca el dato cada pieza, qué **precisión** tiene frente a un vatímetro, cuánto
**overhead** añade y cómo se **atribuye** la energía por pod y por instancia MIG. Es el equivalente
del B2/B3 para energía: dejar de hablar de qué mide cada herramienta y empezar a montar el banco que
lo mide. Con comandos; sin recomendaciones, solo la mecánica.

---

## El stack de medición en Kubernetes

Para medir energía por carga en un cluster GPU, el stack práctico tiene cuatro piezas, y la buena
noticia es que **tres de ellas ya las tienes** si haces observabilidad:

> **Diagrama:** Stack de medición de energía en Kubernetes: DCGM exporter y Kepler exportan a Prometheus, que Grafana visualiza, con el vatímetro como calibracion — [verlo en la versión HTML](https://blog.lo0.es/posts/herramientas-energia-deploy-precision-overhead/)

La pieza nueva frente a un stack de observabilidad normal es **Kepler**, que añade la **atribución de
energía por pod**. DCGM ya da la potencia de la GPU; Prometheus la almacena; Grafana la pinta. Es
infraestructura reutilizada, no un sistema nuevo, en línea con la [observabilidad GPU por DCGM](https://blog.lo0.es/posts/observabilidad-gpu-dcgm-llm/index.md).

---

## DCGM exporter: la base de la potencia de GPU

La potencia de la GPU —la fuente dominante en inferencia LLM— sale del **dcgm-exporter** de NVIDIA
(parte del GPU Operator), que expone métricas DCGM a Prometheus. La métrica clave es
`DCGM_FI_DEV_POWER_USAGE` (potencia instantánea en W), junto con utilización
(`DCGM_FI_DEV_GPU_UTIL`) y memoria. Con eso, la energía es la integral de la potencia en el tiempo
sobre la ventana de la carga. DCGM da la potencia **a nivel de tarjeta**; para repartirla por pod o
por instancia MIG hace falta una capa encima —Kepler—.

---

## Kepler a fondo: eBPF y las fuentes

**Kepler** (Kubernetes-based Efficient Power Level Exporter) es un exporter de Prometheus que mide
energía a nivel de **contenedor, pod y nodo**, usando **eBPF para reducir el overhead** y métodos
científicos para mejorar la precisión ([Kepler · GitHub](https://github.com/sustainable-computing-io/kepler)).
Su fortaleza es que **combina varias fuentes** de potencia:

| Fuente | Qué cubre |
|---|---|
| **RAPL** | CPU y DRAM |
| **NVML** | potencia de GPU NVIDIA |
| **ACPI** | gestión de energía de la plataforma |
| **Redfish / IPMI** | potencia de plataforma (BMC) |
| **Modelos de regresión** | estimación cuando no hay métrica real |

Para la GPU, el parámetro **`dcgmEndpoint`** apunta a la URL de métricas del dcgm-exporter, lo que
permite la **atribución de potencia por instancia MIG** ([Kepler · configuración](https://github.com/sustainable-computing-io/kepler/blob/main/docs/user/configuration.md)).
Es decir: DCGM da la potencia de la tarjeta, Kepler la reparte entre los pods (y las particiones MIG)
que la usan, vía eBPF y modelos. El resultado son métricas de energía por pod en Prometheus, listas
para Grafana, usables para **scheduling o scaling, reporte de consumo y visualización**
([Kepler · GitHub](https://github.com/sustainable-computing-io/kepler)).

> **Diagrama:** Kepler combina RAPL, NVML/DCGM, ACPI y Redfish, y con eBPF reparte la energia por pod y por instancia MIG — [verlo en la versión HTML](https://blog.lo0.es/posts/herramientas-energia-deploy-precision-overhead/)

---

## Despliegue: DaemonSet sobre Prometheus

El despliegue es un **DaemonSet** (un Kepler por nodo), apuntando al Prometheus existente y al
dcgm-exporter:

```bash
# Helm, apuntando al dcgm-exporter para la atribución de GPU
helm install kepler kepler/kepler \
  --namespace kepler --create-namespace \
  --set dcgmEndpoint="http://dcgm-exporter:9400/metrics"
```

Prerrequisitos: un kernel con eBPF, el dcgm-exporter corriendo (del GPU Operator) y Prometheus
scrapeando. Una vez desplegado, Kepler expone métricas como `kepler_container_joules_total` por pod,
que se consultan con PromQL y se pintan en Grafana. La energía por carga deja de ser una estimación
manual y pasa a ser una serie temporal continua, igual que el coste con OpenCost.

---

## Consultas PromQL: energía por pod

Con Kepler exportando, las consultas que construyen los paneles. Los nombres exactos varían por
versión; comprueba en tu `/metrics`:

```promql
# Energía acumulada por pod (julios)
kepler_container_joules_total

# Potencia media por namespace en la última hora (W)
sum by (namespace) (rate(kepler_container_joules_total[1h]))

# Potencia de GPU por nodo (de DCGM, W)
sum by (node) (DCGM_FI_DEV_POWER_USAGE)

# Energía por token: potencia ÷ throughput (con métrica del gateway/motor)
sum(rate(kepler_container_joules_total[5m])) / sum(rate(vllm_generation_tokens_total[5m]))
```

La última es la que cierra el círculo con el track de coste: cruza la energía de Kepler con los
tokens del motor/gateway para dar **J/token en tiempo real**, por carga. Con eso en Grafana, tienes
energía por pod, por namespace y por token, en continuo —el equivalente energético del informe de
coste de OpenCost—.

---

## Un procedimiento de calibración

Como Kepler estima, conviene calibrar una vez por tipo de nodo. Un procedimiento simple:

1. **Vatímetro a la entrada** del nodo (o lectura del PDU/BMC), midiendo la potencia real del nodo.
2. **Carga controlada**: un sweep estable a una potencia conocida (p. ej. el motor al 80 % de GPU).
3. **Comparar**: la suma de `kepler_container_joules_total` del nodo + el idle frente a la lectura del
   vatímetro en la misma ventana.
4. **Ajustar** el factor o el modelo de Kepler si la desviación es notable, y documentar el error
   residual.
5. **Repetir** por cada tipo de nodo (la calibración no es transferible entre hardware distinto).

Con ese error residual documentado, el dato continuo de Kepler tiene una **barra de error conocida**,
que es justo lo que un auditor de CSRD o un comité técnico va a pedir. Medir sin calibrar da un número
sin credibilidad; calibrar una vez convierte la estimación continua en un dato defendible.

---

## Precisión: estimación vs vatímetro

La honestidad de datos del track de energía: Kepler **estima** (eBPF + modelos + contadores), no
mide con un vatímetro. La precisión depende de la fuente: con NVML/DCGM y RAPL disponibles, el dato
es bastante fiel (lee contadores de hardware); cuando cae en **modelos de regresión** (sin métrica
real), es una estimación con más error. La buena práctica: **calibrar contra un vatímetro físico al
menos una vez** por tipo de nodo, ajustar, y usar Kepler como proxy continuo. El vatímetro es la
verdad-terreno puntual; Kepler, la serie continua calibrada contra ella. Para un reporte CSRD que un
auditor pueda cuestionar, esa calibración inicial es lo que da credibilidad al dato continuo.

---

## Overhead: el coste de medir

Medir energía tiene su propio coste de cómputo, que conviene presupuestar. En un entorno Kubernetes,
el overhead del sistema de monitorización lo reparten el servidor de Prometheus y los targets: el
**Prometheus server consume ~150 % de CPU (1,5 cores) y ~15 GB de RAM**, mientras que los targets
(node exporter y dcgm-exporter) usan en conjunto **~35 % de CPU y ~300 MB de RAM**
([arXiv · Container-level Energy Observability](https://arxiv.org/pdf/2504.10702)). Kepler usa eBPF
precisamente para mantener bajo su propio overhead. La lectura: el grueso del coste de medir está en
el **Prometheus** (que probablemente ya tienes para observabilidad), no en los exporters de energía.
Añadir Kepler a un stack de observabilidad existente es marginal; montar Prometheus solo para esto
sería caro. Por eso medir energía es casi gratis si ya observas, y un proyecto si no.

---

## Zeus: para banco y optimización, no para producción continua

**Zeus** (ml.energy) juega un papel distinto: no es un exporter continuo de producción, es la
herramienta de **banco** para medir **y optimizar** la energía de una carga concreta (un benchmark,
un entrenamiento), con **power capping** y selección de frecuencia. Encaja en el flujo de
benchmarking (junto a GuideLLM/AIPerf): durante un sweep, Zeus mide la energía por configuración y
permite probar el efecto del power capping en el rendimiento. La división práctica: **Kepler/DCGM en
producción** (atribución continua por pod), **Zeus en el banco** (medición fina + optimización de una
carga), **CodeCarbon** si quieres el contexto de carbono integrado en un pipeline de ML.

---

## CodeCarbon y Scaphandre en la práctica

Las otras dos piezas, con su rol concreto:

- **CodeCarbon** se integra **dentro del código** de un pipeline de ML (un decorador o un context
  manager que envuelve el entrenamiento o la inferencia), y devuelve la energía y el **CO₂eq** de ese
  bloque, usando `nvidia-smi` para la GPU y estimando CPU/RAM. Encaja cuando quieres el dato de
  carbono **por experimento** o por job de ML, integrado en el flujo de datos, no a nivel de
  infraestructura. Es el más cercano al vatímetro entre los Python.
- **Scaphandre** es un agente de metrología en Rust que lee **RAPL** y da la potencia de proceso/VM
  con precisión cruda de hardware. Para CPU es muy preciso; para GPU hay que combinarlo con NVML.
  Encaja cuando necesitas la metrología de CPU más fiel, o un agente ligero independiente de
  Kubernetes.

La división con Kepler: **Kepler** atribuye energía por pod en el cluster (la vista de
infraestructura); **CodeCarbon** da el carbono por job de ML (la vista de pipeline); **Scaphandre**
da la metrología cruda de CPU. No compiten; cubren capas distintas, y una plataforma madura usa la
que corresponde a cada pregunta.

---

## Elegir el stack por objetivo

| Objetivo | Herramienta | Por qué |
|---|---|---|
| Atribución continua por pod (producción) | **Kepler + DCGM** | eBPF, por pod/MIG, a Prometheus |
| Medición fina + optimización (banco) | **Zeus** | mide y optimiza (power capping) |
| Carbono en un pipeline de ML | **CodeCarbon** | CO₂eq integrado, cercano al vatímetro |
| Precisión cruda de CPU (RAPL) | **Scaphandre** | metrología de hardware |
| Calibración / verdad-terreno | **vatímetro** | el patrón contra el que calibrar todo |

No es "una herramienta", es un **stack por objetivo**: producción continua (Kepler/DCGM), banco
(Zeus), reporte (CodeCarbon), calibración (vatímetro). Mezclarlos según la fase es lo que da una
medición de energía completa y creíble.

---

## Del dato a la acción

Medir es el principio; el valor está en actuar. Con la energía por pod en Prometheus:

- **Reporte (CSRD)**: la huella de carbono por carga, calibrada, lista para el reporte regulatorio.
- **Scheduling por energía/carbono**: mover carga diferible a horas o nodos de menor intensidad
  (conecta con el carbono horario de la red española).
- **Power capping**: con Zeus, recortar la potencia de pico con poca pérdida de rendimiento, bajando
  los W del numerador de J/token.
- **Optimización**: identificar pods con mala eficiencia energética (mucha energía por token) y
  atacarlos con cuantización o batching.

El stack de medición no es un panel para mirar: es la entrada de decisiones de scheduling,
optimización y reporte. Igual que OpenCost cierra el bucle del coste, Kepler+DCGM cierra el de la
energía.

---

## De la energía al carbono: la capa final

El dato de energía (kWh) se convierte en carbono multiplicando por la **intensidad de red**, y aquí
el stack práctico se conecta con la fuente horaria. En España, la intensidad la publica **Red
Eléctrica (esios)** y la agrega **ElectricityMaps**, hora a hora. El patrón:

```promql
# Carbono por carga: energía (kWh) × intensidad de red (gCO2/kWh)
(sum by (namespace) (increase(kepler_container_joules_total[1h])) / 3.6e6)
  * on() group_left() grid_carbon_intensity_gco2_kwh
```

donde `grid_carbon_intensity_gco2_kwh` es una métrica que alimentas desde esios/ElectricityMaps (un
exporter o un push periódico). Con eso, el panel de Grafana muestra **gCO₂ por namespace y por
token, hora a hora**, no una media anual. Y como la intensidad española varía mucho (de ~80 en horas
solares a ~250 en noches de gas), esa resolución horaria es la que habilita el **scheduling
consciente del carbono**: mover lo diferible a las horas limpias baja el carbono medido. El stack de
medición no solo reporta el carbono; con el dato horario, **permite reducirlo**.

---

## KPIs de eficiencia energética a vigilar

| KPI | Qué indica | De dónde |
|---|---|---|
| **J/token por modelo** | eficiencia energética | Kepler ÷ tokens del motor |
| **Potencia media por pod** | consumo por carga | `rate(kepler_container_joules_total)` |
| **gCO₂/token (horario)** | huella real | energía × intensidad de red |
| **Energía en idle** | desperdicio | potencia de pods sin tráfico |
| **PUE efectivo** | overhead del DC | energía total ÷ energía de cómputo |

Estos cinco convierten el panel de energía en una herramienta de decisión: qué modelo es más
eficiente, qué pod desperdicia, cuándo conviene schedulear. Sin ellos, el stack es un panel bonito;
con ellos, es la entrada de optimización y reporte.

---

## Ejemplo: atribución de energía en un cluster multi-tenant

Con Kepler repartiendo por pod, un informe de energía por equipo sobre el nodo de ejemplo (8×H100,
5,6 kW de placa, ~7,84 kW con PUE), un mes:

| Equipo | Energía/mes (kWh) | gCO₂ (red ES ~160) | J/token medio |
|---|---|---|---|
| A · chat-prod | ~3.100 | ~496 kg | ~2,2 J/tok |
| B · batch | ~1.400 | ~224 kg | ~2,8 J/tok |
| C · experimentación | ~900 | ~144 kg | ~6,5 J/tok |
| idle | ~250 | ~40 kg | — |

Lo que revela: A es eficiente (FP8, alta utilización → 2,2 J/token); C es **ineficiente** (6,5
J/token, GPU infrautilizada), igual que arrastraba el coste de idle en el track de FinOps. La columna
de carbono lleva el dato al reporte CSRD por equipo. Y la fila **idle** (~250 kWh, ~40 kg CO₂) es
energía pura desperdiciada. Sin Kepler, ese reparto no existe: solo verías el consumo total del nodo,
sin saber de quién es cada vatio. Con él, la energía es atribuible y accionable, exactamente como el
coste con OpenCost —de hecho, los dos paneles juntos (coste de OpenCost + energía de Kepler) dan la
imagen completa de eficiencia por equipo.

---

## Scheduling consciente de energía y carbono

La acción de mayor retorno que habilita el stack: **schedulear según energía y carbono**. Con la
energía por pod y la intensidad horaria de red en Prometheus, dos políticas:

- **Por carbono**: mover la carga **diferible** (entrenamiento, ingestión, batch nocturno) a las
  horas de menor intensidad de red —en España, las horas de máxima solar (~80 gCO₂/kWh) frente a las
  noches de gas (~250)—. La misma carga emite ~3× menos schedulada a la hora correcta.
- **Por eficiencia**: consolidar cargas para eliminar el idle (la GPU encendida sin trabajo es
  energía tirada), y dirigir cada carga al hardware más eficiente para ella.

Ambas usan el mismo dato (energía por pod + intensidad horaria) que el stack ya expone, y conectan
con el scheduling del cluster (Kueue/Volcano). Es la diferencia entre **medir** el carbono (y
reportarlo) y **reducirlo** (schedulando). El stack de C3 habilita las dos.

---

## Checklist de despliegue

| Paso | Acción | Verificación |
|---|---|---|
| 1 | dcgm-exporter (GPU Operator) | `DCGM_FI_DEV_POWER_USAGE` en Prometheus |
| 2 | Kepler DaemonSet, kernel con eBPF | `kepler_container_joules_total` por pod |
| 3 | `dcgmEndpoint` apuntando al exporter | atribución de GPU/MIG funciona |
| 4 | Métrica de intensidad de red (esios) | `grid_carbon_intensity` en Prometheus |
| 5 | Calibración vs vatímetro (1 vez/tipo nodo) | barra de error documentada |
| 6 | Paneles Grafana (J/token, carbono, idle) | KPIs visibles |

El paso 5 (calibración) es el que más se salta y el que da credibilidad al dato; el paso 3
(`dcgmEndpoint`) es el que más se olvida y sin el cual la GPU no se atribuye.

---

## Energía por fase: prefill vs decode

Un nivel de detalle que el stack permite y que orienta la optimización: la potencia **no es constante**
durante una petición. El **prefill** (procesar el prompt) es compute-bound y tira mucha potencia en
ráfaga; el **decode** (generar tokens) es memory-bound y consume menos pico pero durante más tiempo.
Con un muestreo fino de DCGM se ve ese perfil bimodal, y eso tiene consecuencias:

- Una carga con prompts largos (mucho prefill) tiene un perfil de potencia distinto a una de
  generación larga (mucho decode), aunque produzcan los mismos tokens.
- El **power capping** afecta distinto a cada fase: recortar la potencia de pico toca sobre todo el
  prefill.

Para la mayoría de casos basta el J/token medio; para optimizar la eficiencia energética a fondo,
separar el consumo de prefill y decode (alineando la ventana de DCGM con cada fase) revela dónde está
el gasto. Es el equivalente energético de separar TTFT y TPOT en el benchmarking —el mismo principio,
medir las dos fases por separado porque se comportan distinto—.

---

## Estado del arte: el hueco de la resolución LLM

Una nota honesta sobre los límites del tooling actual. Las herramientas generalistas (Kepler,
CodeCarbon, Scaphandre) miden bien a nivel de **máquina, proceso y pod**, pero **carecen de
resolución específica de LLM**: no distinguen de serie la energía de prefill vs decode, ni la energía
por token por fase, ni el coste energético de un bloque de razonamiento frente a una respuesta normal.
Es un hueco abierto del campo: la atribución por pod existe, pero la atribución **por token y por fase
de inferencia** hay que construirla cruzando la potencia (DCGM/Kepler) con las métricas del motor
(vLLM expone tokens por fase). El estado del arte de 2026 es un stack maduro para la **infraestructura**
y emergente para la **resolución específica de LLM** —exactamente el cruce que el harness reproducible
(S4) tiene que montar a mano—. Reconocerlo evita prometer una precisión por token que las herramientas
generalistas no dan solas.

---

## Límites y trampas (data-driven)

1. **Estimación sin calibrar.** Kepler estima; sin calibrar contra un vatímetro al menos una vez, el
   dato puede tener error notable, especialmente cuando cae en modelos de regresión.
2. **Olvidar el `dcgmEndpoint`.** Sin apuntar Kepler al dcgm-exporter, la atribución de GPU (y MIG)
   no funciona; es el parámetro clave para GPU.
3. **Contabilizar el overhead mal.** El grueso del coste de medir está en Prometheus; si lo montas
   solo para energía, presupuéstalo (1,5 cores, 15 GB).
4. **Confundir banco y producción.** Zeus mide fino una carga; Kepler atribuye continuo en
   producción. Usar uno por el otro da el dato equivocado.
5. **Ventanas desalineadas.** Para energía por token, la ventana de potencia y la de tokens deben
   coincidir; si no, el J/token no corresponde.

Con el stack de medición montado, el track de energía tiene su instrumentación; los artículos
siguientes (C6 carbono, C8 TCO y regulación) construyen sobre estos datos. El cimiento es este: una
medición continua por pod, calibrada, sobre la infraestructura de observabilidad que ya tienes.

## Cierre

Medir la energía de un cluster de IA en producción no requiere un sistema nuevo: requiere **añadir
Kepler** —atribución por pod vía eBPF— al stack de DCGM, Prometheus y Grafana que ya tienes para
observabilidad. Esa es la idea central de C3: el coste de medir está casi todo en el Prometheus que
ya pagas, y Kepler lo convierte de "potencia de la tarjeta" en "energía por pod, por equipo y por
token". Con dos cautelas que separan un dato creíble de un panel decorativo: **calibrar una vez
contra un vatímetro** (para tener una barra de error que aguante una auditoría) y **apuntar el
`dcgmEndpoint`** (sin el cual la GPU no se atribuye). Hecho así, la energía deja de ser el eje blando
de la sostenibilidad y pasa a ser una serie temporal accionable: el J/token por modelo que delata la
ineficiencia, el carbono horario que habilita el scheduling limpio, el idle que se recupera, y el
reporte CSRD que se sostiene. Para la plataforma soberana, el stack Kepler+DCGM cierra el bucle de la
energía igual que OpenCost cierra el del coste —y juntos, con el goodput de GuideLLM, dan las tres
caras del cuadro de mando medidas sobre el mismo hierro, en euros, julios y gramos de CO₂.

## Ver también

- [MLPerf Power](https://blog.lo0.es/posts/mlperf-power-eficiencia-energetica/index.md) — la medición a la pared estándar (PTDaemon), complementaria a la instrumentación software (DCGM/RAPL/Kepler).
- [Medir la potencia de una GPU: NVML, DCGM y los errores de muestreo](https://blog.lo0.es/posts/medir-potencia-gpu-nvml-dcgm/index.md) — la metrología del sensor que alimenta a todas estas herramientas: ventana de promediado, contador acumulado y qué queda fuera del contador.
- [Leaderboards de eficiencia energética de LLMs](https://blog.lo0.es/posts/leaderboards-energia-llm/index.md) — dónde van a parar los J/token que estas herramientas producen: los rankings públicos y cómo interpretarlos sin dejarse engañar por el setup.
- [Del vatio al carbono: PUE, intensidad de la red y el coste real de un token](https://blog.lo0.es/posts/del-vatio-al-carbono-pue-grid/index.md) — el paso de conversión de vatios medidos a gCO₂eq y a euros, aplicando PUE del datacenter e intensidad de la red eléctrica del país.
- [Palancas de eficiencia energética en inferencia LLM](https://blog.lo0.es/posts/palancas-eficiencia-energetica-inferencia/index.md) — las optimizaciones que reducen el consumo que estas herramientas miden: quantization, batching, motor y schedulers de potencia.

## Fuentes

- Kepler · GitHub (CNCF, eBPF, por pod/nodo) — https://github.com/sustainable-computing-io/kepler
- Kepler · configuración (fuentes, dcgmEndpoint para MIG) — https://github.com/sustainable-computing-io/kepler/blob/main/docs/user/configuration.md
- CNCF · explorando Kepler (consumo de aplicaciones cloud) — https://www.cncf.io/blog/2023/10/11/exploring-keplers-potentials-unveiling-cloud-application-power-consumption/
- Red Hat · Kepler: monitorización eficiente de energía para Kubernetes — https://next.redhat.com/2023/08/22/introducing-kepler-efficient-power-monitoring-for-kubernetes/
- arXiv · Container-level Energy Observability in Kubernetes (overhead) — https://arxiv.org/pdf/2504.10702
- NVIDIA · dcgm-exporter — https://github.com/NVIDIA/dcgm-exporter
- Zeus Project (ml.energy) — https://ml.energy/zeus/

