Back to blog
·Agnes

Chargeback on OpenStack: What CloudKitty Gives You, and What It Doesn’t

Chargeback on OpenStack: what CloudKitty gives you, and what it doesn’t.

Moving from VMware to OpenStack changes more than the hypervisor. Showback and chargeback are part of VMware Cloud Foundation (VCF). On OpenStack, you put them together yourself.

Ceilometer measures usage, but billing and pricing have been out of its scope from the start. CloudKitty is the OpenStack project built to fill that gap. It is a rating engine. It reads usage, puts the prices you define on it, and stores the result.

In this post, we run CloudKitty in a DevStack test environment . We go from a dashboard that shows 0.00 to a priced breakdown for each hour.

We also show where CloudKitty stops. It does not generate invoices, and leaves taxes and currency conversion to billing software. A billing platform such as OSIE issues invoices, applies tax, and collects payment. 

We start with why OpenStack doesn’t ship a bill.

Why OpenStack Doesn’t Ship a Bill

A bill rests on business decisions: what you charge for, how much, in which currency, and with which taxes. Most billing operations are business specific, so OpenStack leaves them to the operator.

What OpenStack gives you is the usage and, with CloudKitty, a price on it. Ceilometer measures usage, Gnocchi, a time series database, stores it, and CloudKitty rates it. 

CloudKitty is a generic solution for the chargeback and rating of a cloud. It reads usage from Gnocchi or Prometheus and can run in standalone mode, outside OpenStack.

Rating is where OpenStack stops. Next, we look at how CloudKitty does it.

How CloudKitty Works

Ceilometer measures usage and Gnocchi stores it. CloudKitty then takes over: it fetches the scopes to rate, collects usage, passes it through the enabled rating modules, and stores the rated result.

  • Ceilometer measures. It collects and normalises the data OpenStack services produce.
  • Gnocchi stores. It keeps that data as time series.
  • The fetcher picks the scopes. A scope is usually a project, and it is what CloudKitty rates and reports on.
  • The collector reads the usage. It reads each scope’s usage for every metric defined in metrics.yml.
  • Rating modules price it. The enabled modules apply their rules to the collected usage, highest priority first. In this article, that module is hashmap.
  • The storage backend keeps the ledger. The rated data is stored, and the API returns it grouped by scope or metric type

A hashmap rule ties a price to a service, which is a metric CloudKitty collects. A flat mapping adds a fixed amount per unit, and a rate mapping multiplies the total. 

A price can also depend on a field, such as the volume type or flavor. Your own prices set the unit: CloudKitty has no currency conversion.

Two processes do the work. cloudkitty-processor handles fetching, collecting, rating and storing, and cloudkitty-api serves the results.

Now let’s see it in our test environment.

Our Test Setup

We tested CloudKitty on DevStack, a development environment for OpenStack, running in a virtual machine.

The deployment ran the 2026.2 release. It had the core OpenStack services for compute, networking, images, and block storage. It also had Ceilometer, Gnocchi, and CloudKitty.

The environment had no workloads. It had no instances, so only two things could be measured: the CirrOS image that DevStack uploads during setup, and a 1 GB volume we created. We set a price on each and watched CloudKitty rate them.

The deployment used these settings:

  • Collector: Gnocchi
  • Fetcher: Gnocchi
  • Storage: InfluxDB
  • Rating period: one hour, the default
  • Metrics: seven, defined in metrics.yml

The fetcher finds which projects to rate, and the collector reads their usage. The scope output from our test shows both set to Gnocchi. Your environment may use different settings.

Our metrics.yml defined seven metrics:

  • cpu, 
  • image.size, 
  • volume.size, 
  • network.incoming.bytes.rate,
  • network.outgoing.bytes.rate, ip.floating, 
  • radosgw.objects.size. 

Only image.size and volume.size had data in our environment. The processor logged a warning for the other five and skipped them each cycle. That is normal when nothing is running.

Hands-On: From 0.00 to Priced Usage

