Overview
Grafana Multi-Location deploys one logical Grafana whose UI/API instances run in every location you configure, behind a single georouted*.cpln.app endpoint. Every dashboard, user, org, session, alert rule and saved datasource lives in a postgres-multi-location cluster stretched across the same locations, so Grafana itself holds no state: there is no volume, no session affinity and nothing to hand over when an instance is replaced.
Exactly one instance sends each firing alert’s notification, in one of two shapes you choose with alerting.highAvailability.enabled:
- Off (the default) — a separate single-replica workload runs in one location with rule execution enabled, and it is disabled on every UI instance. Exactly-once evaluation is a property of the topology: nothing is elected at runtime, and no value of
replicascan produce a second evaluator. Losing that location stops evaluation. - On — that workload is not created at all. Every UI instance in every location evaluates every rule, and a stretched Redis tier coordinates the peers so exactly one notification is sent. Alert evaluation then survives the loss of a location, at the cost of multiplying data-source query load.
How Many Locations You Need
The bundled database’s consensus store (etcd-multi-location) commits a write only when a majority of its members agree, and it runs one member per location. That arithmetic decides what survives — the Grafana tier itself has no quorum of its own.
floor((N-1)/2) losses, so an even count buys nothing over the odd count below it. Losing the location named in alerting.location is a separate matter — see Alert Evaluation.
What Gets Created
- Standard Grafana UI Workload —
{release}-grafana,replicasinstances per location, serving the UI and HTTP API on port3000. Public by default. Alert rule execution is disabled here by default, and enabled on every instance when alerting HA is on. - Standard Alert Evaluator Workload (optional) —
{release}-grafana-alerting, the same image with exactly one replica, running only inalerting.locationand never reachable from the internet. Not created whenalerting.highAvailability.enabledistrue, or whenalerting.enabledisfalse. - App Database Workloads — The
postgres-multi-locationsubchart: a stateful Patroni PostgreSQL workload with one primary and asynchronous replicas, a stateful etcd workload for consensus, and an HAProxy leader-routing tier in every location. - Alerting Coordination Workloads (optional) — The
redis-multi-locationsubchart:{release}-redisand{release}-sentinel, one of each per location, coordinating exactly-once notification delivery. Created only whenalerting.highAvailability.enabledistrue. - Volume Sets —
{release}-postgres-vsfor the PostgreSQL data directory and the etcd cluster’s own volume set, plus{release}-redis-vsand{release}-sentinel-vswith alerting HA on. Grafana itself has none. - Secrets — The subchart startup scripts and Redis configuration, and — only when
datasources.definitionsis set —{release}-grafana-datasources, the rendered datasource provisioning file mounted by every Grafana workload. The admin password, encryption key and database credentials are prerequisite secrets you create yourself; the chart references them by name and never creates, modifies or deletes them. - Identities & Policies — One identity shared by every Grafana workload, with
revealon exactly the secrets they mount and nothing else, plus a second policy grantingviewon exactly the one GVC this release installs into so the boot check can read that GVC’s location list. Each subchart tier gets its own identity and policy.
Prerequisites
An existing GVC with at least 2 locations — 3 if you enable alerting HA, and 3 for automatic database failover. This template deploys into the GVC you install it into and creates none of its own; every entry inglobal.locations must already be one of that GVC’s locations. Read them back with cpln gvc get GVC_NAME -o yaml and compare spec.staticPlacement.locationLinks. See Matching the Location List to the GVC.
Three secrets must exist before you install. The admin account is a human-facing login and publicAccess.enabled defaults to true, so its password never passes through Helm values; the encryption key and the database credentials are shared by every instance in every location.
Create the first-boot admin password
Create the datasource encryption key
plain. Every instance reads it on every boot to decrypt datasource credentials stored in the shared database — back it up outside Control Plane and never rotate it:admin.secretKeySecretName to the name you used.Create the app database credentials
username, password and database:username and database — they are used unquoted when the database is created. Set postgresML.postgres.credentialsSecretName to the secret’s name.Read a secret back later
-o json the command prints a table containing no secret data.UI
CLI
Terraform
Pulumi
Configuration
The defaultvalues.yaml for this template:
Locations
The location list lives underglobal so that Helm passes the same list to the bundled database, through it to etcd, and to the optional Redis tier. Never maintain two location lists.
global.locations[].name— A Control Plane location (e.g.aws-us-east-1) that must already be one of the locations of the GVC you install into. At least 2 are required, at least 3 withalerting.highAvailability.enabled: true, and the chart refuses to render with fewer.global.locations[].replicas— Database members in that location, not Grafana instances. It must be at least 1; removing a location from the list is the supported way to shrink the deployment. Grafana’s own count per location is the top-levelreplicas, etcd always runs exactly one member per location, and the Redis tier has its own count (redisML.redis.replicasPerLocation) — all three ignore this number.
Matching the Location List to the GVC
The platform validates the pairing in neither direction. A GVC location this release does not list is harmless — nothing runs there, and its deployments readThis workload location is deactivated because maxScale is set to 0. A location the GVC does not have is the dangerous direction: the platform accepts it, stores it, and it is simply inert, with no failed deployment to see.
Both Grafana tiers read the GVC at boot, using the scoped view grant described in What Gets Created, and log a warning naming any mismatch:
alerting.location must also appear in global.locations — a render-time check enforces that — so a mismatch is necessarily a global.locations mismatch, and the bundled etcd and Patroni tiers refuse to bootstrap on a fresh data directory for any location the GVC does not have. They crash-loop with a FATAL: line naming the location, Grafana never gets past its database gate, and nothing comes up half-working. Fixing the values and upgrading recovers the whole stack with no manual intervention.The quiet failure applies to a location removed from the GVC after the cluster was initialized: the database tiers then only warn and keep serving, so dashboards stay healthy while whatever ran in that location silently does not. See Alert Evaluation for what that costs when the location is alerting.location.Grafana UI Tier
image— The Grafana OSS container image. It must provide/bin/bash: the chart overrides the entrypoint to run Grafana’s/run.shthrough a boot wrapper. The default Alpine-based official image does.replicas— Grafana UI instances per location. It carries no alerting-related restriction in either mode — the only thing to watch is the connection budget below.resources—minCpu/minMemoryare the reservation,maxCpu/maxMemorythe limit, applied per instance.database.maxOpenConn— Maximum database connections per instance.
resources.maxCpu raised above the default — alerting.resources is unused in that mode.
Signup, anonymous access and upstream analytics are disabled by the template and are not configurable.
Admin Credentials and Encryption Key
Both credentials live in opaque secrets you create before installing (see Prerequisites) — neither ever passes through Helm values. They sit next to each other invalues.yaml but their lifecycles are opposites:
admin, so an instance without it that won the race for the empty database would create an admin/admin account on a publicly exposed UI. Testing confirms that does not happen: admin/admin is refused with a 401 on a fresh install.
Datasources as Code
datasources.definitions entries are standard Grafana datasource provisioning entries, rendered verbatim into a provisioning file that every instance of every Grafana workload mounts at boot. Applying the same file concurrently from every instance is safe — testing at ten instances produced exactly one row per definition.
Credentials never go into the provisioning file. Put them in a dictionary secret created before installing, list it under datasources.credentialSecrets, and reference each key as $KEY:
reveal on exactly that secret. Provisioned datasources are read-only in the UI — change the value and upgrade to change one.
SMTP
Grafana sends alert notification emails through the SMTP server you configure, and whichever instance evaluates is what actually sends them — the dedicated evaluator by default, or the coordinating UI instance when alerting HA is on.smtp.passwordSecretName is required whenever smtp.user is set, and the password stays in a pre-created opaque secret with encoding plain. Leave smtp.enabled: false if you use webhook or chat contact points instead.
Access
publicAccess.enabled applies to the UI tier only. When it is on, the tier is served on the canonical *.cpln.app HTTPS endpoint and Grafana’s root_url is derived from it automatically, including for the evaluator, so links in delivered notifications point at the UI tier and open in a browser. The dedicated evaluator itself is never reachable from the internet — it gets a canonical endpoint but requests to it are refused with a 403. With alerting HA on there is no evaluator workload, and the Redis tier is reachable from inside the GVC only.
workload-list, list only your clients. This chart’s own workloads — the UI tier and, when it renders, the alert evaluator — are appended for you, because the same list also governs the in-GVC path the silence procedure below uses. A client that is not listed is still refused.workload-list change took about four minutes. Allow several minutes and re-test before concluding a setting did not apply.App Database
ThepostgresML block configures the bundled postgres-multi-location cluster: one primary, asynchronous replicas in the other locations, an HAProxy leader-routing tier in each, and automatic promotion in a surviving location. Everything the database tier can do — pooling, restores, emergency quorum recovery, per-member addressing — is documented on that template’s page.
postgresML.internalAccess is the database tier’s own internal firewall, separate from this chart’s. Leave it at same-gvc unless you have a reason not to — see the warning under Access for what workload-list requires there.
postgresML.primaryLocation is a preferred location for the primary: the members elsewhere wait up to 90 seconds for it to initialize the cluster before bootstrapping themselves, and it also biases later elections. Keep it aligned with alerting.location so the evaluator’s queries have no cross-region hop. With alerting HA on it also decides which Grafana location runs the schema migrations first.
etcd History Compaction
postgresML.etcd.tuning.autoCompactionMode, postgresML.etcd.tuning.autoCompactionRetention and postgresML.etcd.tuning.quotaBackendBytes control how much revision history the database’s consensus store keeps and how large its backend may grow. Compaction has been enabled in every version of the bundled etcd chart; since template version 1.1.1 the values are also configurable here. The defaults — periodic, 1h and 0 (etcd’s own 2 GiB limit) — are the right settings for a Patroni consensus store and should be left alone: an etcd cluster that fills its backend goes read-only, which takes the database’s failover with it. See Compaction and Backend Growth for the mechanism and the accepted value formats.
Alerting-HA Coordination
TheredisML block configures the bundled redis-multi-location subchart — one Redis and one Sentinel per location, coordinating exactly-once notification delivery. It is rendered only when alerting.highAvailability.enabled is true, and ignored entirely otherwise.
redisML.engine—redis(the default, which changes nothing) orvalkey, which runs both the Redis and Sentinel tiers onredisML.valkeyImage. Valkey is the BSD-licensed fork of Redis 7.2 and shipsredis-server/redis-cli/redis-sentinelcompatibility symlinks, so Grafana’s Sentinel client is unchanged. It is an install-time choice: a data directory cannot be moved between engines.redisML.valkeyImage— The image used for both tiers whenengineisvalkey, at which pointredisML.redis.imageandredisML.sentinel.imageare inert.redisML.firewall.internalAllowType/.workloads— The coordination tier’s own internal firewall. See the warning under Access before setting it toworkload-list.redisML.redis.replicasPerLocation— Redis members per location. One is plenty: the data is a few kilobytes of coordination keys.redisML.redis.volumeset.initialCapacity— GiB per member, at the platform minimum of10.redisML.{redis,sentinel}.image/.resources— Passed through to the subchart. These blocks expose only a limit, so they use barecpuandmemory.redisML.{redis,sentinel}.passwordSecretName— Optional authentication, empty by default. See below.
Authenticating the Redis Tier
Authentication is off by default: enabling alerting HA is one flag and needs no extra secrets. The tier is reachable only from inside the GVC, and that same-GVC firewall is the boundary it relies on. Since version 2.0.0 that GVC is yours rather than this chart’s — it is the GVC you installed into, and it very likely already holds other workloads. Weigh the default accordingly and turn authentication on unless you control everything in that GVC. Write access to an authless Redis is enough to suppress your alert notifications, because a hostile or simply buggy neighbor can claim another peer already sent them, and alert coordination is precisely the thing you do not want failing quietly. Create either or both opaque secrets with encodingplain before installing:
ha_redis_password and ha_redis_sentinel_password, reading the same secrets the Redis tier reads, so the two sides cannot drift apart. Testing confirmed both ports reject unauthenticated clients (NOAUTH) and a wrong password (WRONGPASS) on a fresh install with the passwords set from the first boot, and again after authentication is turned on for an already-running authless install. Rotating the Sentinel password was verified the same way — the new password is accepted and the old one rejected on every Sentinel — and turning a password back off also takes effect, after which that port accepts unauthenticated clients again. In the authenticated runs all six Grafana instances registered their peer keys inside the authenticated keyspace. The fresh-install result was measured through this template; enabling, rotating and removing a password afterwards was measured on the redis-multi-location subchart’s own test run.
Alert Evaluation
alerting.enabled is the parent switch, on by default. Setting it to false creates no evaluator workload and turns rule execution off on every instance: alert rules and contact points can still be created and viewed, and nothing ever evaluates them. Testing measured exactly that — two always-firing rules present, both reporting a null evaluation timestamp, and zero notifications over 6 m 24 s — while the UI, logins and dashboards were unaffected. Combining alerting.enabled: false with alerting.highAvailability.enabled: true is a contradiction and fails at render time.
Everything below concerns the two shapes available while alerting is on. Grafana’s memberlist alerting HA coordinates instances over a UDP gossip channel, which is not available between workloads on Control Plane; Grafana’s Redis-backed coordination needs no peer port at all, and that is what alerting.highAvailability.enabled turns on.
Choosing an Alerting Mode
Read This Before Enabling HA
The other costs, at three locations and defaults: +6 containers and +6 × 10 GiB volumes for the Redis tier (minus the one evaluator container), constant cross-region heartbeat traffic to whichever location holds the Redis master, and rule evaluation landing on the UI tier’sresources rather than on alerting.resources.
Dedicated Evaluator Mode (the Default)
Rule execution is disabled on the UI tier and enabled on a separate workload pinned to one replica inalerting.location, with zero replicas in every other location. Nothing is elected at runtime, and no value of replicas can produce a second evaluator. alerting.location is required in this mode and must name one of global.locations; a render-time check enforces that.
Verified in testing at replicas: 3 across three locations: all 9 UI instances report rule execution disabled, the single evaluator reports it enabled, and the other two locations run no evaluator replica at all. In a later run at the default replicas: 1, an always-firing rule produced 41 notifications with 41 distinct request IDs over 26 minutes, every one of them from the evaluator’s own address.
- Losing the evaluator’s replica self-heals, and re-notifies. The platform reschedules it and evaluation resumes with no operator action — a gap of 21 seconds between the last notification from the old replica and the first from its replacement (measured on 1.0.0, before the database gate was extended, so expect this to be a floor rather than a ceiling), with the UI tier unaffected throughout. Each replacement boots with an empty notification log and immediately re-sends whatever is currently firing, so a restart costs duplicate notifications rather than missed ones.
-
Losing that whole location does not self-heal. Alert evaluation stops until you run
helm upgradewithalerting.locationset to a surviving location, and the UI gives no sign of it — dashboards look perfectly healthy while nothing is being evaluated. This is the failure alerting HA exists to remove. -
That silent shape only happens to a location removed from the GVC after the cluster was initialized. A fresh install naming a location the GVC lacks fails loudly instead:
alerting.locationmust also be inglobal.locations, and the bundled etcd and Patroni tiers refuse to bootstrap on a fresh data directory for any location the GVC does not have, so the whole stack crash-loops with a named error rather than coming up half-working. Either way the boot warning names the consequence explicitly — the evaluator workload holding zero replicas everywhere, and no alert rule ever being evaluated. -
Moving
alerting.locationdoes not open a two-evaluator window. Only the evaluator workload is updated; the UI tier is untouched and does not restart. In the measured relocation the old evaluator’s last notification preceded the new evaluator’s readiness by 57 seconds (measured on 1.0.0, same caveat), so the two never overlapped. Expect a gap of a few minutes with no evaluation while the new one boots. -
Silences are not expected to propagate between instances (not exercised in our testing). Without gossip, a silence created against the UI tier is not guaranteed to be honored by the evaluator, so create silences against the evaluator directly:
The API requires credentials, so the
-uflag is not optional.
Redis-Coordinated Alerting HA
Withalerting.highAvailability.enabled: true no evaluator workload is created. Every UI instance evaluates every rule, registers itself as a peer in the stretched Redis tier, and the peers order themselves so that exactly one sends the notification. Each instance selects its own local Sentinel and all of them resolve the same Redis master, across regions. Configure the tier — including optional authentication — under redisML.
Measured across three locations at replicas: 2 (six evaluating instances):
- Which location sends is not pinnable. The sender is chosen by sorted peer name, and a standard workload’s name carries a ReplicaSet hash that changes on every rollout — the elected sender moved from
aws-us-east-1toaws-us-west-2between two installs of the same chart. Do not build routing, filtering or egress-IP allowlisting on the assumption that a particular location sends. - After a location is lost, hand-off is not instant — and this one is derived, not timed. Two things were measured directly: the Redis peer keys carry a 5-minute TTL, so a dead location’s peers keep their positions until it expires, and a location other than the previous sender was observed taking alerting over on its own after a rollout reordered the peers. The loss event itself has never been observed — no platform primitive simulates a true region outage — so “alerting continues from the survivors and only the sending instance changes” follows from those two measurements rather than from a timed failover. On the same basis, expect roughly 30 s of extra delay before the first notification from a survivor, decaying to zero as the dead peer keys expire (derived from the 5-minute TTL and Grafana’s peer-timeout default, not timed).
Cross-Location Behavior
Every instance shares one database, so there is no replication step between a write in one location and a read in another. Verified across three locations atreplicas: 2 — six UI instances plus the evaluator, each result attributed to a named individual instance:
Connecting
Substitute your release name and the name of the GVC you installed the release into./api/health, which reports the Grafana version and the app-database status. The Grafana HTTP API is available on the same endpoint for scripted dashboard, datasource and alert-rule management.
RELEASE_NAME-grafana.GVC_NAME.cpln.local:3000 is always served by an instance in the caller’s own location. That is why a single write-then-read from one client proves nothing about cross-location state.Migrating From Version 1
Every release before 2.0.0 created its own GVC. Do nothelm upgrade a 1.x release onto 2.0.0. Once the chart stops declaring a GVC, Helm prunes the one the old release created — and deleting a GVC deletes every workload, volume set and identity inside it: both Grafana tiers, the whole Patroni cluster and its data volumes, the etcd store behind it, and the Redis coordination tier. Measured on a sibling template: everything was gone in about six seconds, while the command printed upgraded successfully.
etcd-multi-location or postgres-multi-location rather than this chart. Helm renders the deepest subchart first and every chart in the stack carries the same guard on the same key, so a subchart’s copy aborts the render first. The remedy is identical.Back up the 1.x database
postgresML.backup.mode: logical, or run a pg_dumpall through the old release’s {release}-postgres-proxy endpoint. Everything that makes up your Grafana — dashboards, users, orgs, datasources, alert rules and alert state — lives in that database, so this one dump carries all of it.Rewrite your values
global.gvc.name and rename global.gvc.locations to a top-level global.locations. Every location you list must already exist in the GVC you are installing into.Install 2.0.0 as a new release into an existing GVC
Reuse the same encryption key
admin.secretKeySecretName at the same secret the old release used. It decrypts the datasource credentials stored in the dump, and a different key makes every saved datasource credential unreadable.Restore the dump, then move your users to the new endpoint
postgres-multi-location page has the exact restore command; run it from a client workload in the same GVC.Remove the old release
Availability and Planned Outages
Measured on three locations (aws-us-east-1, aws-eu-central-1, aws-us-west-2).
Failed to lock database line during a cold start is expected, and it clears itself. Grafana runs its schema migrations under a non-blocking lock with no retry, so an instance that arrives while another holds the lock exits; the platform restarts it and the next attempt succeeds against the already-migrated schema. The chart staggers the UI instances so they do not arrive together, which removes these restarts at the default one replica per location. Two replicas in the same location still start together, so a few remain at replicas: 2 — two three-location runs at that setting measured 2 and 3 container restarts, most of them this lock race. They are far more numerous when the database primary does not land in postgresML.primaryLocation, because the migrations then run cross-region and instances keep restarting while they finish — 15 at replicas: 1, against 0 at that same setting with the primary in place. Nothing needs doing either way.Backing Up
Backups are disabled by default and cover the app database — the dashboards, users, alert rules and saved datasources that make up your Grafana. Enable them withpostgresML.backup.enabled: true, choose logical (a scheduled pg_dumpall cron workload in the one location named by postgresML.backup.location) or wal-g (continuous archiving from whichever member is currently the primary), and complete the storage setup for your provider before installing.
- AWS S3
- Google Cloud Storage
- MinIO / S3-compatible
Create a bucket
postgresML.backup.aws.bucket and postgresML.backup.aws.region to match.Set up a Cloud Account
postgresML.backup.aws.cloudAccountName to its name.Create a bucket-scoped IAM policy
YOUR_BUCKET_NAME), then set postgresML.backup.aws.policyName to the policy’s name. This bucket-scoped policy is all the identity needs — no broad managed policy is required.Choose a prefix
postgresML.backup.aws.prefix to the folder path within the bucket.Important Notes
- Create the admin password, encryption key and database credentials secrets before installing. The chart creates none of them; without them the deployment waits on secrets that do not exist while
helm installreports success. - There is no upgrade path from 1.x. Every 1.x release created its own GVC; 2.0.0 deploys into an existing one, and a
helm upgradeacross that boundary deletes the old GVC and everything in it, database volumes included. The chart refuses to render on the 1.xglobal.gvckey, but that guard cannot see an upgrade run with no values at all. Follow Migrating From Version 1. - Every location in
global.locationsmust already exist in the GVC you install into. A GVC location this release does not list runs nothing, which is harmless. A listed location the GVC lacks makes a fresh install crash-loop in the database tier with a named error, and — for a location removed from a GVC after initialization — silently runs nothing there. See Matching the Location List to the GVC. - Setting either subchart’s firewall to
workload-listrequires listing the Grafana workloads in it. The chart refuses to render otherwise and prints the exact links to add; this chart’s own list adds its own workloads for you. - Never rotate or delete the encryption key. Every instance in every location decrypts stored datasource credentials with it; changing it makes them all unreadable and alert rules that query them fail.
- Every
helm upgradethat touches the database tier is a planned outage. The database went unavailable for about 2 m 17 s and the Grafana tier took about 5 minutes to finish rolling every replica. A build whose primary bootstrapped outsideprimaryLocationwas worse — about 4 minutes to recover, one location 5–6 minutes — so treat that as the worst case. The first upgrade after any install costs this even for a Grafana-only change. Changes confined to the Grafana workloads roll with zero downtime. - An upgrade that adds a secret reference can pause the rollout for about 9–10 minutes while Helm reports success. It clears itself with no action, and the grant is already in place — there is nothing to fix in the policy. Enabling
smtp,datasources.credentialSecretsorpostgresML.backupare examples that trigger it. - Alert evaluation stops if you lose
alerting.location, and the UI will not show it. Repoint the knob and upgrade; that restarts only the evaluator. Setalerting.highAvailability.enabled: trueto remove that failure — read the query-load cost in Alert Evaluation first. - Silences must be created against the evaluator, from a workload in
alerting.location— its internal address returns503from every other location. With alerting HA on there is no evaluator and this does not apply. alerting.locationis required while alerting is on and HA is off, and it is ignored with HA on. It is no longer a disable switch: usealerting.enabled: falseto stop rule evaluation entirely, which also fails at render if combined withalerting.highAvailability.enabled: true.- Turning alerting HA on or off changes which workloads exist. Enabling it deletes the
{release}-grafana-alertingworkload and adds a Redis and a Sentinel workload per location; disabling it does the reverse. It is a normalhelm upgrade, but treat it as a planned change, not a toggle to flip during an incident. - Alerting HA multiplies data-source query load by (locations × replicas) — 3× at the defaults — because every instance evaluates every rule and Redis dedupes the notification, not the query.
- Alerting HA is blocked below 3 locations, on purpose. Sentinel elects a master by a majority of locations, so at 2 locations losing either one leaves no quorum.
- With alerting HA on, an unhealthy Redis means duplicate notifications, never silence. Check the
{release}-redisand{release}-sentinelworkloads before suspecting your alert rules. - With alerting HA on, a
helm upgradecosts 80–95 s of duplicate notifications, even an upgrade that changes nothing, and post-outage sender hand-off is not instant — the Redis peer keys’ 5-minute TTL was measured, but the hand-off itself is derived from it rather than timed against a real outage. - Which location sends notifications is not pinnable with alerting HA on. The sender is chosen by sorted peer name and moved between regions across two installs of the same chart, so do not route, filter or egress-allowlist on it.
- The alerting-HA Redis tier is unauthenticated by default, reachable only from inside the GVC you install into — which since 2.0.0 is a GVC you own and may already share with other workloads. Authenticate it unless you control everything in that GVC: write access to it is enough to suppress alert notifications. See Authenticating the Redis Tier.
- If you do set
redisML.redis.passwordSecretNameorredisML.sentinel.passwordSecretName, a wrong name stops the Grafana UI too, because Grafana reads the same secret — andhelm installstill reports success. If a tier sits at 0 replicas after install, readstatus.versions[].messageon the workload. - Use the canonical
*.cpln.appendpoint, not a per-location hostname. Grafana is configured with a single absoluteroot_url(the canonical endpoint). On a per-location hostname the UI and dashboard layout load, but the POST that fetches panel data is rejected — you get a dashboard with empty panels and no error shown. The canonical endpoint is georouted and already serves from the nearest location. - A provisioned datasource reporting
upstream connect error ... connection timeoutis almost always an unsubstituted placeholder in its URL, not a network or firewall problem. Check the GVC segment ofdatasources.definitions[].urlfirst — a name that does not resolve times out rather than failing fast, and nothing in the Grafana UI names the cause. - The public endpoint is proximity-routed. More locations means regional redundancy and locally served traffic, not requests spread across regions.
- Every location except the database primary’s pays a cross-region round trip per query, because Grafana has no read/write splitting. Set
postgresML.primaryLocationwhere most of your users are. - Scaling
replicashas no alerting-related restriction — it applies to the UI tier only, in every location includingalerting.location. Watch the connection budget instead. replicas: 2or higher lengthens a cold install to roughly five and a half minutes. Nothing is wrong; there is simply more to schedule.- Grafana Live has no HA engine here, so a live-streamed message reaches only the browsers connected to the same instance — carried over from the single-location Grafana template’s multi-replica behaviour, and not exercised in this template’s own testing. Dashboard auto-refresh, queries, alerting, provisioning, login and the API are unaffected.
- With
publicAccess.enabled: false, links in alert notifications point at the internal GVC address and will not open from a browser outside the GVC. - Never suspend a location. Suspending and resuming one permanently withdraws its endpoints from the other locations’ service discovery while every status surface still reports healthy. To remove a location, take it out of
global.locationsand out of the GVC. - Uninstall deletes every volume set the chart created — the database, etcd and, with alerting HA on, Redis and Sentinel. The GVC is yours and is left alone. Enable backups if the data matters. Prerequisite secrets you created are not owned by the release and survive it.
- This template ships Grafana OSS only — Enterprise features such as fine-grained RBAC, reporting and query caching are not available.