Dashboards as code, the Bazel way. Write Grafana dashboards with Python and build them in into a reusable Docker image.
Try it out! bazel run //example:grafana
to build and load a Docker image,
then run it with docker run --rm -p 3000:3000 bazel/example:grafana
.
Then load Grafana in your browser at http://localhost:3000
!
Load rules_grafana
by adding the following to your MODULE.bazel
:
bazel_dep(name = "rules_grafana", version = "1.0.0")
# For plugins and container setup
grafana_ext = use_extension("@rules_grafana//grafana:extensions.bzl", "grafana")
use_repo(grafana_ext, "grafana_oci")
# Optional: Add plugins
grafana_ext.plugin(
name = "my_plugin",
urls = ["https://grafana.com/api/plugins/my-plugin/versions/1.0.0/download"],
sha256 = "...",
type = "zip",
)
use_repo(grafana_ext, "my_plugin")
rules_grafana
depends on rules_python
and
rules_oci
, but these are automatically managed
through Bazel's module system.
Requires Bazel 7.0.0 or later with bzlmod enabled.
rules_grafana
makes it easy to build dashboards and incorporate them into your Bazel build,
and to build a complete, runnable Docker image.
Dashboards can be either hard-coded JSON files or Python scripts that generate dashboards.
Use json_dashboards
to add JSON files containing dashboard to your build.
The JSON must be a complete, valid Grafana dashboard;
see the Grafana docs for details on the JSON format.
load("@rules_grafana//grafana:grafana.bzl", "json_dashboards")
json_dashboards(
name = "dashboards",
srcs = ["awesome_graphs.json"],
)
Unlike using the JSON files directly,
json_dashboards
will check the syntax of your files
and ensure that each dashboard has a uid
set,
to ensure it has a consistent URL in Grafana.
Dashboards can also be generated with Python,
using the grafanalib
library.
grafanalib
is automatically imported,
and you can also add other deps
to help build your dashboard.
Each Python dashboard file should print the complete JSON of a Grafana dashboard. An easy way to do that is to follow a template like this:
from grafanalib.core import *
from grafanalib._gen import print_dashboard
dashboard = Dashboard(
# Fill in your dashboard!
)
print_dashboard(dashboard.auto_panel_ids()) # `auto_panel_ids()` call is required!
Use py_dashboards
to add Python files that generate dashboards to your build.
load("@rules_grafana//grafana:grafana.bzl", "py_dashboards")
py_dashboards(
name = "dashboards",
srcs = ["amazing_graphs.py", "even_better_graphs.py"],
)
You can run the Python and see the generated JSON with the FOO_builder
target created by py_dashboards
,
where FOO
is the Python filename without .py
.
For example, run bazel run //example:sample_builder
in this repository to see the output of sample.py
.
The JSON is generated at build time, not a run time, so Python isn't a runtime dependency.
Use grafana_image
to build your dashboards into a Docker image containing Grafana.
When you run the image, it starts Grafana on port 3000
and serves all of the dashboards you've built,
directly from the container.
The dashboards and datasources are added via Grafana provisioning,
where the configuration and sources are declared and built into the image,
alongside all the dashboards.
You must provide a datasources.yaml
file declaring your datasources;
see the Grafana datasources docs for details of the format.
Grafana plugins can be installed into the image too.
Use the grafana
module extension to download plugins:
# In your MODULE.bazel
grafana_ext = use_extension("@rules_grafana//grafana:extensions.bzl", "grafana")
grafana_ext.plugin(
name = "grafana_plotly_plugin",
urls = ["https://grafana.com/api/plugins/natel-plotly-panel/versions/0.0.7/download"],
sha256 = "818ab33b42a1421b561f4e44f0cd19cd1a56767d3952045b8042a4da58bd470e",
type = "zip",
)
use_repo(grafana_ext, "grafana_plotly_plugin")
Then pass the plugin to the image rule's plugins
list as @grafana_plotly_plugin//:plugin
.
The default version of Grafana (12.0) may not suit your needs. You can override the container by modifying the grafana extension in your MODULE.bazel.
Processes a set of .json
Grafana dashboards for inclusion in the image.
Arguments:
name
: Unique name for this target. Required.srcs
: List of labels of.json
files to build into dashboards. Required.
Processes a set of .py
Grafana dashboards for inclusion in the image.
Arguments:
name
: Unique name for this target. Required.srcs
: List of labels of.py
files to build into dashboards. Required.deps
: List of labels of additionalpy_library
targets to use while executing the Python dashboards. Optional, default[]
.
Builds a Docker image containing Grafana and the provided dashboards and datasources.
Arguments:
name
: Unique name for this target. Required.dashboards
: List of labels ofjson_dashboards
and/orpy_dashboards
targets to include in the image. Required.datasources
: List of labels ofdatasources.yaml
files to include in the image (Grafana datasources docs). Required.plugins
: List of labels of plugin targets from the grafana extension, like@your_plugin_name//:plugin
. Optional.env
: Dictionary of environment variant names to values, set in the Docker image when Grafana is run. Optional. Useful for setting runtime configs withGF_
variables.
Module extension for managing Grafana plugins and container configuration.
Downloads a Grafana plugin for inclusion in a grafana_image
.
Arguments:
name
: Unique name for this plugin repository. Required.urls
: List of strings of mirror URLs referencing the plugin archive. Required.sha256
: String of the expected SHA-256 hash of the download. Required.type
: The archive type of the downloaded file as a string; takes the same values as thetype
attribute of Bazel'shttp_archive
rule. Optional, as the archive type can be determined from the plugin's file extension.