Prometheus and Grafana
Prometheus is a monitoring system and time-series database, and Grafana is an open source analytics and visualization platform. This example deploys both on Unikraft Cloud to chart the instance metrics of your own account: Prometheus scrapes the metrics endpoint over a private network, and Grafana serves a pre-built dashboard behind a public port.
The dashboard is a starting point rather than a supported product surface. Rename panels, drop rows you don't need, and tune the alert thresholds to your workload.
Deployment
To run this example, follow these steps:
-
Install the CLI. Use the unikraft CLI or the legacy kraft CLI. You need a BuildKit builder. The easiest way to get one is via Docker. Alternatively, you can also directly set up and use BuildKit, see the quick start.
The unikraft CLI is the current standard, while kraft is the legacy version. Choose one of the CLIs below and only run the commands associated with it for the rest of this guide.
-
Clone the
examplesrepository andcdinto theexamples/prometheus-grafanadirectory:Code
Make sure to log into Unikraft Cloud and pick a metro close to you.
This guide uses fra (Frankfurt, 🇩🇪):
Configure
The configuration files ship to each instance as read-only ROMs, uploaded when the instance starts. Finish this section before deploying: changing a file later means deploying again with a new ROM, not editing a file in place.
Fill in your metro and API token in prometheus/rom/prometheus.yml:
Code
A Unikraft Cloud API token is not read-only.
The same token that reads metrics can also create, stop, and delete instances and volumes in your account.
Never commit prometheus.yml with a real token filled in, and rotate the token if it lands somewhere unexpected.
The repository ships these files:
| File | Purpose |
|---|---|
prometheus/rom/prometheus.yml | Scrape config for /v1/instances/metrics. Mounted at /etc/prometheus. |
prometheus/rom/alerts.yml | Five starter alerting rules. |
grafana/provisioning/datasources/datasource.yml | Points Grafana at the Prometheus instance. Mounted at /etc/grafana/provisioning. |
grafana/provisioning/dashboards/dashboards.yml | Loads dashboards from the ROM directory. |
grafana/dashboards/vm-instances.json | The VM instances dashboard. Mounted at /var/lib/grafana/dashboards. |
Prometheus
Create a volume so the time-series database survives a restart:
Build and deploy Prometheus. It gets an internal domain and no published port, so only Grafana on the same private network can reach it:
unikraft
The output shows the instance details:
unikraft
The domains entry confirms the internal FQDN, and the roms entry confirms the config directory was uploaded and mounted.
Don't publish a port for Prometheus. It has no authentication of its own, so exposing it would hand your metrics, and the alert rules describing your estate, to anyone who finds the address.
Don't enable scale-to-zero on Prometheus either. A sleeping Prometheus stops scraping, which leaves gaps in the data.
Grafana
Build and deploy Grafana, this time with a public port:
unikraft
Port 443 makes Grafana reachable by anyone who knows its address, with only the login in front of your metrics.
Choose a strong, unique <password> rather than the placeholder, and keep GF_USERS_ALLOW_SIGN_UP=false so visitors can't create their own accounts.
The output shows the generated address under domains:
unikraft
The FQDN is generated for you, and it differs on each run.
The CLI masks GF_SECURITY_ADMIN_PASSWORD in its output, but the value still reaches the instance as an environment variable.
Point your browser at the address and log in with the credentials you set above. The dashboard appears in the Unikraft Cloud folder.
Data appears after the first couple of scrapes.
The rate()-based panels need one to two minutes of history before they render anything.
You can list information about the instances by running:
Grafana shows as standby rather than running because cooldown-time=1000 is 1000 milliseconds, so it parks almost immediately when idle.
The next request wakes it.
or
kraft
When done, you can remove the instances and the volume:
What the dashboard shows
The dashboard holds 24 panels across five rows, driven by the metrics that the instance metrics reference documents:
| Row | Panels |
|---|---|
| Fleet overview | Instance counts by state, total resident memory, active connections, and a per-instance state table |
| Resource usage | CPU time rate in cores, resident memory, uptime, and restarts per hour |
| Network | Inbound and outbound throughput, plus packet rates |
| Requests and connections | Active, queued, and processed connections or requests |
| Boot and wakeup latency | Boot, network setup, and template creation times, with wakeup latency percentiles and a heatmap |
A Data source variable selects which Prometheus to query, and an Instance variable filters by instance_uuid.
What to watch out for
A few behaviours surprise people the first time:
-
The endpoint reports only live instances. An instance appears only while a live virtual machine backs it, so a fully stopped instance produces no series at all. Don't build a "stopped instances" count on this endpoint, because it would always read zero.
-
Per-instance identity lives in
instance_uuid. Prometheus injects its owninstancelabel holding the API host it scraped, which is identical for every instance. Group and join oninstance_uuidinstead. -
Panels label each series by UUID. The Prometheus exposition carries no instance name, so legends show raw UUIDs.
-
Counters restart from zero. CPU time, the byte and packet counters, and the processed-request counter are reported since the last start of the instance, so a restart resets them. The
rate()-based panels handle the reset. -
The wakeup latency panels stay empty without scale-to-zero. Only instances with scale-to-zero enabled record the histogram.
Customize your app
To customize the app, update the files in the repository, listed below:
prometheus/rom/prometheus.yml: scrape targets, intervals, and labels. To watch more than one metro, add astatic_configsentry per metro, each with its ownregionlabel.prometheus/rom/alerts.yml: alerting rules and thresholds.grafana/provisioning/: the Grafana data source and dashboard provider.grafana/dashboards/vm-instances.json: the dashboard itself.Kraftfile: the Unikraft Cloud specification, including command-line argumentsDockerfile: In case you need to add files to your instance's rootfs
The dashboard queries carry a hard-coded job="instances" selector.
If you rename the job in prometheus.yml, update the dashboard queries to match, or every panel reads "No data".
Learn more
Use the --help option for detailed information on using Unikraft Cloud:
Or visit the CLI Reference or the legacy CLI Reference.