Skip to main content

Overview

CockroachDB is a distributed SQL database with PostgreSQL wire compatibility, automatic replication and built-in fault tolerance. This template deploys a CockroachDB cluster (cockroachdb/cockroach:v25.4.0) with a configurable number of nodes in each location you list, a PgBouncer connection pooler in front of it, and an optional cron job that writes scheduled full-cluster backups to S3 or GCS. On first deployment the cluster initializes itself and creates a database and user. With three or more locations it also registers every location as a CockroachDB region and sets the database’s survival goal to SURVIVE REGION FAILURE, so the loss of one whole location does not interrupt reads or writes. The default is a single location with three nodes, which survives the loss of a node but not of a location.
This template deploys into an existing GVC that you already have. It does not create, provision or manage a GVC. Every location you list in locations must already be on that GVC, and a GVC location you did not list simply starts nothing — no CockroachDB node and no PgBouncer replica runs there.

What Gets Created

The cluster runs in CockroachDB’s insecure mode: there are no SQL credentials, and access is governed by internal_access and the GVC boundary. Neither workload is exposed publicly.

Prerequisites

The GVC you install into must already have every location you list in locations. The default list is one location, aws-us-east-1; if your GVC does not have it, change locations before installing (see Locations). The requirement is one-directional — the GVC may have more locations than you list, and nothing CockroachDB-related runs in those.
1

Check the GVC's locations

The locations are listed under spec.staticPlacement.locationLinks:
2

Add a missing location, or change your values

Either add the location to the GVC (cpln gvc add-location, documented in the gvc CLI reference) or edit locations to match what the GVC has. Every workload in a GVC runs in every location that GVC has, so add locations to a shared GVC deliberately.
A location the GVC does not have is not caught at install time. The install succeeds — the platform does not validate it — and each CockroachDB node then checks the GVC itself at boot. A node with no data yet refuses to initialize and restarts with this in its logs:
A node that already holds data logs a WARNING instead and keeps serving, so this check never takes down a running cluster. Every startup guard prints a [cockroach]-prefixed line naming what is wrong; read them with a server-side filter:
Nothing else is required for a default install. Backups additionally need a bucket and a Control Plane cloud account before they can be enabled — see Backing Up.

Installation

A default install needs no values when GVC_NAME has the aws-us-east-1 location:
If it does not, or you want more than one location, put your locations list in a values file and pass it with Helm’s -f values.yaml. locations is a list, so it cannot be set with --set — the chart refuses --set locations=[] with a message saying so.

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

Each block below is the shipped default for that part of values.yaml.

Locations

Each entry pairs a location with the number of CockroachDB nodes to run there. Every location listed must already exist in the GVC (see Prerequisites); a GVC location you did not list runs nothing. For a cluster that survives the loss of a location, list at least three:
The chart refuses to render, before anything is applied, when the list is empty, a location is listed twice, an entry has no name, a location has replicas: 0, or the total is a single node:
  • replicas: 0 is refused. To stop running in a location, remove it from locations — a zero-replica location would still be added to the database as a region that no node ever joins.
  • A one-node deployment is refused. Each node joins every other node, so a single node has nothing to join and cannot start. Use at least 3 replicas in total; 3 in one location is the smallest supported shape, matching CockroachDB’s default replication factor of 3.
GVC locations you did not list appear in the console as deactivated, with This workload location is deactivated because maxScale is set to 0. That is what a healthy install looks like on a GVC with extra locations, not a fault.

Image and Multi-Zone Placement

multiZone: true spreads the nodes across availability zones within each location.
Confirm every location in your GVC supports multi-zone placement before enabling multiZone. A location that does not support it accepts the setting and then wedges: the workload never becomes ready, no container starts, and cpln logs returns nothing. If that happens, read status.versions[].message from cpln workload get-deployments RELEASE_NAME-cockroach --gvc GVC_NAME -o yaml, set multiZone: false and upgrade. Leave it false if you are unsure.

Resources

Per CockroachDB node. Scale the cluster horizontally with locations[].replicas and vertically here.

Database

The database and user are created on the first initialization only, and the user is granted ALL on that database. On an existing cluster, changing these values does nothing — use ALTER USER or ALTER DATABASE ... RENAME TO inside CockroachDB instead.

Storage

Every node gets its own ext4 volume of this size on general-purpose-ssd storage, with a final snapshot on deletion retained for 7 days.

Internal Access