Step 1: The starting point

  • Right after install, the Rating page has nothing to show.
Rating dashboard at 0.00, breakdown reads “No data available”
Rating dashboard listing image.size at 0.00
Reporting page with an empty chart

Step 2: What is being rated

  • On a fresh DevStack, the only measurable resource is the CirrOS image uploaded during setup. We will add a volume later. The image ID in CloudKitty’s rated data is the one openstack image list shows.
The CirrOS image listed by openstack image list

Step 3: Enable the hashmap module

Module list before and after

Step 4: Read metrics.yml

  • CloudKitty keeps the metrics it collects in metrics.yml, by default at /etc/cloudkitty/metrics.yml. A service must match a metric in this file, so open it first. To read the image.size entry run:
grep -A 13 'image.size' /etc/cloudkitty/metrics.yml
The image.size entry in CloudKitty’s metrics.yml in our test: unit MiB, factor 1/1048576

Each field in the entry does a different job:

  • unit is a label for people. It has no effect on collection, conversion, or rating.
  • factor does the conversion. 21,692,416 bytes multiplied by 1/1048576 gives 20.6875 MiB.
  • groupby and metadata list the attributes CloudKitty carries with each reading.
  • extra_args holds the Gnocchi settings for this metric.

Step 5: Create the service

A service tells CloudKitty that a collected metric is billable. It carries no price yet. The service you create has to match a metric defined in metrics.yml.

Creating the image.size service

Step 6: Add the mapping (the price)

A flat mapping sets one fixed price: 0.01 for every MiB, every hour. No field or group is attached, so nothing is charged twice. The mapping starts at 08:04:04 and has no end date.

Creating the flat mapping

Step 7: Wait for the next full hour

CloudKitty prices usage one period at a time, and the default period is one hour.

In our test, the 08:00–09:00 hour contains the mapping’s start, and it stayed at 0.0. The first priced hour is 09:00–10:00.

The arithmetic for that hour:

  • Gnocchi stores the image size as 21,692,416 bytes.
  • The factor turns that into 20.6875 MiB.
  • 20.6875 MiB × 0.01 = 0.206875 for the hour.
The 07:00 and 08:00 hours at 0.0, and 09:00 at 0.206875
10:00 and 11:00, each at 0.206875

Step 8: The result

  • The dashboard now shows 0.83 for the month, a forecast of 1.28, and image.size as 100 percent of the breakdown.
Rating dashboard, 0.83 this month, 1.28 forecast
Current month breakdown and Top Cost Generators
Reporting page, cumulative cost repartition and cost per service per hour

The 0.83 comes from the price we set: 0.01 per MiB for each hour. The provider chooses the prices, and CloudKitty doesn’t care about currency. The unit is yours to decide: euros, dollars, cents, or squirrels.

Two details help when you work out your own prices.

First, CloudKitty prices each hour, so a monthly price has to be converted. A 30-day month has 720 hours. To charge 5 per GiB per month, divide 5 by 720, which is about 0.0069 per GiB per hour.

Second, the price applies to the quantity CloudKitty stores. For image.size, the quantity is in MiB, so our 0.01 is per MiB, or 10.24 per GiB for every hour.

Even a correct price can give a lower total than you expect. In our test, an hour went unpriced because the mapping started partway through it. Let’s explore more gotchas next.

Seven Gotchas Before You Trust the Numbers

  1. In CloudKitty, the hour that contains a mapping’s start stays unpriced. In our CloudKitty test on DevStack, the image.size mapping started at 08:04:04. The 08:00–09:00 hour has a price of 0.0, and 09:00–10:00 is the first priced hour. The volume.size mapping started at 13:57:43, and its 13:00–14:00 hour also has a price of 0.0. Create mappings before the usage you want priced, and expect the hour you create them to read 0.0.
