[release-12.3.0] Restructure As code and developer resources (#113969)
Co-authored-by: Roberto Jiménez Sánchez <roberto.jimenez@grafana.com> Co-authored-by: Anna Urbiztondo <anna.urbiztondo@grafana.com>
This commit is contained in:
@@ -0,0 +1,306 @@
|
||||
---
|
||||
description: Learn about the Foundation SDK, a set of tools, types, and libraries for defining Grafana dashboards and resources.
|
||||
keywords:
|
||||
- as code
|
||||
- as-code
|
||||
- Foundation SDK
|
||||
labels:
|
||||
products:
|
||||
- enterprise
|
||||
- oss
|
||||
title: Foundation SDK
|
||||
weight: 250
|
||||
canonical: https://grafana.com/docs/grafana/latest/as-code/observability-as-code/foundation-sdk/
|
||||
aliases:
|
||||
- ../../observability-as-code/foundation-sdk/ # /docs/grafana/next/observability-as-code/foundation-sdk/
|
||||
---
|
||||
|
||||
# Get started with the Grafana Foundation SDK
|
||||
|
||||
The [Grafana Foundation SDK](https://github.com/grafana/grafana-foundation-sdk) is a set of tools, types, and libraries that let you define Grafana dashboards and resources using strongly typed code. By writing your dashboards as code, you can:
|
||||
|
||||
- **Leverage strong typing:** Catch errors at compile time, ensuring more reliable configurations.
|
||||
- **Enhance version control:** Track changes seamlessly using standard version control systems like Git.
|
||||
- **Automate deployments:** Integrate dashboard provisioning into your CI/CD pipelines for consistent and repeatable setups.
|
||||
|
||||
The SDK supports multiple programming languages, including Go, TypeScript, Python, PHP, and Java, so you can choose the one that best fits your development environment.
|
||||
|
||||
{{< youtube id="_OKQoABmg0Q" >}}
|
||||
|
||||
## Before you begin
|
||||
|
||||
Ensure you have the following prerequisites:
|
||||
|
||||
- **Programming environment:** Set up for your chosen language. For example: Go, Node.js for TypeScript, or Python 3.x for Python.
|
||||
- **Grafana instance:** A running Grafana instance compatible with the SDK version you’re using (refer to the [compatibility matrix](https://github.com/grafana/grafana-foundation-sdk#navigating-the-sdk)).
|
||||
- **Package manager:** Appropriate for your language, for example, `npm` or `yarn` for TypeScript or `pip` for Python.
|
||||
|
||||
To get started, clone the [intro-to-foundation-sdk repository](https://github.com/grafana/intro-to-foundation-sdk) to access examples and a `docker-compose` stack.
|
||||
|
||||
## Install the Grafana Foundation SDK
|
||||
|
||||
Select the `go` or `typescript` tab to view instructions to install the SDK.
|
||||
For other languages, refer to the Grafana Foundation SDK documentation for installation instructions.
|
||||
{{< code >}}
|
||||
|
||||
```go
|
||||
go get github.com/grafana/grafana-foundation-sdk/go@next+cog-v0.0.x
|
||||
```
|
||||
|
||||
```typescript
|
||||
npm install @grafana/grafana-foundation-sdk
|
||||
```
|
||||
|
||||
{{< /code >}}
|
||||
|
||||
## Grafana Foundation SDK Overview
|
||||
|
||||
Here's a quick overview of how the Grafana Foundation SDK works:
|
||||
|
||||
- **Builder pattern:** The SDK uses a chainable builder pattern to let you define dashboards fluently. You start with a `DashboardBuilder`, then add panels, queries, and other components step by step.
|
||||
- **Strong typing:** Everything in the SDK is strongly typed. This gives you autocompletion in your IDE, catches mistakes early, and helps ensure you're always using valid configuration values.
|
||||
- **Structured options:** When a configuration get complex (like data reduction or display settings), the SDK uses typed option builders to keep things readable and predictable.
|
||||
|
||||
You'll see these concepts in action in the next example. These concepts are explained in more detail afterwards.
|
||||
|
||||
## Create a dashboard
|
||||
|
||||
The following example demonstrates how you can create a simple dashboard:
|
||||
|
||||
{{< code >}}
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
// Import the appropriate Grafana Foundation SDK packages
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
|
||||
"github.com/grafana/grafana-foundation-sdk/go/cog"
|
||||
"github.com/grafana/grafana-foundation-sdk/go/common"
|
||||
"github.com/grafana/grafana-foundation-sdk/go/dashboard"
|
||||
"github.com/grafana/grafana-foundation-sdk/go/stat"
|
||||
"github.com/grafana/grafana-foundation-sdk/go/testdata"
|
||||
"github.com/grafana/grafana-foundation-sdk/go/timeseries"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Define a data source reference for our testdata data source
|
||||
testdataRef := dashboard.DataSourceRef{
|
||||
Type: cog.ToPtr("grafana-testdata-datasource"),
|
||||
Uid: cog.ToPtr("testdata"),
|
||||
}
|
||||
|
||||
// Define our dashboard as strongly typed code
|
||||
builder := dashboard.NewDashboardBuilder("My Dashboard").
|
||||
WithPanel(
|
||||
stat.NewPanelBuilder().
|
||||
Title("Version").
|
||||
Datasource(testdataRef).
|
||||
ReduceOptions(common.NewReduceDataOptionsBuilder().
|
||||
Calcs([]string{"lastNotNull"}).
|
||||
Fields("/.*/")).
|
||||
WithTarget(
|
||||
testdata.NewDataqueryBuilder().
|
||||
ScenarioId("csv_content").
|
||||
CsvContent("version\nv1.2.3"),
|
||||
),
|
||||
).
|
||||
WithPanel(
|
||||
timeseries.NewPanelBuilder().
|
||||
Title("Random Time Series").
|
||||
Datasource(testdataRef).
|
||||
WithTarget(
|
||||
testdata.NewDataqueryBuilder().
|
||||
ScenarioId("random_walk"),
|
||||
),
|
||||
)
|
||||
|
||||
// Build the dashboard - errors in configuration will be thrown here
|
||||
dashboard, err := builder.Build()
|
||||
if err != nil {
|
||||
log.Fatalf("failed to build dashboard: %v", err)
|
||||
}
|
||||
|
||||
// Output the generated dashboard as JSON
|
||||
dashboardJson, err := json.MarshalIndent(dashboard, "", " ")
|
||||
if err != nil {
|
||||
log.Fatalf("failed to marshal dashboard: %v", err)
|
||||
}
|
||||
|
||||
log.Printf("Dashboard JSON:\n%s", dashboardJson)
|
||||
}
|
||||
```
|
||||
|
||||
```typescript
|
||||
// Import the appropriate Grafana Foundation SDK packages
|
||||
import * as common from '@grafana/grafana-foundation-sdk/common';
|
||||
import * as dashboard from '@grafana/grafana-foundation-sdk/dashboard';
|
||||
import * as stat from '@grafana/grafana-foundation-sdk/stat';
|
||||
import * as testdata from '@grafana/grafana-foundation-sdk/testdata';
|
||||
import * as timeseries from '@grafana/grafana-foundation-sdk/timeseries';
|
||||
|
||||
// Define a data source reference for our testdata data source
|
||||
const testDataRef: dashboard.DataSourceRef = {
|
||||
type: 'grafana-testdata-datasource',
|
||||
uid: 'testdata',
|
||||
};
|
||||
|
||||
// Define our dashboard as strongly typed code
|
||||
const builder = new dashboard.DashboardBuilder('My Dashboard')
|
||||
.withPanel(
|
||||
new stat.PanelBuilder()
|
||||
.title('Version')
|
||||
.reduceOptions(new common.ReduceDataOptionsBuilder().calcs(['lastNotNull']).fields('/.*/'))
|
||||
.datasource(testdataRef)
|
||||
.withTarget(new testdata.DataqueryBuilder().scenarioId('csv_content').csvContent('version\nv1.2.3'))
|
||||
)
|
||||
.withPanel(
|
||||
new timeseries.PanelBuilder()
|
||||
.title('Random Time Series')
|
||||
.datasource(testdataRef)
|
||||
.withTarget(new testdata.DataqueryBuilder().scenarioId('random_walk'))
|
||||
);
|
||||
|
||||
// Build the dashboard - errors in configuration will be thrown here
|
||||
const dashboard = builder.build();
|
||||
|
||||
// Output the generated dashboard as JSON
|
||||
console.log(JSON.stringify(dashboard, null, 2));
|
||||
```
|
||||
|
||||
{{< /code >}}
|
||||
|
||||
This code defines a dashboard titled “My Dashboard” with a two panels:
|
||||
|
||||
- a simple stat panel displaying a version number, and
|
||||
- a time series panel displaying randomized data from the `testdata` data source `random_walk` scenario.
|
||||
|
||||
## Export and use the JSON
|
||||
|
||||
After you've defined your dashboard as code, build the final dashboard representation using the dashboard builder (typically using the `build()` function depending on language choice) and output the result as a JSON.
|
||||
|
||||
With the JSON payload, you can:
|
||||
|
||||
- **Manually import:** Paste into Grafana’s dashboard import feature.
|
||||
- **Automate:** Use [Grafana's API](/docs/grafana/<GRAFANA_VERSION>/developer-resources/api-reference/http-api/) or the [Grafana CLI](../grafana-cli/) to programmatically upload the dashboard JSON.
|
||||
|
||||
## Concepts
|
||||
|
||||
Now that you've seen how to define a basic dashboard using code, let's take a moment to explain how it all works behind the scenes. The Grafana Foundation SDK is built around a few core concepts that make your dashboards structured, reusable, and strongly typed.
|
||||
|
||||
### Builders
|
||||
|
||||
The SDK follows a builder pattern, which lets you compose dashboards step-by-step using chained method calls.
|
||||
Almost every piece of the dashboard, including dashboards, panels, rows, queries, and variables, has its own `Builder` class.
|
||||
|
||||
Here are a few you've already seen:
|
||||
|
||||
- `DashboardBuilder` - Starts the dashboard definition and sets global configuration settings like title, UID, refresh interval, time range, etc.
|
||||
- `PanelBuilder` - Creates individual visualizations like time series panels, stat panels, or log panels.
|
||||
- `DataqueryBuilder` - Defines how a panel fetches data, for example, from Prometheus or the `testdata` plugin.
|
||||
|
||||
Builders are chainable, so you can fluently compose dashboards in a readable, structured way:
|
||||
|
||||
{{< code >}}
|
||||
|
||||
```go
|
||||
stat.NewPanelBuilder().
|
||||
Title("Version").
|
||||
Datasource(testdataRef).
|
||||
ReduceOptions(common.NewReduceDataOptionsBuilder().
|
||||
Calcs([]string{"lastNotNull"}).
|
||||
Fields("/.*/")).
|
||||
WithTarget(
|
||||
testdata.NewDataqueryBuilder().
|
||||
ScenarioId("csv_content").
|
||||
CsvContent("version\nv1.2.3"),
|
||||
)
|
||||
```
|
||||
|
||||
```typescript
|
||||
new stat.PanelBuilder()
|
||||
.title('Version')
|
||||
.reduceOptions(new common.ReduceDataOptionsBuilder().calcs(['lastNotNull']).fields('/.*/'))
|
||||
.datasource(testdataRef)
|
||||
.withTarget(new testdata.DataqueryBuilder().scenarioId('csv_content').csvContent('version\nv1.2.3'));
|
||||
```
|
||||
|
||||
{{< /code >}}
|
||||
|
||||
### Types
|
||||
|
||||
The Grafana Foundation SDK uses strong types under the hood to help catch mistakes before you deploy a broken dashboard.
|
||||
|
||||
For example:
|
||||
|
||||
- When setting a unit, you'll get autocomplete suggestions for valid Grafana units like `"percent"` or `"bps"`.
|
||||
- When defining a time range, you'll be guided to provide the correct structure, like `from` and `to` values.
|
||||
- When referencing data sources, you'll use a structured `DataSourceRef` object with defined `type` and `uid` fields.
|
||||
|
||||
This helps you:
|
||||
|
||||
- Avoid typos or unsupported configuration values
|
||||
- Get full autocomplete and inline documentation in your IDE
|
||||
- Write dashboards that are less error-prone and easier to maintain
|
||||
|
||||
Strong typing also makes it easier to build reusable patterns and components with confidence, especially in large codebases or teams.
|
||||
|
||||
### Options
|
||||
|
||||
Most builder methods accept simple values like strings or numbers, but others expect more structured option objects. These are used for things like:
|
||||
|
||||
- `ReduceDataOptions` - How to reduce time series data into single values (e.g. last, avg).
|
||||
- `VizLegendOptions` - Configure how the legend of a panel is displayed.
|
||||
- `CanvasElementOptions` - Define how the the various components of a Canvas panel should be displayed.
|
||||
|
||||
Example using options:
|
||||
|
||||
{{< code >}}
|
||||
|
||||
```go
|
||||
stat.NewPanelBuilder().
|
||||
ReduceOptions(common.NewReduceDataOptionsBuilder().
|
||||
Calcs([]string{"lastNotNull"}).
|
||||
Fields("/.*/"))
|
||||
)
|
||||
```
|
||||
|
||||
```typescript
|
||||
new stat.PanelBuilder().reduceOptions(new common.ReduceDataOptionsBuilder().calcs(['lastNotNull']).fields('/.*/'));
|
||||
```
|
||||
|
||||
{{< /code >}}
|
||||
|
||||
By using option builders, you don't need to manually construct deeply nested configuration objects. Instead, the SDK gives you a typed and guided API that mirrors a dashboards internal structure, making it easier to configure complex options without guesswork or referring back to the JSON schema.
|
||||
|
||||
## Explore a real-world example
|
||||
|
||||
If you want to explore further and see a more real-world example of using the Grafana Foundation SDK, watch the following walkthrough:
|
||||
|
||||
{{< youtube id="ZjWdGVsrCiQ" >}}
|
||||
|
||||
In this video, we generate a dashboard from code and deploy it using the Grafana API, covering patterns and practices you'd use in production environments. It also includes a working example of a web service that emits metrics and logs, and shows how to deploy a dashboard alongside it using Docker Compose.
|
||||
|
||||
You can find the full source code for this example in the [intro-to-foundation-sdk repository](https://github.com/grafana/intro-to-foundation-sdk/tree/main/generate-and-deploy-example).
|
||||
|
||||
## Summary
|
||||
|
||||
The Grafana Foundation SDK is designed to make dashboard creation:
|
||||
|
||||
- **Composable** through the use of chainable builders
|
||||
- **Safe** with strong typing and clear APIs
|
||||
- **Configurable** using structured options for fine control
|
||||
|
||||
As you build more advanced dashboards, you’ll work with additional builders and types to support richer functionality.
|
||||
The SDK supports not just panels and queries, but also variables, thresholds, field overrides, transformations, and more.
|
||||
Refer to [the full API reference](https://grafana.github.io/grafana-foundation-sdk/) to explore what's possible.
|
||||
|
||||
## Next steps
|
||||
|
||||
Now that you understand the basics of using the Grafana Foundation SDK, here are some next steps:
|
||||
|
||||
- **Explore more features:** Check out the [full API reference](https://grafana.github.io/grafana-foundation-sdk/) to learn about advanced dashboard configurations.
|
||||
- **Version control your dashboards:** Store your dashboard code in a Git repository to track changes over time.
|
||||
- **Automate dashboard provisioning with CI/CD:** [Integrate the SDK into your CI/CD pipeline](./dashboard-automation) to deploy dashboards automatically.
|
||||
@@ -0,0 +1,260 @@
|
||||
---
|
||||
description: Learn how to automatically generate and deploy Grafana dashboards as code with GitHub Actions.
|
||||
keywords:
|
||||
- foundation SDK
|
||||
- dashboard provisioning
|
||||
- CI/CD
|
||||
- GitHub Actions
|
||||
labels:
|
||||
products:
|
||||
- cloud
|
||||
- enterprise
|
||||
- oss
|
||||
title: Automate dashboard provisioning with CI/CD
|
||||
weight: 200
|
||||
canonical: https://grafana.com/docs/grafana/latest/as-code/observability-as-code/foundation-sdk/dashboard-automation/
|
||||
aliases:
|
||||
- ../../../observability-as-code/foundation-sdk/dashboard-automation/ # /docs/grafana/next/observability-as-code/foundation-sdk/dashboard-automation/
|
||||
---
|
||||
|
||||
# Automate dashboard provisioning with CI/CD
|
||||
|
||||
## Introduction
|
||||
|
||||
Managing Grafana dashboards manually can be inefficient and error-prone. As you saw in the Getting Started guide, we can define dashboards using strongly typed code with the Grafana Foundation SDK. We can then commit them to version controls, and automatically deploy them using GitHub Actions.
|
||||
|
||||
This guide walks through:
|
||||
|
||||
- Generating a Grafana dashboard as code
|
||||
- Formatting it for Kubernetes-style deployment
|
||||
- Using GitHub Actions to deploy the dashboard
|
||||
- Checking if the dashboard exists and updating it if needed
|
||||
|
||||
By the end, every change to your dashboard code will be automatically created or updated in your Grafana instance without manual intervention.
|
||||
|
||||
{{< youtube id="cFnO8kVOaAI" >}}
|
||||
|
||||
You can find the full example source code in the [intro-to-foundation-sdk repository](https://github.com/grafana/intro-to-foundation-sdk/tree/main/github-actions-example).
|
||||
|
||||
## 1. Generating the dashboard JSON
|
||||
|
||||
Before deploying a dashboard, we need to define it in code using the Grafana Foundation SDK. We ran through an example of this in the Getting Started guide, however, in order to comply with the Kubernetes resource compatible API that Grafana exposes, we’ll make some changes to the code to output the dashboard JSON in the appropriate format.
|
||||
|
||||
{{< code >}}
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/grafana/grafana-foundation-sdk/go/cog"
|
||||
"github.com/grafana/grafana-foundation-sdk/go/common"
|
||||
"github.com/grafana/grafana-foundation-sdk/go/dashboard"
|
||||
)
|
||||
|
||||
type DashboardWrapper struct {
|
||||
APIVersion string `json:"apiVersion"`
|
||||
Kind string `json:"kind"`
|
||||
Metadata Metadata `json:"metadata"`
|
||||
Spec dashboard.Dashboard `json:"spec"`
|
||||
}
|
||||
|
||||
type Metadata struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
builder := dashboard.NewDashboardBuilder("My Dashboard").
|
||||
Uid("my-dashboard").
|
||||
Tags([]string{"generated", "foundation-sdk", "go"}).
|
||||
Refresh("5m").
|
||||
Time("now-1h", "now").
|
||||
Timezone(common.TimeZoneBrowser).
|
||||
WithRow(dashboard.NewRowBuilder("Overview"))
|
||||
|
||||
dashboard, err := builder.Build()
|
||||
if err != nil {
|
||||
log.Fatalf("failed to build dashboard: %v", err)
|
||||
}
|
||||
|
||||
dashboardWrapper := DashboardWrapper{
|
||||
APIVersion: "dashboard.grafana.app/v1beta1",
|
||||
Kind: "Dashboard",
|
||||
Metadata: Metadata{
|
||||
Name: *dashboard.Uid,
|
||||
},
|
||||
Spec: dashboard,
|
||||
}
|
||||
|
||||
dashboardJson, err := json.MarshalIndent(dashboardWrapper, "", " ")
|
||||
if err != nil {
|
||||
log.Fatalf("failed to marshal dashboard: %v", err)
|
||||
}
|
||||
|
||||
err = os.WriteFile("dashboard.json", dashboardJson, 0644)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to write dashboard to file: %v", err)
|
||||
}
|
||||
|
||||
log.Printf("Dashboard JSON:\n%s", dashboardJson)
|
||||
}
|
||||
```
|
||||
|
||||
```typescript
|
||||
import { DashboardBuilder, RowBuilder } from '@grafana/grafana-foundation-sdk/dashboard';
|
||||
import * as fs from 'fs';
|
||||
|
||||
// Generate the dashboard JSON
|
||||
const dashboard = new DashboardBuilder('My Dashboard')
|
||||
.uid('my-dashboard')
|
||||
.tags(['generated', 'foundation-sdk', 'typescript'])
|
||||
.refresh('5m')
|
||||
.time({ from: 'now-1h', to: 'now' })
|
||||
.timezone('browser')
|
||||
.withRow(new RowBuilder('Overview'))
|
||||
.build();
|
||||
|
||||
// Convert to Kubernetes-style format
|
||||
const dashboardWrapper = {
|
||||
apiVersion: "dashboard.grafana.app/v1beta1",
|
||||
kind: "Dashboard",
|
||||
metadata: {
|
||||
name: dashboard.uid!
|
||||
},
|
||||
spec: dashboard
|
||||
};
|
||||
|
||||
// Save the formatted JSON to a file
|
||||
const dashboardJSON = JSON.stringify(dashboardWrapper, null, 2);
|
||||
fs.writeFileSync('dashboard.json', dashboardJSON, 'utf8');
|
||||
|
||||
console.log(`Dashboard JSON:\n${}`);
|
||||
```
|
||||
|
||||
{{< /code >}}
|
||||
|
||||
This script:
|
||||
|
||||
- Generates a Grafana dashboard JSON file
|
||||
- Wraps it in a Kubernetes-style API format (`apiVersion`, `kind`, `metadata`, `spec`)
|
||||
- Saves it as `dashboard.json` for deployment
|
||||
|
||||
## 2. Automating deployment with GitHub Actions
|
||||
|
||||
Next, we’ll set up GitHub Actions to:
|
||||
Extract the dashboard name from `dashboard.json`
|
||||
Check if the dashboard already exists within our Grafana instance
|
||||
Update it if it does, create it if it doesn’t
|
||||
|
||||
{{< admonition type="note" >}}
|
||||
The following GitHub Action configuration assumes you are using a Go-based dashboard generator. If you are using one of the other languages that the Foundation SDK supports, please modify the **Generate Dashboard JSON** step accordingly.
|
||||
{{< /admonition >}}
|
||||
|
||||
`.github/workflows/deploy-dashboard.yml`
|
||||
|
||||
```yaml
|
||||
name: Deploy Grafana Dashboard
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: 1.24.6
|
||||
|
||||
- name: Verify Go version
|
||||
run: go version
|
||||
|
||||
- name: Download and Extract grafanactl
|
||||
run: |
|
||||
curl -L -o grafanactl-x86_64.tar.gz "https://github.com/grafana/grafanactl/releases/download/${{ vars.GRAFANACTL_VERSION }}/grafanactl_Linux_x86_64.tar.gz"
|
||||
tar -xzf grafanactl-x86_64.tar.gz
|
||||
chmod +x grafanactl
|
||||
sudo mv grafanactl /usr/local/bin/grafanactl
|
||||
|
||||
- name: Generate Dashboard JSON
|
||||
working-directory: ./github-actions-example
|
||||
run: go run main.go
|
||||
|
||||
- name: Deploy Dashboard with grafanactl
|
||||
env:
|
||||
GRAFANA_SERVER: ${{ vars.GRAFANA_SERVER }}
|
||||
GRAFANA_STACK_ID: ${{ vars.GRAFANA_STACK_ID }}
|
||||
GRAFANA_TOKEN: ${{ secrets.GRAFANA_TOKEN }}
|
||||
run: |
|
||||
if [ -f dashboard.json ]; then
|
||||
echo "dashboard.json exists, deploying dashboard."
|
||||
grafanactl resources push dashboards --path ./dashboard.json
|
||||
else
|
||||
echo "dashboard.json does not exist."
|
||||
exit 1
|
||||
fi
|
||||
working-directory: ./github-actions-example
|
||||
```
|
||||
|
||||
## 3. Explaining this GitHub Action
|
||||
|
||||
This GitHub Action automates the deployment of a Grafana dashboard using the Foundation SDK and the `grafanactl` CLI tool.
|
||||
|
||||
### 1. Checkout and set up Go
|
||||
|
||||
The first few steps:
|
||||
|
||||
- Check out the repository to access the project code.
|
||||
- Install Go 1.24.6 using the `actions/setup-go` action.
|
||||
- Verify Go is properly installed.
|
||||
|
||||
### 2. Download and install `grafanactl`
|
||||
|
||||
This step downloads the `grafanactl` CLI from GitHub using a version defined in `vars.GRAFANACTL_VERSION`. It unpacks the tarball, makes it executable, and moves it to a location in the system `PATH`.
|
||||
|
||||
### 3. Generate the dashboard JSON
|
||||
|
||||
Runs the dashboard generator (`main.go`) from the `./github-actions-example` directory. This should produce a `dashboard.json` file that contains the Grafana dashboard definition.
|
||||
|
||||
### 4. Deploy the dashboard with `grafanactl`
|
||||
|
||||
If `dashboard.json` exists, it is deployed to your Grafana instance using:
|
||||
|
||||
```bash
|
||||
grafanactl resources push dashboards --path ./dashboard.json
|
||||
```
|
||||
|
||||
This command authenticates against Grafana using the following environment variables:
|
||||
|
||||
- `GRAFANA_SERVER`: Your Grafana instance URL
|
||||
- `GRAFANA_STACK_ID`: Your Grafana stack ID
|
||||
- `GRAFANA_TOKEN`: A Grafana service account token with sufficient permissions
|
||||
|
||||
### GitHub variables and secrets used
|
||||
|
||||
These are configured in your repository under **Settings → Security → Secrets and variables → Actions**:
|
||||
|
||||
- `vars.GRAFANACTL_VERSION`: Version of `grafanactl` to install
|
||||
- `vars.GRAFANA_SERVER`: The URL of your Grafana instance
|
||||
- `vars.GRAFANA_STACK_ID`: The stack ID in Grafana
|
||||
- `secrets.GRAFANA_TOKEN`: Grafana API token
|
||||
|
||||
This action ensures that every push to `main` will regenerate and deploy your latest dashboard definition to Grafana.
|
||||
|
||||
### Why automate this?
|
||||
|
||||
Automating Grafana dashboard deployment eliminates the need for manual dashboard creation and updates, ensuring that dashboards remain consistent across environments. By defending dashboards as code and managing them through CI/CD such as GitHub Actions, we gain full version control, making it easy to track changes over time and roll back if needed. This also prevents duplication, as the workflow intelligently checks whether a dashboard exists before deciding to create or update it. With this fully automated CI/CD pipeline, developers can focus on improving their dashboards rather than manually uploading JSON files to Grafana.
|
||||
|
||||
### Conclusion
|
||||
|
||||
By integrating the Grafana Foundation SDK with GitHub Actions, we have successfully automated the entire lifecycle of Grafana dashboards. This setup allows us to define dashboards programmatically, convert them into a Kubernetes-compatible format, and deploy them automatically. With each push to the repository, the workflow ensures that dashboards are either created or updated as needed. This not only improves the efficiency but also guarantees that all deployed dashboards are always in sync with the latest code changes, reducing manual effort and potential errors.
|
||||
Reference in New Issue
Block a user