kodebeat / papers / families

Standing up energy and cost observability on Kubernetes

Terraform and Helm modules for the measurement stack.

Ten Terraform modules distributing the GreenOps measurement stack: Prometheus and Grafana, Kepler and Scaphandre for hardware power, CodeCarbon, OpenCost, grid-intensity data, and KEDA and KubeGreen for acting on what you learn. The umbrella module defaults to observability-only, so the first apply cannot disturb production. The problem it solves is assembly: nine upstream projects whose interactions are mostly discovered by failing.

The problem

An organisation decides to measure the energy and carbon footprint of its Kubernetes estate. The components are all open source, well regarded and individually documented. The work looks like an afternoon.

It is not an afternoon, for reasons that only show once the work starts:

Nothing works without Prometheus. Kepler, Scaphandre, OpenCost and the carbon-intensity exporter all export metrics and none stores them. So the real first task is a monitoring stack, with the storage, retention and dashboard decisions that come with it.

Kepler needs cert-manager, and fails quietly without it. The Kepler Operator requires cert-manager to be installed before deployment. A cluster without it produces an operator that comes up and does not work, and the diagnosis is not in the pod logs where you would look first.

Scaphandre needs the host. Container-level power monitoring reads /proc and /sys, which means Linux nodes and privileged access. On a managed control plane, or a provider that does not expose the underlying hardware counters, the numbers are unavailable or wrong, and the tool does not announce this.

The tools overlap and disagree. Kepler and Scaphandre both report power. CodeCarbon reports emissions at the application level. Cloud Carbon Footprint estimates from billing data. Four numbers, four methodologies, and no guidance about which to trust for which question; a team that deploys all four without understanding the differences ends up with a dashboard nobody believes.

And some of these tools change things. kube-green hibernates workloads. KEDA scales them. Both are valuable and both act on your cluster, which makes the "just deploy the stack and see" approach unsafe in the environment where the measurements would matter most.

The afternoon becomes a multi-week project, and in the author's experience it stalls where Kepler is producing no metrics and nobody knows why.

The method

One module per component, each usable alone. The nine component modules are standalone: fabiocicerchia/kepler/helm deploys Kepler and nothing else. A team that already has Prometheus and only wants power metrics takes one module. This matters because most teams do not arrive with a blank cluster.

A uniform, small interface. The eight Helm modules expose the same four inputs and three outputs (Cloud Carbon Footprint adds two service-URL outputs); terraform-kubernetes-codecarbon and the umbrella differ, as described under Architecture:

The values passthrough is the design decision that keeps the modules small. A module that re-exposed every chart setting as a typed Terraform variable would be a second, always-stale copy of the chart's own interface. Passing values straight through means the module never blocks a setting the chart supports, and never needs updating when the chart adds one. The cost is that values is untyped (any), so mistakes surface at apply time rather than at plan time.

Observability-first by default, and say so loudly. The umbrella module's default posture, in the README's own list (with Scaphandre added from variables.tf):

  • Enabled: Prometheus, Kepler, OpenCost, CodeCarbon (safe, read-only monitoring).
  • Disabled: KEDA, kube-green, the carbon-intensity exporter, Cloud Carbon Footprint and Scaphandre, because they require configuration, perform actions, or, in Scaphandre's case, overlap with Kepler.

A stack that hibernated a namespace on first apply would be uninstalled the same day. Measurement is the default; anything that touches workloads is opt-in and requires an explicit line in the configuration.

Dependencies are declared, not hidden. cert-manager is a stated prerequisite that no module installs: the Kepler module deploys the operator only, and its README gives the one-line install (cert-manager v1.18.2 or later) to run first, because the failure mode without it is silent. Scaphandre's need for Linux nodes with /proc and /sys access is likewise stated in the module's own Requirements section rather than left to be discovered.

The headline results

  • What these modules assert:
  • What the upstream tools assert:
  • The error bars are largely environmental.
  • What is verifiable locally:

The full results, with the tables and the reasoning behind each figure, are in the PDF.

What is in the PDF

  • The problem — what goes unanswered without it, and who notices first.
  • Why the obvious alternative falls short — stated plainly, including where it is the better choice.
  • How it works — the method, not a feature list.
  • Concrete use cases — with console output quoted from the repository, never reconstructed.
  • The methodology behind any number it emits — every term shown, so the figure survives a question.
  • What it deliberately does not do — the section most papers leave out.

Part of the catalogue.

Get the PDF

This paper already selected; the download starts when you send the form. No follow-up sequence.

Get the PDF