Set Up Team Chargeback

Chargeback lets you attribute Kubernetes costs to the teams that own them. Once configured, every pound spent on pods, nodes, and storage can be traced back to an engineering team — making cost accountability part of your normal engineering workflow.

This guide walks you through auditing your labels, configuring CostPilot’s label mappings, and producing reports your finance team can act on.

Prerequisites

  • CostPilot agent installed and sending metrics
  • Access to your Kubernetes manifests (or Helm chart values) to inspect existing labels
  • Settings access in CostPilot (Owner or Admin role)

Step 1: Audit your existing labels

Before configuring anything in CostPilot, understand what labels already exist on your workloads.

Run the following against each cluster to see which label keys are in use:

kubectl get pods --all-namespaces -o json \
  | jq -r '.items[].metadata.labels | keys[]' \
  | sort | uniq -c | sort -rn | head -30

Look for keys that map to teams — common patterns include:

Common label keyExample value
teamplatform
app.kubernetes.io/managed-byargocd
ownerdata-engineering
squadcheckout
cost-centreCC-1042
Tip

If you use Helm, your Chart.yaml or values.yaml often defines a team label that propagates to all resources. This is the easiest place to enforce labelling consistency.

Make a note of the label key you want to use as the team identifier. You will map this in the next step.


Step 2: Configure label mappings in Settings → Labels

  1. Open CostPilot and navigate to Settings → Labels.
  2. Click Add mapping.
  3. In the Label key field, enter the Kubernetes label key you identified (e.g. team).
  4. In the Semantic role dropdown, select Team.
  5. Click Save.

CostPilot supports five semantic roles for label mappings:

RolePurpose
TeamAttributes cost to an engineering team
EnvironmentSplits cost by production, staging, dev, etc.
Cost CentreMaps to a finance cost centre code
ProductGroups cost by product or feature area
ComponentDifferentiates service tiers (e.g. api, worker, db)

You can configure multiple mappings — one per role. CostPilot uses all of them simultaneously, so a single pod can be attributed across Team, Environment, and Cost Centre at the same time.

Note

Label mappings apply to all clusters under your account. If different clusters use different label key conventions, add a mapping for each key — CostPilot will coalesce matching values under the same role.


Step 3: Verify team attribution

After saving your mapping, navigate to Cost Explorer and set the Group by dimension to Label: Team (or whichever key you mapped).

You should see cost broken down by team label value. If pods appear under an Unlabelled row, proceed to Step 4.


Step 4: Handle unlabelled pods

Unlabelled pods are real cost that cannot be attributed. There are two strategies:

Add the team label to every Deployment, StatefulSet, DaemonSet, and Job. Labels set on the controller propagate automatically to all pods it creates.

# Deployment example
metadata:
  labels:
    team: platform          # applied to Deployment itself
spec:
  template:
    metadata:
      labels:
        team: platform      # MUST also be set here — pods inherit from template
Warning

Labels on metadata.labels of a Deployment do not propagate to pods. You must set them under spec.template.metadata.labels. This is the most common labelling mistake.

Option B — Assign unlabelled cost to a catch-all team

Some organisations assign the unlabelled bucket to a “platform” or “shared” team for accounting purposes. This is a valid interim approach while you roll out labels.


Step 5: Export cost data

Once attribution looks correct, you can export a CSV for your finance team.

  1. Go to Cost Explorer → Group by Label: Team.
  2. Set the date range to the billing period you want (e.g. last calendar month).
  3. Click Export CSV in the top-right corner.

The export includes: team name, total cost, CPU cost, memory cost, storage cost, and efficiency score.

Note

Exports respect your current filters and date range. To export per-cluster breakdowns for each team, filter by cluster before exporting, then repeat for each cluster.


Step 6: Set up recurring reports

For ongoing chargeback, configure a recurring export or alert so you don’t need to log in manually each month.

  • Automated alerts: Navigate to Settings → Alerts and create a monthly budget alert scoped to each team label value. Set the notification channel to email or Slack.
  • API access (paid plans): Use the CostPilot API to pull cost-by-team data into your internal finance tooling or data warehouse on a schedule.

Label propagation reference

Resource typeLabels propagate to pods?Notes
DeploymentYesVia spec.template.metadata.labels
StatefulSetYesVia spec.template.metadata.labels
DaemonSetYesVia spec.template.metadata.labels
ReplicaSetYesUsually managed by Deployment — set on Deployment instead
JobYesVia spec.template.metadata.labels
CronJobYesVia spec.jobTemplate.spec.template.metadata.labels
Pod (bare)N/ALabels must be set directly on the pod spec

Common pitfalls

  • Label key typos: Team and team are different keys. Use lowercase consistently.
  • Missing template labels: As above — controller labels do not reach pods automatically.
  • Label value inconsistency: platform, Platform, and platform-team will appear as three separate teams. Standardise values across your organisation.
  • Namespace-only attribution: Namespace grouping is available but is not a substitute for team labels — many teams share namespaces in practice.