internal_access governs direct connections to the CockroachDB nodes only when PgBouncer is disabled. With PgBouncer enabled (the default), the nodes accept connections from this release’s own workloads only, clients are expected to go through the pooler, and pgbouncer.internal_access is the knob that controls who reaches it.
List only your clients. The chart adds this release’s own workloads — the nodes, PgBouncer and the backup cron — to every workload-list it renders, because node-to-node replication is inbound traffic to the same workload and would otherwise be cut off. You never need to list them yourself.
A change to either access list takes up to a few minutes to take effect; re-test rather than trusting the first response.

PgBouncer

PgBouncer multiplexes application connections into a smaller pool of real database connections and is configured with every CockroachDB node in every location as a backend, so failover and load distribution across nodes are handled for the client. Its backend list is built at container start from the same location list the nodes use to find each other, so the two cannot disagree about which nodes exist.
  • maxDbConnections is a hard cap on real CockroachDB connections shared across all PgBouncer replicas — set it to what your cluster can safely accept regardless of how many replicas are running.
  • minReplicas / maxReplicas apply per location; PgBouncer autoscales on request rate between them.
  • resources names the limit maxCpu / maxMemory beside the reservation minCpu / minMemory. The pre-2.0.0 names cpu and memory are refused at render with a message naming the replacement.
  • The remaining timeouts are PgBouncer’s own settings, in seconds — see the PgBouncer configuration reference.

Backup

The bucket, cloud account and (on AWS) IAM policy must exist before you enable backups — see Backing Up for the per-provider steps. backup.location must be one of locations: the backup cron runs in exactly that location and is suspended everywhere else, and the chart refuses to render otherwise.

Connecting

The template exposes no public endpoint. Reach the cluster from workloads in the same GVC, or from your own machine through cpln port-forward. A PostgreSQL connection string through the pooler, with TLS off because the cluster is insecure-mode:
Verify the cluster from inside a node. --replica names one replica of the stateful workload; on a release with more than one location, add --location LOCATION to pick the location:
Every node you configured should be listed with is_available and is_live both true. To open the DB Console — cluster health, node status and SQL activity — from your machine, forward port 8080 and open http://localhost:8080:

Operations

Backing Up

