Deploy Grafana on Kubernetes with Helm and Provisioning Values
Run Grafana from a Helm chart where data sources, dashboards, and settings all come from values files.
On Kubernetes, the Grafana Helm chart turns the provisioning folders into configuration you write in values.yaml. The chart renders ConfigMaps and Secrets, mounts them at the paths Grafana expects, and restarts or reloads when they change. That makes Grafana a good fit for GitOps, since the values file is the only thing you edit. This guide builds a values file that provisions a data source, dashboards, alerting, and server settings.
Chart hosting is changing: some Grafana Labs charts are moving to a community-maintained repository. Before installing, check the chart’s README for the repository URL and chart version to use, and pin that version. The values keys below follow the chart’s documented structure, but confirm them in the values.yaml of the version you install.
Install
helm repo add grafana https://grafana.github.io/helm-charts
helm repo update
helm install grafana grafana/grafana \
--namespace monitoring --create-namespace \
--version <chart-version> \
-f values.yaml
If the chart has moved, replace the repository URL with the one in the README. Keep the command, the --version, and the values file in Git so the installation is repeatable.
Server settings: grafana.ini
Anything you would put in grafana.ini goes under the grafana.ini key, organized by section:
grafana.ini:
server:
root_url: https://grafana.example.com/
users:
allow_sign_up: false
analytics:
reporting_enabled: false
check_for_updates: false
log:
mode: console
Values that must not be committed can reference environment variables or files, as in the configuration guide (for example password: $__file{/etc/secrets/db/password}).
Admin credentials and other secrets
Use an existing Kubernetes Secret instead of a password in values:
admin:
existingSecret: grafana-admin
userKey: admin-user
passwordKey: admin-password
envFromSecret: grafana-secrets # every key becomes an environment variable
apiVersion: v1
kind: Secret
metadata:
name: grafana-secrets
namespace: monitoring
stringData:
POSTGRES_PASSWORD: change-me
SLACK_WEBHOOK_URL: https://hooks.slack.com/services/XXX/YYY/ZZZ
Provisioning files can then use $POSTGRES_PASSWORD and ${SLACK_WEBHOOK_URL}. Encrypt the Secret with SOPS or sync it with External Secrets rather than committing it as plain YAML (see the secrets guide).
Data sources
The datasources key is rendered into a provisioning file:
datasources:
datasources.yaml:
apiVersion: 1
datasources:
- name: Prometheus
uid: prometheus
type: prometheus
access: proxy
url: http://prometheus-server.monitoring.svc.cluster.local
isDefault: true
editable: false
Dashboards: three ways
1. Inline from files in the chart folder. Declare a provider and list dashboards by source:
dashboardProviders:
dashboardproviders.yaml:
apiVersion: 1
providers:
- name: default
orgId: 1
folder: ''
type: file
disableDeletion: false
allowUiUpdates: false
options:
path: /var/lib/grafana/dashboards/default
dashboards:
default:
node-exporter:
gnetId: 1860
revision: 37
datasource: Prometheus
kubernetes-overview:
json: |
{ "uid": "k8s-overview", "title": "Kubernetes Overview", "panels": [] }
Entries can come from grafana.com (gnetId and revision), a URL, or inline JSON. The key under dashboards (here default) must match the provider’s options.path folder name.
2. From ConfigMaps you manage yourself. Keep dashboard JSON in its own ConfigMaps (for example generated by Kustomize from the repository) and mount them:
dashboardsConfigMaps:
default: grafana-dashboards
3. With the sidecar. A sidecar container watches the cluster for ConfigMaps (or Secrets) with a label and loads them as dashboards, so each application team can ship its own dashboard next to its manifests:
sidecar:
dashboards:
enabled: true
label: grafana_dashboard
labelValue: "1"
searchNamespace: ALL
folderAnnotation: grafana_folder
provider:
foldersFromFilesStructure: true
datasources:
enabled: true
label: grafana_datasource
alerts:
enabled: true
label: grafana_alert
apiVersion: v1
kind: ConfigMap
metadata:
name: webapp-dashboard
namespace: webapp
labels:
grafana_dashboard: "1"
annotations:
grafana_folder: Applications
data:
webapp.json: |
{ "uid": "webapp-overview", "title": "Webapp Overview", "panels": [] }
The sidecar approach scales best across teams: no one edits Grafana’s values to add a dashboard.
Alerting
Alerting provisioning files can come from the alerting key, using the YAML formats from the alerting guide:
alerting:
contactpoints.yaml:
secret:
apiVersion: 1
contactPoints:
- orgId: 1
name: team-slack
receivers:
- uid: team-slack-1
type: slack
settings:
url: ${SLACK_WEBHOOK_URL}
recipient: '#alerts'
policies.yaml:
apiVersion: 1
policies:
- orgId: 1
receiver: team-slack
The secret: wrapper places that file in a Secret instead of a ConfigMap. Check the chart’s values.yaml for the exact shape in your version. Alert rules can come from the same key or from the sidecar’s alerts setting.
Persistence and replicas
persistence:
enabled: true
size: 5Gi
replicas: 1
SQLite on a persistent volume supports one replica. For high availability, point Grafana at PostgreSQL through grafana.ini and raise replicas.
Deploy with Flux
If you use Flux, the chart becomes a HelmRelease, and the values above go in spec.values:
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: grafana
namespace: monitoring
spec:
interval: 10m
chart:
spec:
chart: grafana
version: "<chart-version>"
sourceRef:
kind: HelmRepository
name: grafana
namespace: flux-system
valuesFrom:
- kind: ConfigMap
name: grafana-values
A change to the values in Git rolls out the change automatically. See the Helm guide in the Flux series for HelmRepository, remediation, and drift detection.
Verify
kubectl get pods -n monitoring
kubectl port-forward svc/grafana 3000:80 -n monitoring &
curl -s http://localhost:3000/api/health
kubectl logs deploy/grafana -n monitoring -c grafana | grep -i provisioning
If a dashboard or data source is missing, check the provisioning log lines first, then the sidecar’s logs (-c grafana-sc-dashboard) for label or namespace problems.
Popular Guides
-
Operate Grafana as Code: The Big Picture What can live in files, what needs an API, and how the pieces fit together. -
Configure the Grafana Server with grafana.ini and Environment Variables Know where config files live, how overrides are ordered, and how to keep settings in Git. -
Provision Dashboards from JSON Files Load dashboards from disk, map folders from directories, and author them without losing changes. -
Provision Alert Rules, Contact Points, and Notification Policies Define the whole alerting pipeline in YAML so it is reviewed and versioned like code. -
Reload, Verify, and Troubleshoot Provisioning from the Command Line Find out what Grafana loaded, reload without a restart, and fix the usual provisioning errors.