openstack rating hashmap mapping create for the volume.size service in our CloudKitty test. The flat price is 0.02 and the mapping start date is 2026-10-20T13:57:43
Selected hours from openstack rating dataframes get in our CloudKitty test. image.size is 0.0 at 08:00 and 0.206875 from 09:00. volume.size is 0.0 at 13:00

2. CloudKitty’s hashmap module starts disabled. The hashmap module applies mapping prices, and it is disabled by default. A correct mapping prices nothing until you run openstack rating module enable hashmap

openstack rating module list on a new CloudKitty install shows hashmap as False. After openstack rating module enable hashmap, the list shows it as True

3. A CloudKitty metric with no service has a cost of zero. CloudKitty collects and stores the metric anyway. In our test, the Rating dashboard listed image.size at 0.00 until we created a service for it.

The Horizon Rating dashboard on 20 October. image.size is listed at 0.00, before we created a service or a mapping for it

4. A running CloudKitty mapping cannot be edited. To change a price, delete the mapping and create a new one.

5. In CloudKitty, mapping a service and one of its fields charges twice. If you map a service and a field of that service, CloudKitty charges both.

6. A wrong aggregation method hides a metric in CloudKitty. The Gnocchi collector defaults to max, but Ceilometer’s default archive policies don’t support it. Gnocchi then returns a 404, and the docs recommend mean. The image.size entry in our metrics.yml sets mean.

7. CloudKitty timestamps are in UTC. Every Begin and End value in openstack rating dataframes get ends in +00:00. Compare your mapping’s start time against UTC to see which hour goes unpriced.

Output of openstack rating dataframes get in our CloudKitty test, from 12 October. Every Begin and End value ends in +00:00, which means UTC

Those gotchas are about getting CloudKitty’s numbers right. The next section covers what CloudKitty does not do, however you configure it.

What CloudKitty Doesn’t Do

CloudKitty rates usage and stores the result. It stops there.

CloudKitty cannot limit resources in other OpenStack services. It rates and only rates, so it can’t, for example, block instance creation in Nova above a certain price.

CloudKitty does not add taxes or convert currencies. A billing system has to do that. CloudKitty attaches a price to a metric for a period, and the unit of that price is whatever you choose.

CloudKitty does not generate invoices, handle payments or manage customers. Its v1 and v2 API references cover dataframes, scope state, summaries, reports, price quotes, tasks and rating modules. They list no endpoints for invoices, payments, taxes, currencies or customers. 

What you get is rated usage, grouped by scope or metric type, and the Horizon Rating and Reporting pages show it.

To go from rated usage to a bill, you add billing software on top of CloudKitty.

Where OSIE Fits

CloudKitty is enough when the goal is showback: showing each project or team what its usage costs. OSIE fits when that grows into billing customers.

OSIE prices usage with its own plans. Price plans set a price per resource attribute, charged per minute, hour or month. A periodic billing job adds each charge to the customer’s open bill.

OSIE issues invoices. It generates and delivers invoices automatically, using PDF templates that include tax calculations.

OSIE collects payment. It supports Stripe, PayPal, Razorpay, HyperPay, Xendit, BTCPay Server and bank transfer, with prepaid wallets or postpaid accounts with credit limits.

OSIE suspends customers who don’t pay. Suspension rules include grace periods, and customers are reactivated when they pay.

OSIE gives customers a self-service portal. Customers create instances, networks and volumes, add a credit card and see their invoices.

Conclusion

OpenStack does not ship a bill, but CloudKitty gives you the rating layer. It reads usage from Gnocchi or Prometheus, applies the prices you define and stores the result. In our DevStack test, image.size went from 0.00 to 0.206875 per hour once we enabled the hashmap module, created a service and added a flat mapping of 0.01 per MiB.

CloudKitty settles what each project and metric type costs, at prices you define. It leaves open invoices, tax, currency conversion and payments.

If you need to show teams what they use and what it costs, CloudKitty covers it. If customers pay you, you need billing software on top. OSIE is one: it issues invoices, applies tax and collects payment for OpenStack.

Try the OSIE Free Edition: https://osie.io/free