Skip to main content

Overview

Metabase is an open-source business intelligence platform — dashboards, a SQL editor and scheduled report subscriptions over databases you already run. This template deploys the free open-source edition as a single stateless workload backed by a bundled PostgreSQL app database (users, dashboards, saved connections): the postgres-highly-available template by default, or the single-instance postgres template with one flag. The databases you analyze are data sources you connect in the app after install — the template never installs or touches them. The admin account is created automatically on first boot from a secret you create, and the workload only starts receiving traffic once that setup is complete, so there is never a publicly reachable setup page.
This template deploys into an existing GVC that you already have — it does not create or manage a GVC. Every workload below runs in each location of that GVC.

What Gets Created

Metabase itself has no volume set — every question, dashboard, user and saved connection lives in the app database. The admin login and the encryption key are prerequisite secrets you create yourself; the chart references them by name and never creates, modifies or deletes them.

Prerequisites

Two secrets must exist before you install. The admin login guards a form on a public endpoint and the encryption key is long-lived key material, so neither is a Helm value and neither ever lands in the release. Secrets are org-level, so no --gvc flag is involved.
1

Create the admin login secret

A dictionary secret holding exactly the keys email and password. The password must satisfy Metabase’s own check — letters and digits, 8 or more characters; the generated value below does:
Set admin.secretName to this name. Read the values back later with cpln secret reveal ADMIN_SECRET_NAME -o yaml — the -o yaml is required; a bare reveal prints only a summary table.
2

Create the encryption-key secret

An opaque secret with encoding plain whose whole payload is a random string of at least 16 characters. Metabase encrypts every saved data-source connection with it, on every boot, for the life of the install:
Set encryptionKey.secretName to this name, and store a copy of the key somewhere safe outside Control Plane.
3

Choose the app-database password

