Logo

Kubernetes

The OpenMeter Collector is a standalone application you can install in your Kubernetes cluster to meter resource usage, such as Pod runtime CPU, memory, and storage allocation. This is useful if you want to monetize customer workloads like usage-based billing and invoicing.

How it works

You can install the OpenMeter Collector as a deployment in your Kubernetes cluster to collect metrics from your Kubernetes Pods automatically. OpenMeter will then periodically scrape the Kubernetes API to collect runnign pods and resources and emit them as CloudEvents to your OpenMeter instance. This allows you to track usage and billing for your Kubernetes workloads.

Once you have the usage data ingested into OpenMeter, you can use it to setup prices and billing for your customers based on their usage.

Example

Let's say you want to charge your customers $0.05 per CPU-core minute. The OpenMeter Collector will emit the following events every 10 seconds (configurable) from your Kubernetes Pods to OpenMeter Cloud:

{
  "id": "123e4567-e89b-12d3-a456-426614174000",
  "specversion": "1.0",
  "type": "workload",
  "source": "run_ai",
  "time": "2025-01-01T00:00:00Z",
  "subject": "my-customer-id",
  "data": {
    // Metadata
    "pod_name": "my-pod",
    "pod_namespace": "my-namespace",
    // Pod running for 10 seconds
    "duration_seconds": 10,
    // CPU cores used
    "cpu_request_millicores": 0.5,
    "cpu_request_millicores_per_second": 5,
    // Memory used
    "memory_request_bytes": 4294967296,
    "memory_request_bytes_per_second": 42949672960,
    // GPU
    "gpu_type": "A100",
    "gpu_request_count": 1,
    "gpu_request_count_per_second": 10
  }
}
Normalized Usage

Note how the collector normalizes the collected metrics to a second (configurable) making it easy to set per second, minute or hour pricing similar to how AWS EC2 pricing works.

See OpenMeter Billing docs to setup prices and billing for your customers.

Kubernetes Metrics

The collector can meter the following metrics:

  • cpu_request_millicores: The number of CPU cores requested for the pod.
  • cpu_request_millicores_per_second: The number of CPU cores requested per second.
  • cpu_limit_millicores: The number of CPU cores limited for the pod.
  • cpu_limit_millicores_per_second: The number of CPU cores requested per second.
  • memory_request_bytes: The amount of memory requested for the pod.
  • memory_request_bytes_per_second: The amount of memory requested per second.
  • memory_limit_bytes: The amount of memory limited for the pod.
  • memory_limit_bytes_per_second: The amount of memory limited per second.
  • gpu_request_count: The number of GPUs requested for the pod.
  • gpu_request_count_per_second: The number of GPUs requested per second.
  • gpu_limit_count: The number of GPUs limited for the pod.
  • gpu_limit_count_per_second: The number of GPUs limited per second.

Get Started

Follow the steps below to get started with the Kubernetes collector.

Check out the full example

Installation

The simplest method for installing the collector is through Helm:

# Set your OpenMeter token
export OPENMETER_TOKEN=om_...
 
