Skip to content

grem11n/cost-exporter

Repository files navigation

Cost Exporter

Version License Artifact Hub Go Report Lint Unit Tests Helm Tests

Cost Exporter is a small tool that gets your cost and usage metrics from AWS Cost Explorer and outputs them in the Prometheus format.

SWUbanner

Table of Contents

  1. Motivation
  2. Usage
    1. Kubernetes
    2. Configuration
    3. Prometheus
  3. Observability
    1. Metrics
    2. Logs
  4. Implementation
  5. Further Thoughts
    1. Adding More Clients, Converters, and Outputs
    2. Other Improvements
  6. Contribution
  7. Inspiration

Motivation

The main motivation for this project is because I can.

There are other similar projects out there (see the "Inspiration" section) but each of them seems to solve a very special use case of their respective creators.

Thus, I have created another project that solves my special use case! Also, there is a caveat when working with the AWS Cost Explorer API: you have to pay $0.01 for each API call. While it doesn't sound like much, it's rather amusing that one has to pay to save costs.

Some of the other projects make AWS API calls ad-hoc when a request for metrics comes. This can make the whole setup rather expensive for such a simple task. This project makes calls every hour or day (depends on the metrics granularity), (see "Implementation" for more details), thus reducing the number of API calls to a minimum. These data doesn't change that often anyway.

There is however a general purpose Cost Exporter by Grafana. You should use that one if you're planning to run things in production, because it's maintained by an actual company and not a random dude on the internet, who spends half a year battling the weather-induced depresion.

Still, by the time I discovered the Grafana's exporter, I have already started some work related to this one. In theory, this exporter should also be fairely extensible both in terms of the cloud probider support (see the and in terms of the available formats and output methods (see the "Implementation" section for more information).

However, I work with AWS, so only AWS is supported for now. Also, the metrcs are available in the Prometheus format on an HTTP endpoint, because this is kind of the industry standard.

Usage

There is a ready-to-go Helm chart available in the charts/cost-exporter directory. However, Cost Exporter is a Go application which also has a Docker image available. So, you can run it in any environment you want.

Kubernetes

Cost Exporter comes with a Helm chart, so you can deploy into a Kubernetes cluster. The chart is located in the charts/cost-exporter directory of this repository.

To install it using the Helm chart, do:

helm repo add ...
helm upgrade --install cost-exporter oci://ghcr.io/grem11n/charts/cost-exporter --set serviceAccount.awsRoleArn="..."

You need to provide an IAM Role ARN, so the Cost Exporter pods can access AWS API, as well as the required configuration for AWS Cost Explorer.

For the rest of the available Helm values, see the README in the chart directory.

Configuration

There is an example configuration available in the config.example.yaml file.

Cost Exporter tries to use sane defaults, so you only really need to care about which metrics do you want to expose.

Prometheus

Currently, only the Prometheus format is supported, and the exporter outpts mertics on an HTTP endpoint. You can configure both the port and the endpoint to scrape the metrics, though.

Observability

Metrics

On top of the cost metrics, Cost Explorer also outputs some custom metrics on the same endpoint. Here's the list of available internal metrics with their types, units and descriptions.

Metric Name Type Unit Description
aws_calls_total count Total calls made to AWS API
aws_get_metrics_duration histogram ms Duration of API calls to AWS
cost_metrics_total counter Total number of the exported cost metrics
prometheus_aws_conversion_duration_bucket histogram ms Time it takes to convert the cost metrics

Logs

Cost Exporter uses Uber's zap library to provide structured logs. You can control the verbosity using the LOG_LEVEL environment variable. Standard log levels are available, e.g. INFO, DEBUG, ERROR, etc.

The default log level is set to INFO.

Implementation

In nutshell, Cost Exporter is just a bunch of control loops that use a single exchange point. Because everything is a control loop, when you have worked with Kubernetes long enough.

There are three types of loops:

  • Clients: cloud provider clients, take care of retrieving metrics from the cloud provider API
  • Converters: take care of converting whatever format a cloud provider provides into th e output format e.g. Prometheus. For now, I assume that while there can be multiple cloud clients, there should be only a single output format
  • Outputs: "metric sinks", take care of providing converted metrics to the clients

All the loops use a single sync.Map as an exchange point.

flowchart TD
    CC[Cloud Client] -->|Fetch data from the cloud API| CA[Cache]
    CA -->|Get raw cost metrics from cache| CV[Converter]
    CV -->|Put converted metrics| CA
    CA -->|Get converted metrics| O[Output]
    O --> CL([Client])
Loading

Clients, converters, and outputs are implemented as registries of plugins. Thus, it should be relatively easy to add new ones. However, I personally believe that that is only make sense to have a single converted format per exporter.

Initially, this project was designed around a single cache to decrease the number of AWS API calls, since those are paid. However, later on I realized that this could be a neat way to make this exporter extensible.

Implemented so Far

  • Cloud Clients:
    • AWS
  • Converters:
    • AWS to Prometheus
  • Outputs:
    • HTTP listener

Further Thoughts

Adding More Clients, Converters, and Outputs

Since each client, converter, and output is essentially a plugin, it's possible to extend this exporter to support other cloud providers, output formats, and metric sinks.

For example, it should be possible to add a client for Azure or Google Cloud. However, I am personally not familiar with these providers.

Also, it should be possible to, for example, push metrics to CloudWatch using their metrics format, etc. After all, CloudWatch is an AWS native tool.

Other Improvements

There are some things that could be improved in the codebase, e.g.:

  • Reduce the amount of hardcode required to set Prometheus labels and metric names
  • Automate the sync between the tag creation and Helm chart update somehow
  • Add other deploy manifests. For example, Terraform configuration for AWS ECS
  • Create a Grafana dashboard based on the metrics

Contribution

Since it's not particularly likely that I will do any serious updates to this project, feel free to create a PR! Otherwise, create an new issue with your feedback and suggestions!

Also, there are some ideas for improvements in the "Further Thoughts" section.

Release Process

  • Keep the version and the AppVersion in the Helm chart in sync
  • Preferably, keep the version and the Helm chart version itself also in sync
  • In case of any changes to the Helm chart, make sure to re-generate its README file
  • Update this README file with the new version icon before releasing
  • Create a new tag and let GHA and GoReleaser do their job

Inspiration

About

Export AWS Cost Explorer Metrics in Prometheus format

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors