2.1 (latest)

CSV Pricing

This feature is only officially supported on Kubecost Enterprise plans.
The following steps allow Kubecost to use custom prices with a CSV pipeline. This feature allows for individual assets (e.g. nodes) to be supplied at unique prices. Common uses are for on-premise clusters, service-providers, or for external enterprise discounts.

Creating a pricing file

  1. 1.
    Create a CSV file in this format (also in the below table). CSV changes are picked up hourly by default.
    1. 1.
      EndTimeStamp: currently unused
    2. 2.
      InstanceID: identifier used to match asset
    3. 3.
      Region: filter match based on topology.kubernetes.io/region
    4. 4.
      AssetClass: node pv, gpu are supported
    5. 5.
      InstanceIDField: field in spec or metadata that will contain the relevant InstanceID. For nodes, often spec.providerID , for pv’s often metadata.name
    6. 6.
      InstanceType: optional field to define the asset type, e.g. m5.12xlarge
    7. 7.
      MarketPriceHourly: hourly price to charge this asset
    8. 8.
      Version: field for schema version, currently unused
If the node label topology.kubernetes.io/region is present, it must also be in the Region column.
Pricing table

GPU pricing

This section is only required for nodes with GPUs.
  1. 1.
    The node the GPU is attached to must be matched by a CSV node price. Typically this will be matched on instance type (node.kubernetes.io/instance-type)
  2. 2.
    Supported GPU labels are currently:
    • gpu.nvidia.com/class
    • nvidia.com/gpu_type
  3. 3.
    1. 1.
      Connect to the Kubecost Prometheus: kubectl port-forward --namespace kubecost services/kubecost-cost-analyzer 9090:9090
    2. 2.
      Run the following query: curl localhost:9090/model/prometheusQuery?query=node_gpu_hourly_cost
      1. 1.
        You should see output similar to this: {instance="ip-192-168-34-166.us-east-2.compute.internal",instance_type="test.xlarge",node="ip-192-168-34-166.us-east-2.compute.internal",provider_id="aws:///us-east-2b/i-055274d3576800444",region="us-east-2"} 10 | YOUR_HOURLY_COST

Kubecost configuration

Provide a file path for your CSV pricing data in your values.yaml. This path can reference a local PV or an S3 bucket.
enabled: true
provider: "AWS|GCP"
region: "us-east-1"
URI: s3://YOUR_BUCKET/path/custom-pricing.csv
csvAccessCredentials: pricing-schema-access-secret
Alternatively, mount a ConfigMap with the CSV:
kubectl create configmap csv-pricing --from-file custom-pricing.csv
Then set the following Helm values:
enabled: true
URI: /var/kubecost-csv/custom-pricing.csv
csvAccessCredentials: ""
- name: kubecost-csv
name: csv-pricing
- name: kubecost-csv
mountPath: /var/kubecost-csv
For S3 locations, provide file access. Required IAM permissions:
"Version": "2012-10-17",
"Statement": [
"Effect": "Allow",
"Action": [
"Resource": [
There are two options for adding the credentials to the Kubecost pod:
  1. 1.
    Service key: Create an S3 service key with the permissions above, then add its ID and access key as a K8s secret:
    1. 1.
      kubectl create secret generic pricing-schema-access-secret -n kubecost --from-literal=AWS_ACCESS_KEY_ID=id --from-literal=AWS_SECRET_ACCESS_KEY=key
    2. 2.
      The name of this secret should be the same as csvAccessCredentials in values.yaml above
  2. 2.
    AWS IAM (IRSA) service account annotation

Pricing discounts

Negotiated discounts are applied after cost metrics are written to Prometheus. Discounts will apply to all node pricing data, including pricing data read directly from the custom provider CSV pipeline. Additionally, all discounts can be updated at any time and changes are applied retroactively.

Pricing inference

The following logic is used to match node prices accurately:
  • First, search for an exact match in the CSV pipeline
  • If an exact match is not available, search for an existing CSV data point that matches region, instanceType, and AssetClass
  • If neither is available, fall back to pricing estimates
You can check a summary of the number of nodes that have matched with the CSV by visiting /model/pricingSourceCounts. The response is a JSON object of the form:
"code": 200,
"status": "success",
"data": {
"TotalNodes": 10,
"PricingType": {
"csvExact": 5, // exact matches by the providerID field
"csvClass": 4, // matches where the region and instanceType match
"": 1 // matches that use our default pricing