When backup.enabled is true, the RELEASE_NAME-cockroach-backup cron workload runs on backup.schedule and issues one SQL statement against the cluster (through PgBouncer when it is enabled):
(gs://BUCKET_NAME/PREFIX?AUTH=implicit on GCS.) Two consequences shape how you restore:
  • It is a full-cluster backup, not a backup of mydb alone: every database, every table, users and cluster settings land in one backup collection at BUCKET_NAME/PREFIX/. Each run adds a new full backup to that collection; nothing deletes older ones, so manage retention with a bucket lifecycle rule.
  • The CockroachDB nodes upload the data themselves, authenticating with the workload identity’s cloud account binding (AUTH=implicit). The cron job only triggers the statement, which is why the cloud permissions are on RELEASE_NAME-cockroach-identity and the restore statements later on this page run from a node.
backup.location must be one of locations — the cron is suspended everywhere else, and the chart refuses to render otherwise, because the platform accepts a location that does not exist and the job would then never run anywhere with no failed run to observe. Set it to the location nearest your bucket to avoid cross-region egress.
1

AWS S3

  1. Create an S3 bucket. Set backup.aws.bucket to its name and backup.aws.region to its region.
  2. If you do not have a Control Plane cloud account for AWS, follow the Create a Cloud Account guide. Set backup.aws.cloudAccountName to its name.
  3. Create an IAM policy with the following JSON, replacing YOUR_BUCKET_NAME, and set backup.aws.policyName to its name. The template attaches this policy to the identity, so the bucket in it is the only storage the nodes can reach:
  1. Set backup.aws.prefix to the folder path for the backup collection, then set backup.enabled: true, backup.provider: aws and backup.location.
2

GCS

  1. Create a GCS bucket. Set backup.gcp.bucket to its name.
  2. If you do not have a Control Plane cloud account for GCP, follow the Create a Cloud Account guide. Set backup.gcp.cloudAccountName to its name.
  3. Add the Storage Admin role to the GCP service account associated with the cloud account. The template additionally binds the identity to roles/storage.objectAdmin on exactly the bucket in backup.gcp.bucket.
  4. Set backup.gcp.prefix to the folder path for the backup collection, then set backup.enabled: true, backup.provider: gcp and backup.location.
Check a run with the cron workload’s container logs; a successful run ends with Backup complete.:
To list what the collection holds, ask the cluster itself from a node (swap the URI for the GCS form when backup.provider is gcp):
Switch backup.provider with a fresh install, not an upgrade. An identity’s cloud binding is merged rather than replaced when the identity is updated, so a release switched from aws to gcp keeps the old provider’s binding on RELEASE_NAME-cockroach-identity even though the chart no longer renders it.

Restoring a Backup

The backup is a full-cluster backup collection, and which RESTORE statement you use depends on what you are restoring into — getting this wrong is the common failure. Both statements below run from a node, because the nodes hold the cloud credentials; the URIs are the same ones the backup wrote to (gs://BUCKET_NAME/PREFIX?AUTH=implicit on GCS).
These statements match how the backup job writes its collection, the cloud access the chart grants the nodes, and CockroachDB’s documented RESTORE syntax, but they have not been rehearsed against a live install of this template version. Rehearse on a throwaway release before you depend on them.
Into the cluster you already have — restore the database under a new name. A full-cluster restore cannot be used here: CockroachDB refuses one on any cluster that already has user databases, and this template creates mydb and myuser on first deploy.
Then move your application to mydb_restored, or drop mydb and rename. Drop WITH new_db_name only if you have already dropped mydb. Into an empty cluster — a full-cluster restore, which also brings back users and cluster settings. It requires the target to have no user databases at all, so drop the ones this template created first:
Running the second statement without the first fails with full cluster restore can only be run on a cluster with no tables or databases. Follow progress with SHOW JOBS the same way, and verify afterwards with SHOW DATABASES.

Upgrading from 1.x

Template versions through 1.5.0 created their own GVC, so that GVC is part of a 1.x release’s manifest. Version 2.0.0 does not declare a GVC — and Helm deletes what a chart stops declaring.
Never cpln helm upgrade a 1.x release onto 2.0.0. The upgrade would delete the GVC the 1.x release created and every workload, volume set and identity inside it — including your data — while reporting success. The only supported path is a new release against an existing GVC, a restore of the data, and removal of the old release.The chart refuses to render when your values still carry the 1.x gvc key, so an upgrade that passes your old values file stops before any API call is made:
The guard cannot cover an upgrade run with no values file at all. A 1.x release installed on pure defaults has no gvc key for the chart to see, so nothing fires. Do not run an upgrade of a 1.x release against the 2.0.0 chart under any circumstances.
1

Back up the old cluster

Enable backup on the 1.x release, or issue a BACKUP INTO by hand against one of its nodes. See Backing Up for the bucket and cloud account setup.
2

Choose the GVC for the new release

Create or pick a GVC that has every location you intend to list in locations. See Prerequisites.
3

Install 2.0.0 as a NEW release into that GVC

Use a different release name: secret names are org-wide, so a same-named release collides with the 1.x one even in another GVC. Follow Installation.
4

Restore and cut over

Restore into the new cluster with the matching path under Restoring a Backup, then point your applications at the new PgBouncer endpoint.
5

Uninstall the old release against the GVC you installed it into

Not the GVC it created — the GVC you passed at install time is where Helm tracks the release, and uninstalling from there takes the created GVC with it:
Values keys that changed in 2.0.0, for the new release’s values file:

Scaling and Availability

  • Node loss. With three nodes in a location (the default), CockroachDB’s replication factor of 3 keeps every range available through the loss of one node. Scale a location by raising locations[].replicas and upgrading; new nodes join the cluster on their own.
  • Location loss needs three or more locations. With three or more entries in locations, the first deploy registers every location as a CockroachDB region and sets the survival goal of database.name to SURVIVE REGION FAILURE, so the cluster tolerates the loss of an entire location. With one or two locations that step is skipped — no CockroachDB setting can make a one- or two-location cluster survive a region loss. Verify what your cluster actually has:
    If the region setup did not complete, the start log of the first node says so explicitly (ERROR: Multi-region configuration is INCOMPLETE) and prints SHOW REGIONS FROM CLUSTER; see Troubleshooting.
  • Rolling restarts during an outage are not covered. A cluster that is already missing a location is at its fault-tolerance limit; rolling out or restarting nodes in the remaining locations during that outage causes a brief period of unavailability for ranges on those nodes. Wait for the lost location to return before upgrading.
  • Your application must retry. PgBouncer routes around failed nodes, but transient errors still reach the client during failover events — a location outage or a rolling restart — while PgBouncer cycles through backends and leader elections complete. Without retries those errors propagate to your users.
  • Removing a location from locations does not drain its nodes. They refuse to start rather than rejoining from a region the database was not told about. Decommission the nodes in that location first if they hold data.
  • PgBouncer scales on its own between pgbouncer.minReplicas and pgbouncer.maxReplicas in each location; raise maxReplicas when the pooler, not the database, becomes the bottleneck.
  • Data survives restarts and upgrades, not an uninstall: cpln helm uninstall removes the volume set with the release, taking a final snapshot retained for 7 days. Take a backup first if the data matters.

Troubleshooting

Symptom: the install succeeded but the CockroachDB workload never becomes ready, and cpln logs for it shows:
Cause: locations names a location the GVC does not have. The platform accepts this silently; the nodes catch it at boot and refuse to initialize rather than forming a cluster whose regions can never exist.Fix: add the missing location to the GVC, or remove it from locations and upgrade. See Prerequisites.
Symptom: a replica in a location you did not list exits immediately with that message.Cause: the platform placed a replica in a location this release does not declare. The node refuses to join from a region the database was never told about rather than holding replicas outside the survival goal.Fix: remove that location from the GVC, or add it to locations with a replica count and upgrade.
Symptom: cpln helm install or cpln helm upgrade exits before anything is applied with an execution error at (cockroach/templates/identity.yaml ...) message, and the existing release is untouched.Cause: the chart validates the values at render time. The message names the problem exactly — a leftover 1.x gvc key, an empty or duplicated locations entry, replicas: 0, a single node in total, a backup.location that is not one of locations, a backup.provider other than aws or gcp, a missing backup field, or the renamed pgbouncer.resources.cpu / memory.Fix: change the values as the message says and run the command again. For the gvc key, do not work around it — see Upgrading from 1.x.
Symptom: after setting multiZone: true the workload never reaches ready, no container starts, and cpln logs returns no lines.Cause: a location in the GVC does not support multi-zone placement for this workload. The setting is accepted and the deployment wedges without a log line.Fix: read status.versions[].message from cpln workload get-deployments RELEASE_NAME-cockroach --gvc GVC_NAME -o yaml, set multiZone: false and upgrade.
Symptom: on a release with three or more locations, the first node’s log shows ERROR: Multi-region configuration is INCOMPLETE. The database is serving, but it cannot survive the loss of a region. followed by the output of SHOW REGIONS FROM CLUSTER.Cause: one or more locations in locations had no nodes running when the regions were added — typically because the location is missing from the GVC, or its nodes had not joined yet.Fix: confirm every location in locations exists in the GVC and has nodes listed by cockroach node status, then run the ALTER DATABASE mydb ADD REGION "LOCATION" and ALTER DATABASE mydb SURVIVE REGION FAILURE statements by hand from a node, and verify with SHOW SURVIVAL GOAL FROM DATABASE mydb.
Symptom: a bare RESTORE FROM LATEST IN ... fails with that error.Cause: the backup is a full-cluster backup, and CockroachDB refuses to restore one onto a cluster that already has user databases — which this template always creates on first deploy.Fix: either restore the database under a new name with RESTORE DATABASE mydb ... WITH new_db_name, or drop mydb and myuser first. Both paths are under Restoring a Backup.
Symptom: after changing internal_access or pgbouncer.internal_access, previously allowed clients keep connecting, or newly allowed ones are still refused.Cause: firewall changes take up to a few minutes to propagate.Fix: wait and re-test for several minutes before concluding the knob did not work.

Important Notes

  • Every location in locations must already exist in the GVC. A missing one is accepted at install and refused by the nodes at boot; a GVC location you did not list runs nothing.
  • Never helm upgrade a 1.x release onto 2.0.0. It deletes the GVC the 1.x release created and everything in it. Install a new release and move the data — see Upgrading from 1.x.
  • Surviving a region loss needs at least three locations. The default single location survives a node failure, not a location failure.
  • The cluster runs in insecure mode. There are no SQL credentials; internal_access, pgbouncer.internal_access and the GVC boundary are the only access control.
  • Confirm multi-zone support in every GVC location before setting multiZone: true. An unsupported location wedges the deployment with no log output.
  • Use at least 3 replicas in total. A one-node deployment is refused at render; replicas: 0 on a location is refused too — remove the location instead.
  • Removing a location does not drain its nodes. Decommission them first if they hold data.
  • Backups are full-cluster backups. Restoring into a live cluster must use RESTORE DATABASE mydb ... WITH new_db_name, never a bare RESTORE FROM LATEST IN — see Restoring a Backup.
  • backup.location must be one of locations. The cron runs only there; anywhere else it is suspended.
  • Your application must retry transient errors. Failover events surface them through PgBouncer.
  • Access-knob changes take up to a few minutes to apply. Re-test before concluding a change did not work.
  • cpln helm uninstall deletes the volume set and with it the data, after a final snapshot retained 7 days. Back up first.

External References

CockroachDB Documentation

Official CockroachDB documentation

Multi-Region Survival Goals

What SURVIVE REGION FAILURE guarantees and requires

RESTORE

The RESTORE statement reference, including new_db_name and full-cluster restores

Backup Image Source

Source code for the CockroachDB backup container image

CockroachDB Template

View the source files, default values, and chart definition