The bundled database’s credentials are internal plumbing: this chart writes 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-metabase-db-password, so set postgres.credentials.password to a value of your own before installing. This applies in both database modes, even with postgres.enabled: false.
Neither the admin email nor the password may contain a double quote (") or a backslash (\). Both values are embedded in the JSON body of Metabase’s first-boot setup call, and either character breaks it. The container checks this at startup and refuses to run setup rather than send a malformed request; the workload then never becomes ready and its logs carry a cpln-bootstrap: ERROR line naming the secret. Fix the secret’s contents and force a redeployment.
A missing prerequisite secret wedges the install rather than failing it. cpln helm install reports success and every resource is created, but the Metabase container never starts — so cpln logs returns zero lines. The only place the missing secret is named is status.versions[].message:
The message reads The secret <name> no longer exists. Workload updates are paused until the secret is added or the reference to the secret removed. It is get-deployments — plain cpln workload get has no versions key. Create the missing secret and the deployment recovers on its own after several minutes, or run cpln workload force-redeployment RELEASE_NAME-metabase --gvc GVC_NAME to skip the wait.
The two secrets have different lifecycles — read Admin Account and Encryption Key before you change or delete either one. Optional database backups need a bucket and access setup on AWS S3, Google Cloud Storage or an S3-compatible server, and S3-compatible servers additionally need a dictionary secret with the bucket keys — see Backing Up.

Installation

Once both secrets exist, install the template into your GVC, naming the secrets and replacing the database password placeholder:
Prefer a values file (--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

Browse, install, and manage templates visually

CLI

Manage templates from your terminal

Terraform

Declare templates in your Terraform configurations

Pulumi

Declare templates in your Pulumi programs

Configuration

Metabase Instance

The template caps the JVM heap at 75% of the container memory limit, so raising resources.maxMemory also raises the Java heap. The 2 GiB default is sized for the JVM — lowering it is not recommended. image must provide /bin/bash: the chart wraps Metabase’s own entrypoint in a short start script, and the official image does. Anonymous usage tracking is disabled by the template and is not configurable.

Admin Account and Encryption Key

Both secrets are created by you before installing (see Prerequisites); neither value passes through Helm. They sit next to each other but their lifecycles are opposites: admin.firstName, admin.lastName and siteName are ordinary values, used by the first-boot setup for the admin’s display name and the instance name; like the secret’s contents they may not contain double quotes or backslashes, which the chart rejects at render.
The encryption-key secret is permanent. Deleting it wedges the workload on a missing secret reference, and changing its payload makes every data-source connection already saved in the app database undecryptable — you would have to re-enter every one. Back the key up outside Control Plane instead of rotating it. Metabase does ship an offline rotate-encryption-key command, but this template exposes no procedure for it.

Access

  • publicAccess.enabled — Serve the UI and API on the canonical *.cpln.app HTTPS endpoint (default). Metabase is a browser tool people open directly, everything behind the endpoint is gated by its own login, and that login is a credential you created rather than a published default. Metabase’s site URL is derived from the canonical endpoint automatically. Set it to false for an internal-only instance — external requests are then refused while in-GVC callers still reach it per internalAccess, and you reach the UI yourself with cpln port-forward (see Connecting).
  • internalAccess.type — Internal firewall scope of the Metabase workload:
Allow several minutes after changing an access knob before concluding it did not apply.

App Database

Exactly one of the two database modes must be enabled — the chart enforces this at render and refuses to install otherwise. Metabase is wired to the active database automatically: the HAProxy leader endpoint in HA mode, or the single instance directly.
In both modes the database credentials come from 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. In HA mode the proxy must stay enabled — that endpoint is Metabase’s stable database address, and the chart refuses to render with postgresHA.proxy.enabled: false. 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.

Connecting

Verify the instance from inside its own container — the Metabase image ships curl:
With publicAccess.enabled: false there is no canonical endpoint; open a tunnel to the UI instead and browse to http://localhost:3000:

First Run

Metabase normally greets a fresh install with a setup wizard. This template runs that step for you: on first boot the start script creates the admin account through Metabase’s local setup API using the email and password from your admin secret and the name in admin.firstName / admin.lastName, and the workload only reports ready once setup is complete — so no unauthenticated setup page is ever exposed. A fresh install in HA mode takes several minutes to become ready while the database cluster forms and Metabase runs its schema migrations.
1

Wait for the workload to report ready

If it stays not-ready well past the first few minutes, read its logs for a cpln-bootstrap line — that is where a failed admin setup is explained:
2

Sign in

Open the canonical endpoint (or the port-forward URL) and sign in with the email and password from your admin secret. Change the password in the UI if you wish — that is the only place it changes from now on.
3

Add your first data source

Go to Admin → Databases and add the database you want to analyze — see Adding Data Sources.
Setup runs exactly once. Metabase reads the admin secret only while creating the account, so editing the secret afterwards does not change the existing login, and an upgrade never resets the password you set in the UI.

Adding Data Sources

The databases you analyze are added inside Metabase after install (Admin → Databases) — the template never installs or touches them. To analyze a database running on Control Plane in the same GVC, use its internal address as the host, for example WORKLOAD_NAME.GVC_NAME.cpln.local on port 5432. Any database Metabase can reach — inside or outside Control Plane — works as a data source. The connection credentials you enter are encrypted at rest with your encryption key.

Operations

Backing Up

Database backups are optional and disabled by default. They cover the app database — the questions, dashboards, users and saved connections that make up your Metabase instance. Enable them on whichever database is active and complete the storage setup for your provider before installing or upgrading with them on.
In HA mode postgresHA.backup.mode selects logical (a scheduled pg_dumpall run by the RELEASE_NAME-postgres-ha-backup cron workload through the HAProxy endpoint) or wal-g (continuous WAL archiving from a sidecar on the database workload itself, with no separate backup workload). The single-instance database takes scheduled logical dumps only, through RELEASE_NAME-postgres-backup. 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.*.
1

Create a bucket

Create an S3 bucket. Set postgresHA.backup.aws.bucket and postgresHA.backup.aws.region to match.
2

Set up a Cloud Account

If you do not have one, create a Cloud Account for the AWS account holding the bucket. Set postgresHA.backup.aws.cloudAccountName to its name.
3

Create a bucket-scoped IAM policy

Create an IAM policy with the JSON below (replace YOUR_BUCKET), then set postgresHA.backup.aws.policyName to the policy’s name:
A database backup does not cover your two prerequisite secrets — the admin login and, above all, the encryption key, which the restored data is useless without. The database volume sets take no scheduled snapshots; a final snapshot is taken when the volume set is deleted and kept 7 days.

Restoring a Backup

No restore path has been rehearsed against this template. The outline below follows the backup job’s output format and the chart’s configuration; rehearse it against a scratch release before you depend on it. Restoring from a volume set snapshot is likewise unverified here.
A restore goes into the database, not into Metabase: everything that makes up your instance lives there, so restoring it brings back questions, dashboards, users and saved connections together. Each logical backup is a gzip-compressed pg_dumpall of the whole server (postgres-<timestamp>.sql.gz under your prefix), so restoring means replaying it with psql from a client that can reach both the bucket and the database — a workload inside the GVC, or your own machine with a tunnel open. The Metabase container has neither psql nor a cloud CLI, so do not run it from there. In HA mode go through the HAProxy endpoint so the writes land on the leader:
Use RELEASE_NAME-postgres as the workload name in single-instance mode. Then, with PGPASSWORD set to the password from the app-database credentials secret (cpln secret reveal DB_CREDENTIALS_SECRET_NAME -o yaml):
Use gsutil cp "gs://BUCKET_NAME/PREFIX/BACKUP_FILE.sql.gz" - for GCS, and add --endpoint-url with your MinIO address for an S3-compatible server. The dump contains the role and the metabase database created at first boot, so a straight replay into a running instance collides with them: restore into an empty database (a fresh release, or one whose metabase database you have dropped) and keep the Metabase workload from connecting until the replay has finished. The step-by-step procedures for each store, including the WAL-G outline for HA mode — which ends in a manual volume-set swap this chart does not expose — are on the postgres-highly-available and postgres pages. Restore into a release that uses the same encryption key: encryptionKey.secretName decrypts the data-source connections stored in the dump, and a different key makes every saved connection unreadable. Because the restored app database already carries a completed setup, the first-boot admin setup does not run again — the admin account in the dump is the one you sign in with.

Upgrading from 1.0.x

Two changes landed in the 1.0.x to 1.1.0 range; apply both when upgrading from 1.0.0. 1.0.1 — etcd compaction. Version 1.0.0 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.0.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. 1.1.0 — the admin login became a prerequisite secret. Earlier versions shipped admin.email and a working admin.password as values — a published default guarding a login form on the public endpoint. An upgrade that still carries either key is rejected at render, before anything is applied, with a message naming its replacement; there is no compatibility fallback.
1

Create the admin login secret

Follow Prerequisites. Its contents only matter to a fresh install — the account already exists in your app database and first-boot setup never runs again, so your existing admin password does not change on upgrade. Any values work; put your current login in for clarity.
2

Drop the removed keys and upgrade

Remove admin.email and admin.password from your values and set admin.secretName. admin.firstName, admin.lastName, siteName and encryptionKey.secretName are unchanged. The single Metabase replica restarts; questions, dashboards and users are in the app database and are untouched.
3

Change the admin password in the UI

If the install was still using the published 1.0.x default password, treat it as compromised and change it now in Metabase’s account settings — the secret cannot change an existing account. Every later migration note below also applies.

Upgrading from 1.1.0

Version 1.2.0 adopted the postgres 3.4.1 template, which stopped taking database credentials as values. Metabase absorbed that change — the chart now creates the credentials secret itself — so there is no new prerequisite, only a rename of three keys in single-instance mode: Move the keys keeping the same values — PostgreSQL enforces the credentials written when the volume was first created, and different values just leave Metabase unable to authenticate. A values file that still carries an old key fails the render with the postgres template’s message, which tells you to create a dictionary secret yourself — ignore that advice here; 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 is unchanged by this step.

Upgrading from 1.2.0

Version 1.3.0 adopted the postgres-highly-available 2.5.0 template, which made the same change on the HA path, and 1.3.1 did the same for its MinIO backup keys. The HA database credentials now come from the same postgres.credentials.* block as the single-instance ones, and the chart creates the secret named by postgresHA.config.credentialsSecretName for both stores. Move the three credential values unchanged into postgres.credentials.* — the running cluster was initialized with them — and delete the postgresHA.postgres block entirely. Leaving postgres.enabled: false is correct; the postgres.credentials.* values feed both database modes. A values file that still carries the old block stops the upgrade at render:
The message’s instruction to create the secret yourself does not apply — this template creates it. If you back up the HA database to an S3-compatible server, create the credentials secret described under Backing Up with the same access key and secret key, set postgresHA.backup.minio.credentialsSecretName, and remove the two old keys; if you are already on 1.3.0, that MinIO change is the only part of this step that applies. The details of the subchart change are under Upgrading From 2.4.x on the postgres-highly-available page.

Upgrading from 1.3.x

Version 1.4.0 renamed the Metabase container’s resource limits: a block that exposes both a reservation and a limit now names the limit maxCpu / maxMemory, so it is no longer ambiguous which number is the ceiling. Nothing else changed. An upgrade that still carries either old key is refused at render with metabase: resources.cpu was RENAMED to resources.maxCpu (or the memory equivalent); rename the two keys and upgrade. resources.minCpu and resources.minMemory keep their names.

Scaling and Availability

  • Metabase runs as a single replica in this template, and no replicas knob is exposed. It holds no state of its own, so a replaced replica comes back with everything intact; the highly available default database removes the database as a failure point.
  • Database replicas are set with postgresHA.replicas; the single-instance database must stay at one replica.
  • Every Helm upgrade restarts the Metabase replica, so expect a short UI outage per upgrade. The first helm upgrade after an install can additionally restart the bundled database even when no database value changed.
  • Rotating a prerequisite secret does not restart anything. The admin secret is only read on first boot, so there is nothing to rotate there — change the password in the UI. Never rotate the encryption key. After fixing a rejected admin secret on a fresh install, run cpln workload force-redeployment RELEASE_NAME-metabase --gvc GVC_NAME so the container reads the new contents.
  • Confirm an upgrade is live from the deployment, not from the Helm output — cpln workload get-deployments RELEASE_NAME-metabase --gvc GVC_NAME -o yaml.
  • 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

Symptom: cpln helm install succeeded, but RELEASE_NAME-metabase shows no containers and cpln logs returns nothing.Cause: A prerequisite secret named in your values does not exist — the admin secret or the encryption-key secret. The deployment pauses on the unresolved reference.Fix: Read the message naming the secret, then create it:
The message reads 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-metabase --gvc GVC_NAME to skip the wait.
Symptom: The container runs, /api/health answers, but RELEASE_NAME-metabase stays not-ready and its logs contain a line starting cpln-bootstrap: ERROR.Cause: The first-boot admin setup failed, and the workload is deliberately kept unready rather than exposing an open setup page. The line says why: the email or password in the admin secret contains a double quote or a backslash (must not contain a double quote or a backslash), the setup call was rejected (POST /api/setup failed with HTTP 400 — most often a password that fails Metabase’s own check, which requires letters and digits and 8 or more characters), or the health endpoint never answered within the bootstrap’s own wait.Fix: Correct the admin secret’s contents, then run cpln workload force-redeployment RELEASE_NAME-metabase --gvc GVC_NAME. On a fresh app database the setup runs again with the new values. Read the line with a server-side filter:
Symptom: Several minutes after install, RELEASE_NAME-metabase is still not ready, and no cpln-bootstrap: ERROR line has appeared.Cause: Metabase cannot finish its schema migrations until the bundled database cluster has formed and the HAProxy endpoint routes to a leader, and the workload reports ready only once first-boot setup has completed on top of that. On a fresh HA install the container may restart while the database comes up — that is expected and self-correcting.Fix: Wait, then re-check cpln workload get-deployments RELEASE_NAME-metabase --gvc GVC_NAME -o yaml. Confirm the database tier is ready first: cpln workload get-deployments RELEASE_NAME-postgres-ha --gvc GVC_NAME -o yaml.
Symptom: The install stops with metabase: 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.
Symptom: Installing a second release of this template in the same org fails with 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-metabase-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.
Symptom: Data sources that worked before now fail, and Metabase cannot read the connection details it stored for them.Cause: The payload of the secret named by encryptionKey.secretName was changed, or the secret was deleted and recreated with a different value. Metabase reads the key on every boot to decrypt saved connections; a different key cannot decrypt them.Fix: Restore the original key from your backup of it and run cpln workload force-redeployment RELEASE_NAME-metabase --gvc GVC_NAME. If the original key is gone, re-enter the credentials of every saved data source.
Symptom: helm upgrade stops at render with admin.password was REMOVED in 1.1.0, config.username was REMOVED in postgres 3.4.0, the postgres block was REMOVED in 2.5.0, backup.minio.accessKey and backup.minio.secretKey were REMOVED, or resources.cpu was RENAMED to resources.maxCpu.Cause: Your values still carry a key that moved in template versions 1.1.0, 1.2.0, 1.3.0, 1.3.1 or 1.4.0. The existing release is left untouched and running.Fix: Follow the matching migration note above — Upgrading from 1.0.x, Upgrading from 1.1.0, Upgrading from 1.2.0 or Upgrading from 1.3.x — keeping the credentials the database already uses. Do not create a database credentials secret yourself; this template creates it.

Important Notes

  • Create the admin and encryption-key secrets before installing, and change postgres.credentials.password from its change-me placeholder. 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; a database backup is useless without it.
  • The admin secret applies on first boot only. Change the password in the Metabase UI; editing the secret later changes nothing, and an upgrade never resets your password.
  • Neither the admin email nor the password may contain a double quote or a backslash, and the password needs letters and digits, 8 or more characters — a rejected setup keeps the workload unready by design rather than exposing a setup page.
  • Give each release its own credentialsSecretName — secret names are org-wide, and a second release on the default name is refused at install.
  • Questions, dashboards and users live in the app database and survive Metabase restarts. Uninstall deletes the database volume sets — enable backups if the data matters.
  • Metabase is single-replica in this template — every upgrade restarts it; the highly available default database keeps running and no data is lost.
  • Prerequisite secrets you create are not owned by the release — they survive helm uninstall and must be deleted manually if you no longer need them.
  • This template ships the open-source image only — Pro/Enterprise features (SSO, sandboxing, config-file initialisation) are not available.

External References

Metabase Documentation

Official Metabase documentation

Environment Variables

Metabase environment variables reference

Encrypting Database Details

How the encryption key protects saved connection credentials

Metabase in Production

Upstream guidance on running Metabase in production

Metabase Template

View the source files, default values, and chart definition