# Get the latest version or visit https://github.com/openmeterio/openmeter/pkgs/container/helm-charts%2Fbenthos-collector
export LATEST_VERSION=$(curl -s https://api.github.com/repos/openmeterio/openmeter/releases/latest | jq -r '.tag_name' | cut -c 2-)
 
# Install the collector in the openmeter-collector namespace
helm upgrade openmeter-collector oci://ghcr.io/openmeterio/helm-charts/benthos-collector \
  --version=${LATEST_VERSION} \
  --install --wait --create-namespace \
  --namespace openmeter-collector \
  --set fullnameOverride=openmeter-collector \
  --set openmeter.token=${OPENMETER_TOKEN} \
  --set preset=kubernetes-pod-exec-time

With the default settings, the collector will report on pods running in the default namespace to OpenMeter every 15 seconds.

Take a look at this example to see the collector in action.

Capture CPU And Memory Limits

A common use case for monetizing workloads running on Kubernetes is to charge based on resource consumption. One way to do that is to include resource limits of containers in the ingested data.

Although it requires a custom configuration, it's straightforward to achieve with the Kubernetes collector:

input:
  # just use the defaults
 
pipeline:
  processors:
    - mapping: |
        root = {
          "id": uuid_v4(),
          "specversion": "1.0",
          "type": "kube-pod-exec-time",
          "source": "kubernetes-api",
          "time": meta("schedule_time"),
          "subject": this.metadata.annotations."openmeter.io/subject".or(this.metadata.name),
          "data": this.metadata.annotations.filter(item -> item.key.has_prefix("data.openmeter.io/")).map_each_key(key -> key.trim_prefix("data.openmeter.io/")).assign({
            "pod_name": this.metadata.name,
            "pod_namespace": this.metadata.namespace,
            "duration_seconds": (meta("schedule_interval").parse_duration() / 1000 / 1000 / 1000).round().int64(),
            "memory_limit": this.spec.containers.index(0).resources.limits.memory,
            "memory_requests": this.spec.containers.index(0).resources.requests.memory,
            "cpu_limit": this.spec.containers.index(0).resources.limit.cpu,
            "cpu_requests": this.spec.containers.index(0).resources.requests.cpu,
          }),
        }
    - json_schema:
        schema_path: 'file://./cloudevents.spec.json'
    - catch:
        - log:
            level: ERROR
            message: 'Schema validation failed due to: ${!error()}'
        - mapping: 'root = deleted()'

Here is the important section from the above configuration:

  "memory_limit": this.spec.containers.index(0).resources.limits.memory,
  "memory_requests": this.spec.containers.index(0).resources.requests.memory,
  "cpu_limit": this.spec.containers.index(0).resources.limit.cpu,
  "cpu_requests": this.spec.containers.index(0).resources.requests.cpu,

It adds the memory and CPU limits and requests to the data section of the CloudEvent. You can tweak the configuration to include other resource limits and requests or resource info for multiple containers as needed.

Start Metering

To get start measuring Kubernetes pod execution time, create a meter in OpenMeter:

Create meter

Configuration

The collector accepts several configuration values as environment variables:

VariableDefaultDescription
SCRAPE_NAMESPACEdefaultThe namespace to scrape. Leave empty to scrape all namespaces.
SCRAPE_INTERVAL15sThe interval for scraping in Go duration format (Minimum interval: 1 second).
BATCH_SIZE20The minimum number of events to wait for before reporting. The collector will report events in a single batch (set to 0 to disable).
BATCH_PERIOD-The maximum duration to wait before reporting the current batch to OpenMeter, in Go duration format.
DEBUGfalseIf set to true, every reported event is logged to stdout.

These values can be set in the Helm chart's values.yaml file using env or envFrom. For more details, refer to the Helm chart reference.

Mapping

The collector maps information from each pod to CloudEvents according to the following rules:

  • Event type is set as kube-pod-exec-time.
  • Event source is set as kubernetes-api.
  • The subject name is mapped from the value of the openmeter.io/subject annotation. It falls back to the pod name if the annotation is not present.
  • Pod execution time is mapped to duration_seconds in the data section.
  • Pod name and namespace are mapped to pod_name and pod_namespace, respectively, in the data section.
  • Annotations labeled data.openmeter.io/KEY are mapped to KEY in the data section, with previous data attributes being given higher priority.

Performance tuning

The ideal performance tuning options for this collector depend on the specific use case and the context in which it is being used. For instance, reporting on a large number of pods infrequently requires different settings than reporting on a few pods frequently. Additionally, accuracy and real-time requirements might influence the selection of appropriate options.

The primary factors influencing performance that you can adjust are SCRAPE_INTERVAL, BATCH_SIZE, and BATCH_PERIOD.

A lower SCRAPE_INTERVAL implies the need for more accurate information about pod execution time, but it also generates more events, leading to increased requests to OpenMeter. To mitigate this, you can raise BATCH_SIZE and/or set or increase BATCH_PERIOD. This approach reduces the number of requests (and the potential for back-pressure) to OpenMeter. However, this means that your more accurate data will be delayed in reaching OpenMeter, resulting in less real-time data.

Managing a large number of pods typically requires a higher SCRAPE_INTERVAL to avoid overburdening the Kubernetes API and OpenMeter. A higher SCRAPE_INTERVAL, though, might lead to less accurate metering.

For additional options to fine-tune performance, please consult the Advanced configuration section.

Advanced configuration

The Kubernetes collector utilizes Redpanda Connect to gather pod information, convert it to CloudEvents, and reliably transmit it to OpenMeter.

The configuration file for the collector is available here.

To tailor the configuration to your needs, you can edit this file and mount it to the collector container. This can be done using the config or configFile options in the Helm chart. For more details, refer to the Helm chart reference.

For additional tips on performance fine-tuning, consult the Redpanda Connect documentation.