Overview
Grafana is the open-source (AGPL-3.0) dashboarding and alerting front end for time-series and SQL data. This template deploys Grafana OSS as a stateless app tier backed by a bundled PostgreSQL app database — every dashboard, user, alert rule and saved datasource lives in that database, so the Grafana workload itself holds no state and can run more than one replica. It exists to visualize data you own: the catalog’s Prometheus, Thanos and Mimir installs, your own SQL databases, and external systems. It is not an observability stack in itself — it ships no collectors, no exporters and no data.What Gets Created
postgres.credentials.*, so there is nothing for you to create for the database.
Prerequisites
Two opaque secrets must exist before you install. Grafana’s admin account is a human-facing login, andpublicAccess.enabled defaults to true, so that account is reachable from the internet — neither credential is a Helm value, and neither ever lands in the release. Secrets are org-level, so no --gvc flag is involved.
Create the admin password secret
plain. Grafana reads it only when the admin account is first created:admin.passwordSecretName to this name.Create the encryption key secret
admin.secretKeySecretName to this name.Choose the app-database password
postgres.credentials.username, postgres.credentials.password and postgres.credentials.database into a dictionary secret it creates, and the database reads that secret. Nothing to create — but the password ships as the placeholder change-me-grafana-db-password, so set postgres.credentials.password to a value of your own before installing. This applies in both database modes.Installation
Once both secrets exist, install the template into your GVC, naming the secrets and replacing the database password placeholder:--values) over --set for the database password if you do not want it in your shell history. If you run more than one release of this template in the same org, also give each its own postgresHA.config.credentialsSecretName (or postgres.config.credentialsSecretName in single-instance mode) — see App Database.
UI
CLI
Terraform
Pulumi
Configuration
Grafana Instance
replicas of 2 or more forms an HA tier over the shared app database and requires redis.enabled: true — see Alerting High Availability. image must provide /bin/bash: the chart wraps Grafana’s own entrypoint in a short boot script, and the official image does. User signup, anonymous access and upstream analytics and update checks are disabled by the template and are not configurable.
Admin Credentials
admin.applyPassword: false the chart drops the password secret from both places it appeared — the container environment and the reveal policy grant — and the encryption-key reference is kept. The retirement sequence is under First Run.
Datasources as Code
datasources.definitions additionally lets you declare them as code: each entry is a standard Grafana datasource provisioning entry, rendered verbatim into a provisioning file that the workload mounts at startup. Provisioned datasources are read-only in the Grafana UI — change the value and upgrade the release to change one. For catalog services in the same GVC, use their internal endpoints, substituting both the workload name and the GVC:
Datasource Credentials
datasources.credentialSecrets holds the credentials Grafana authenticates to each datasource with — not user access to Grafana. The provisioning file is plaintext, so credentials never go into it: create a dictionary secret before installing, list it under credentialSecrets, and write $KEY in the definition. Each listed key becomes an environment variable of that name, the chart grants the Grafana identity reveal on exactly that secret, and Grafana interpolates the variable when it loads the file.
$PG_PASSWORD placeholder — the value stays in the secret. Every entry needs a name and a non-empty keys list; the chart refuses to render otherwise.
Control Plane Metrics as a Datasource
Control Plane’s own metrics store is Prometheus-compatible and holds more than the console’s built-in dashboards display, including custom metrics your workloads expose and cost-relevant series such asegress, cross_zone_traffic and volume_set_*. Adding it as a datasource complements the built-in workload dashboards rather than replacing them. Follow the centralized metrics management guide for the endpoint details, then wire the token in as a datasource credential:
Create a service account with readMetrics
readMetrics permission on the org and generate a key for it. A workload’s built-in CPLN_TOKEN does not authenticate against the metrics endpoint.Store the key in a dictionary secret
CPLN_METRICS_TOKEN — and list the secret under datasources.credentialSecrets.Add the datasource definition
prometheus-type datasource at https://metrics.cpln.io/metrics/org/YOUR_ORG and send the token as an Authorization header:SMTP
smtp.enabled: false if you use webhook, chat or other contact points instead. smtp.passwordSecretName is required whenever smtp.user is set — the chart refuses to render without it. The password stays in an opaque secret you create before installing, and the chart grants the Grafana identity reveal on exactly that secret:
Access
publicAccess.enabled— Serve the UI and API on the canonical*.cpln.appHTTPS endpoint (default). Everything behind the endpoint is gated by Grafana’s own login, and Grafana’sroot_urlis set to that endpoint automatically. Set it tofalsefor an internal-only instance — external requests are then refused while in-GVC callers still reach it perinternalAccess, and you reach the UI yourself withcpln port-forward(see Connecting).internalAccess.type— Internal firewall scope of the Grafana workload:
App Database
Exactly one of the two database modes must be enabled — the chart enforces this at render and refuses to install otherwise.postgres.credentials.* — the chart writes them into the dictionary secret named by postgresHA.config.credentialsSecretName or postgres.config.credentialsSecretName (whichever database is enabled), and the database reads that secret. Change postgres.credentials.password before installing even when postgres.enabled is false. Grafana is wired to the active database automatically: the HAProxy leader endpoint in HA mode, or the single instance directly. In HA mode the proxy must stay enabled — that endpoint is Grafana’s stable database address, and the chart refuses to render with it disabled.
Secret names are org-wide, so a second release of this template left on the default credentialsSecretName is refused at install with cannot be updated because it is being managed by a different release and creates nothing — the first release is unaffected. Give each release its own name.
Everything else the bundled databases can do — volume autoscaling, PgBouncer pooling, etcd tuning — is documented on the postgres-highly-available and postgres pages and is set under the same postgresHA.* / postgres.* prefixes. Their backup settings are covered under Backing Up.
Alerting High Availability
Grafana holds no local state, so scaling the app tier is a matter of raisingreplicas. Alert evaluation is the one thing that must be coordinated: without coordination every replica would evaluate the same rule and send its own notification.
- Coordination uses Grafana’s Redis Sentinel alerting HA mode against the Sentinel workload deployed by the bundled redis subchart (master name
mymaster), not gossip-based peer clustering. Each replica registers under its own peer name, and exactly one notification is delivered per firing alert. - The chart refuses to render
replicas >= 2withoutredis.enabled: true. - Redis and Sentinel ship without authentication — the same-GVC internal firewall is the boundary. Enabling Redis or Sentinel authentication under
redis.redis.authorredis.sentinel.authis rejected at render in this version. - Grafana Live push updates are per-instance in multi-replica mode; dashboard auto-refresh and alerting are unaffected.
Connecting
curl:
publicAccess.enabled: false there is no canonical endpoint; open a tunnel to the UI instead and browse to http://localhost:3000:
First Run
Sign in on the public endpoint asadmin.user (default admin) with the password from the admin password secret. Grafana ships no dashboards and no datasources — connect your own in the UI or as code. Grafana applies GF_SECURITY_ADMIN_PASSWORD only when the admin account is first created: on every later boot the secret’s value is ignored, so changing the secret never changes the login, and an upgrade never resets the password you set in the UI. Once you have logged in, the password secret is inert and you can retire it:
Log in once
admin.user with the password from the secret and confirm you can reach the UI. Change the password in the UI if you wish — that is the only place it changes from now on.Set applyPassword to false and upgrade
admin.applyPassword: false, the chart drops the password secret from both the container environment and the reveal policy grant. The encryption-key reference is retained.Delete the secret
Operations
Backing Up
Database backups are optional and disabled by default. They cover the app database — the dashboards, users, alert rules and saved datasources that make up your Grafana. Enable them on whichever database is active and complete the storage setup for your provider before installing.postgresHA.backup.mode selects logical (a scheduled pg_dump run by the RELEASE_NAME-postgres-ha-backup cron workload) or wal-g (continuous WAL archiving from the database workload itself, with no separate backup workload). The single-instance database takes scheduled logical dumps only. Both come from the bundled postgres-highly-available and postgres subcharts. The steps below name the keys under postgresHA.backup.*; in single-instance mode set the same keys under postgres.backup.*.
- AWS S3
- Google Cloud Storage
- MinIO / S3-compatible
Create a bucket
postgresHA.backup.aws.bucket and postgresHA.backup.aws.region to match.Set up a Cloud Account
postgresHA.backup.aws.cloudAccountName to its name.Create a bucket-scoped IAM policy
YOUR_BUCKET), then set postgresHA.backup.aws.policyName to the policy’s name. No broad managed policy is required.Restoring a Backup
A restore goes into the database, not into Grafana: everything that makes up your Grafana lives there, so restoring it brings back dashboards, users, datasources and alert rules together. The restore procedures belong to the bundled database — follow Restoring a Backup on thepostgres-highly-available page in HA mode, or Restoring a Backup on the postgres page in single-instance mode, substituting this release’s database address (RELEASE_NAME-postgres-ha-proxy.GVC_NAME.cpln.local or RELEASE_NAME-postgres.GVC_NAME.cpln.local, port 5432) and the credentials from the chart-created secret:
admin.secretKeySecretName decrypts the datasource credentials stored in the dump, and a different key makes every saved datasource credential unreadable.
Upgrading from 1.1.0 or Earlier
Version 1.2.0 moved the admin password and the encryption key out of Helm values (admin.password, admin.secretKey) into the two prerequisite opaque secrets described under Prerequisites, and stopped creating the chart-owned admin secret those values used to feed. Version 1.1.0 had already renamed resources.cpu and resources.memory to resources.maxCpu and resources.maxMemory. The old keys are not rejected at render — they are simply ignored — so remove them deliberately.
Create the encryption key secret with the key the install already uses
admin.secretKey. Any other value makes every datasource credential already saved in the app database undecryptable:admin.secretKeySecretName to this name.Decide what to do with the admin password
admin.applyPassword: false and create no password secret at all (the chart requires admin.passwordSecretName only while applyPassword is true), or create one as under Prerequisites and retire it later.Remove the old keys and upgrade
admin.password and admin.secretKey from your values (and rename resources.cpu / resources.memory if you still carry them), then upgrade. Every later migration note below also applies.Upgrading from 1.2.0 or Earlier
Template versions before 1.2.1 did not compact the etcd cluster inside the bundled highly available database, so etcd’s backend grows with time alone and eventually goes read-only when it reaches its quota — taking PostgreSQL failover with it. Only installs running the HA database are affected (postgresHA.enabled, the default). See etcd History Compaction for the mechanism and symptoms. Upgrading to 1.2.1 or later turns compaction on; that stops further growth but cannot shrink a backend that has already grown, and a cluster that has already raised a NOSPACE alarm needs operator recovery rather than an upgrade.
Upgrading from 1.2.1 or Earlier
Version 1.3.0 moved the single-instance database credentials frompostgres.config.username, postgres.config.password and postgres.config.database to postgres.credentials.username, postgres.credentials.password and postgres.credentials.database, named by the new postgres.config.credentialsSecretName. postgres.backup.minio.accessKey and postgres.backup.minio.secretKey were replaced by postgres.backup.minio.credentialsSecretName at the same time. Carrying the old keys stops the upgrade at render, before anything is applied:
postgres.credentials.* using the values the database was initialised with — PostgreSQL enforces the credentials written when the volume was first created, and different values just leave Grafana unable to authenticate. Ignore the message’s advice to create the secret yourself: this template creates it from postgres.credentials.*. If you back up to MinIO, create the dictionary secret described under Backing Up and set postgres.backup.minio.credentialsSecretName. The HA path, Redis and the admin and encryption-key secrets are unchanged by this step.
Upgrading from 1.3.0
Version 1.4.0 made the same change on the HA path:postgresHA.postgres.username, postgresHA.postgres.password and postgresHA.postgres.database were removed, and the bundled highly available database now reads the dictionary secret named by postgresHA.config.credentialsSecretName — which this chart creates from postgres.credentials.*, exactly as in single-instance mode. Carrying the old block stops the upgrade at render:
postgresHA.postgres.*, and set postgres.credentials.username, postgres.credentials.password and postgres.credentials.database to the same values the cluster already has (the message’s instruction to create the secret yourself does not apply — this template creates it). Leaving postgres.enabled: false is correct; the postgres.credentials.* values feed both database modes. If you run several releases in one org, give each its own postgresHA.config.credentialsSecretName.
Upgrading from 1.4.0
Version 1.4.1 replacedpostgresHA.backup.minio.accessKey and postgresHA.backup.minio.secretKey with postgresHA.backup.minio.credentialsSecretName. Only installs backing up the HA database to MinIO or another S3-compatible endpoint are affected; the old keys stop the upgrade at render:
postgresHA.backup.minio.credentialsSecretName to its name, remove the two old keys, and upgrade.
Scaling and Availability
replicasscales the Grafana tier;2or more requiresredis.enabled: true— see Alerting High Availability. Database replicas are set separately withpostgresHA.replicas; the single-instance database must stay at one replica.- The first
helm upgradeafter an install can restart the bundled database even when no database value changed, making the UI unavailable briefly; later upgrades that only touch the Grafana workload roll without downtime in multi-replica mode. - Rotating a prerequisite secret does not restart anything. After changing the value of a datasource-credential or SMTP secret, run
cpln workload force-redeployment RELEASE_NAME-grafana --gvc GVC_NAMEso the replicas pick it up. Never rotate the encryption key, and change the admin password in the UI rather than in its secret. - Confirm an upgrade is live from the deployment, not from the Helm output —
cpln workload get-deployments RELEASE_NAME-grafana --gvc GVC_NAME -o yaml— especially after adding a new secret reference (enabling SMTP with a password, addingdatasources.credentialSecrets, turning on backups). - Uninstall deletes every volume set the chart created — the database and, in HA mode, the consensus store — so the data does not survive a reinstall. The GVC is yours and is left alone, and the prerequisite secrets you created survive. Enable backups if the data matters.
Troubleshooting
The Grafana workload sits at 0 replicas after install while helm reported success
The Grafana workload sits at 0 replicas after install while helm reported success
cpln helm install succeeded, but RELEASE_NAME-grafana shows no containers and cpln logs returns nothing.Cause: A prerequisite secret named in your values does not exist — the admin password, the encryption key, a datasource-credential secret or the SMTP password. The deployment pauses on the unresolved reference.Fix: Read the message naming the secret, then create it:The secret <name> no longer exists. Workload updates are paused until the secret is added or the reference to the secret removed. Once the secret exists the deployment recovers on its own, or run cpln workload force-redeployment RELEASE_NAME-grafana --gvc GVC_NAME to skip the wait.Logins return 401 and /api/health returns 503 right after an upgrade
Logins return 401 and /api/health returns 503 right after an upgrade
helm upgrade — typically the one that sets admin.applyPassword: false — every login fails with 401 and /api/health returns 503.Cause: The first upgrade after an install can restart the bundled app database even when no database value changed, and Grafana cannot authenticate anyone while its database is unreachable. Nothing was reset — the default admin credentials fail in the same way.Fix: Wait for /api/health to return 200 and log in again. Do not roll back and do not recreate the password secret.Render fails with replicas >= 2 requires redis.enabled=true
Render fails with replicas >= 2 requires redis.enabled=true
helm install or helm upgrade stops before applying anything with grafana: replicas >= 2 requires redis.enabled=true — Redis Sentinel coordinates alerting HA; without it every replica evaluates alerts independently and sends duplicate notifications.Cause: replicas is 2 or more and redis.enabled is false.Fix: Set redis.enabled: true alongside replicas — see Alerting High Availability — or return replicas to 1.Render fails with enable exactly one database
Render fails with enable exactly one database
grafana: enable exactly one database — set either postgresHA.enabled or postgres.enabled to true, not both, or the variant naming postgresHA.enabled (production) or postgres.enabled (dev/lightweight).Cause: Both postgresHA.enabled and postgres.enabled are true, or both are false.Fix: Enable exactly one — see App Database. To use the single-instance database, set postgresHA.enabled: false together with postgres.enabled: true.A second release is refused because a resource is managed by a different release
A second release is refused because a resource is managed by a different release
cannot be updated because it is being managed by a different release, naming the database credentials secret, and creates nothing.Cause: Secret names are org-wide, and both releases are trying to create the same credentialsSecretName (default my-grafana-db-credentials). The first release owns it.Fix: Give the new release its own postgresHA.config.credentialsSecretName (or postgres.config.credentialsSecretName in single-instance mode) and install again. The first release is unaffected.Saved datasources stop working after the encryption key secret changed
Saved datasources stop working after the encryption key secret changed
admin.secretKeySecretName was changed, or the secret was deleted and recreated with a different value. GF_SECURITY_SECRET_KEY is read on every boot to decrypt stored datasource credentials; a different key cannot decrypt them.Fix: Restore the original key from your backup of it and run cpln workload force-redeployment RELEASE_NAME-grafana --gvc GVC_NAME. If the original key is gone, re-enter the credentials of every saved datasource.Links in alert emails point at localhost
Links in alert emails point at localhost
localhost.Cause: publicAccess.enabled is false, so the chart does not derive Grafana’s root_url from a canonical endpoint and Grafana falls back to its default.Fix: Set publicAccess.enabled: true and upgrade, or use contact points that do not rely on absolute links.Upgrade fails with a key that was REMOVED in postgres 3.4.0 or 2.5.0
Upgrade fails with a key that was REMOVED in postgres 3.4.0 or 2.5.0
helm upgrade stops at render with config.username was REMOVED in postgres 3.4.0, the postgres block was REMOVED in 2.5.0, or backup.minio.accessKey and backup.minio.secretKey were REMOVED.Cause: Your values still carry database or MinIO credential keys that moved in template versions 1.3.0, 1.4.0 or 1.4.1. The existing release is left untouched and running.Fix: Follow the matching migration note above — Upgrading from 1.2.1 or Earlier, Upgrading from 1.3.0 or Upgrading from 1.4.0 — keeping the credentials the database already uses.Important Notes
- Create the admin-password and encryption-key secrets before installing, and change
postgres.credentials.passwordfrom itschange-meplaceholder. A missing prerequisite secret does not fail the install — the workload sits at zero replicas waiting on it. - The encryption-key secret is permanent: never delete it, never rotate it. Back the key up outside Control Plane.
- The admin password applies on first boot only. Change it in the Grafana UI; then set
admin.applyPassword: false, upgrade, and delete the password secret — see First Run. - This template ships no dashboards and no datasources. Control Plane’s console already provides built-in workload-metrics dashboards; this is the pane for data you own.
replicas >= 2requiresredis.enabled: true— the chart refuses to render multi-replica without the Sentinel tier that keeps one firing alert from producing one notification per replica.- Dashboards, users and alert rules live in the app database and survive Grafana restarts and replica replacement. Uninstall deletes the database volume sets — enable backups if the data matters.
- Give each release its own
credentialsSecretName— secret names are org-wide, and a second release on the default name is refused at install. - Prerequisite secrets you create are not owned by the release — they survive
helm uninstalland must be deleted manually if you no longer need them. - Keep
publicAccess.enabled: trueif you rely on links in alert emails — an internal-only instance has no derivedroot_urland links point at localhost. - This template ships Grafana OSS only — Enterprise features such as fine-grained RBAC, reporting and query caching are not available.