Overview
TiDB is a distributed, MySQL-compatible database designed for horizontal scalability and high availability. It separates compute from storage across three components: a SQL processing layer (TiDB Server), a distributed key-value store (TiKV), and a placement driver (PD) that manages cluster metadata and scheduling. This template deploys a TiDB cluster across one or more Control Plane locations using PingCAP’s official images, with optional scheduled backups to S3 or GCS. Database credentials are not template values. The init job and TiDB Server read the root password, application user, password and database name from a dictionary secret you create before installing, so none of them pass through Helm or land in the release.What Gets Created
- Stateful PD Workload — (
RELEASE_NAME-pd): the placement driver quorum,pdReplicasmembers spread evenly across your locations. UsesreplicaDirectaddressing so each PD member is individually reachable. - Stateful TiKV Workload — (
RELEASE_NAME-tikv): distributed storage nodes. Replica count per location is controlled bylocations[].replicas. - Standard TiDB Server Workload — (
RELEASE_NAME-server): MySQL-compatible SQL layer on port4000. Per-location replica count followslocations[].replicas. - DB Init Cron Workload (optional, on by default) — (
RELEASE_NAME-tidb-db-init): a scheduled job that sets the root password and creates the application database and user, then fast-exits on every later run. - Backup Cron Workload (optional) — A scheduled job that uses TiDB’s
brtool to write a full cluster snapshot to AWS S3 or GCS, unsuspended in exactly one location. - Volume Set — PD storage (
RELEASE_NAME-tidb-pd-vs):volumeset.pd.capacityGiB with no autoscaling, ext4, general-purpose SSD, with 7-day snapshot retention. - Volume Set — TiKV storage (
RELEASE_NAME-tidb-tikv-vs): configurable capacity with optional autoscaling, ext4, general-purpose SSD, with 7-day snapshot retention. - Secrets — Opaque secrets containing startup scripts for PD, TiKV, TiDB Server, and the database init job. No credential secret — the passwords live only in the prerequisite secret you create.
- Identity & Two Policies — A shared identity bound to all workloads, with
revealon the template’s own secrets plus exactly the credentials secret you created,viewon the one GVC you install into so PD can confirm at boot that the GVC really has every location you listed, and cloud storage access when backup is enabled.
This template does not create a GVC. It deploys into a GVC you already have — every resource lands in the GVC you install into, so
cpln workload exec, cpln logs and uninstalling all work against that GVC, and uninstalling can never delete it. Every location you list in locations must already be on that GVC, and a GVC location you did not list simply runs nothing.Prerequisites
Two things must be in place before you install: a GVC with the right locations, and a credentials secret.A GVC with your locations
A GVC must already exist, and it must contain every location you list inlocations. The requirement is one-directional — the GVC may have more locations than you list, and nothing TiDB-related runs in those. Check what a GVC has before installing:
spec.staticPlacement.locationLinks. To add a missing one:
Database credentials
One secret must exist before you install, whenautoCreateDatabase.enabled is true (the default). It holds the credentials your applications put in their connection strings, plus the cluster’s root password. The values never pass through Helm, so they do not land in the release. Secrets are org-level, so no GVC flag is involved.
1
Create the database credentials secret
A dictionary secret holding exactly four keys — Set
rootPassword, user, password and db. The init job sets the root password, then creates that user and that database:autoCreateDatabase.credentialsSecretName to the name you used. Secret names are org-wide, so give each release its own.2
Read the secret back later
Pass
-o yaml. A bare cpln secret reveal prints only a summary table, not the values:Installation
Create the prerequisite secret first, then install by whichever method you prefer: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
Migrating from 1.x
Template versions through 1.8.1 created their own GVC, so that GVC is part of the 1.x release’s manifest. Version 2.0.0 does not declare it — and Helm deletes what a chart stops declaring.1
Recover the credentials the existing cluster uses
Versions up to 1.7.0 took the credentials as plain Helm values and wrote them into a chart-owned secret named after the release. Read them out of your current values file, or out of that secret:Pass
-o yaml. A bare cpln secret reveal prints only a summary table, not the values. Any password that came from a pre-1.8.0 default was published in the public template repository — treat it as compromised and choose a new one for the new cluster.2
Back up the old cluster
Enable
backup on the 1.x release, or run br backup full by hand against the old PD endpoint.3
Choose the GVC for the new release
Create or pick a GVC and make sure it has exactly the locations you intend to list in
locations. See Prerequisites.4
Create the credentials secret and install 2.0.0 as a NEW release
Follow Database credentials, then install into that GVC with a different release name — secret names are org-wide, so a same-named release collides with the 1.x one even in another GVC.
5
Restore and cut over
Restore into the new cluster (see Restoring a Backup), then point your applications at the new
RELEASE_NAME-server endpoint.6
Uninstall the old release against the GVC you installed it into
Not the
tidb-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.gvc.locationsis now the top-levellocations,gvc.pdReplicasis now the top-levelpdReplicas, andgvc.nameis gone entirely.devModeis gone. It only waived a three-location requirement that no longer exists —locationsmay hold a single location, and PD’s replication factor is now derived from the number of TiKV nodes you configure rather than mode-switched.exposeServeris gone. It never published the MySQL port: opening public inbound does nothing for port 4000 without a direct load balancer the chart does not render, so the only thing the canonical endpoint would have served was TiDB’s unauthenticated status API on port 10080. Reach the server over internal GVC DNS orcpln port-forwardinstead.replicas: 0on a location is refused. 1.x turned it into a suspended location, and suspending a location permanently withdraws that workload’s endpoints from other locations’ service discovery. Remove the location fromlocationsinstead.
The guards fire on the mere presence of the removed keys, so
exposeServer: false and devMode: false fail too. Anyone carrying a 1.x values file forward will hit an error naming the key and its replacement, rather than a silent misconfiguration.Configuration
The defaultvalues.yaml for this template:
Locations
locations— List of Control Plane locations. Every one must already exist in the GVC you install into.locations[].replicas— Number of TiKV and TiDB Server replicas in that location. Must be at least 1;0is refused at render.pdReplicas— Total number of PD members across all locations, spread evenly with any remainder going to the first ones. PD is Raft-based, so it must be1,3,5or7. A value of1is a single point of failure and is for testing only.
GVC locations you did not list show as red in the console, with
This workload location is deactivated because maxScale is set to 0. That is the mechanism that keeps a shared GVC safe — it is what a healthy install looks like, not a fault.Images and Resources
images.server/images.tikv/images.pd— Container images for each tier. Bump these together withbackup.image: from v8.5.7,brenforces a version match with the cluster.resources.pd.cpu/resources.pd.memory— CPU and memory per PD member.resources.server.cpu/resources.server.memory— CPU and memory per TiDB Server replica.resources.tikv.cpu/resources.tikv.memory— CPU and memory per TiKV replica.
Database Initialization
autoCreateDatabase.enabled— Wires the credentials secret into the TiDB Server and init workload, and grants the identityrevealon it.autoCreateDatabase.deployInitWorkload— Deploys the init job that sets the root password and creates the application database and user.autoCreateDatabase.credentialsSecretName— Name of the dictionary secret holdingrootPassword,user,passwordanddb. See Database credentials.autoCreateDatabase.schedule— How often the init job runs.
schedule really only controls how soon after install the database appears. With the default */5 * * * *, a measured install had the database created 61 seconds after helm install finished, well ahead of the five-minute worst case.
Set
autoCreateDatabase.deployInitWorkload: false and upgrade if you would rather remove the job entirely once the cluster is initialized. It is cheap to leave on; the trade is a workload that runs forever for a one-time purpose.Credentials are applied on first initialization only. Changing the secret afterwards does not change the cluster — it only changes what clients present when they authenticate. To rotate on an existing cluster, run
ALTER USER inside TiDB first, then update the secret, then force a redeployment: a cpln:// reference is resolved when a replica starts and is never re-resolved while it runs.Storage
TiKV storage (configurable):volumeset.tikv.capacity— Initial volume size in GiB (minimum 10).volumeset.tikv.autoscaling.enabled— Automatically expand volumes as they fill. When enabled:maxCapacity— Maximum volume size in GiB.minFreePercentage— Trigger a scale-up when free space drops below this percentage.scalingFactor— Multiply current capacity by this factor when scaling up.
volumeset.pd.capacity— Initial volume size in GiB for PD metadata (minimum 10). PD only holds cluster metadata, so it has no autoscaling knob.
Access
Internal access — configured per component (server, tikv, pd):
List only your clients. Every workload this release creates is always allowed, whatever you set — the three tiers have to reach each other, and each tier’s own replicas have to reach each other, so a
workload-list naming only your applications would otherwise cut the cluster off from itself. Before 2.0.0 the workloads list never reached the stored spec at all, so workload-list blocked everything.external_access.server_outboundAllowCIDR/tikv_outboundAllowCIDR/pd_outboundAllowCIDR— Outbound CIDR allowlists for each component, for reaching external services. Whenbackup.enabledistrue, TiKV outbound access is automatically set to0.0.0.0/0so nodes can upload directly to cloud storage, regardless oftikv_outboundAllowCIDR.
exposeServer was removed in 2.0.0 because it never published the MySQL port. Reach the server over internal GVC DNS, or forward the port:
cpln port-forward is a top-level command, not a cpln workload subcommand, and it works against a workload with no public inbound at all.
Connecting to TiDB
TiDB Server is MySQL-compatible. Connect using any MySQL client from a workload in the same GVC:.GVC_NAME.cpln.local form. The bare workload name is not reliable on this platform — whether it resolves depends on the workload type.
The pingcap/tidb image ships no MySQL client, so run the command from another workload in the same GVC — a throwaway mysql:8 workload works. Depending on how many replicas and locations you configured, the cluster can take a few minutes to accept connections.
Ports
Backup
Backup is disabled by default. When enabled, a cron workload uses TiDB’sbr tool to take a full cluster snapshot on the configured schedule and upload it to AWS S3 or GCS.
backup.enabled— Enable scheduled backups.backup.image— The backup image. Its version must match the cluster: from v8.5.7,brenforces the check even with--check-requirements=false, so bump this together withimages.*.backup.schedule— Cron expression for backup frequency (default: daily at 2am UTC).backup.provider—awsorgcp.backup.location— The Control Plane location where the backup job runs. It must be one of yourlocations, and the chart refuses to render otherwise: the cron is suspended everywhere else, so a mismatch would mean the backup never ran anywhere with no failed run to observe. Set it to the location nearest your bucket to minimize transfer cost and latency.backup.activeDeadlineSeconds— Maximum time allowed per backup job in seconds (default:14400/ 4 hours).backup.resources.cpu/backup.resources.memory— Resources for the backup cron container.
When
backup.enabled is true, the template automatically grants TiKV outbound access to 0.0.0.0/0 so nodes can upload data directly to cloud storage. This overrides external_access.tikv_outboundAllowCIDR.AWS S3
Before enabling backup withprovider: aws, complete the following in your AWS account:
- Create an S3 bucket. Set
backup.aws.bucketto its name andbackup.aws.regionto its region. - If you do not have a Cloud Account set up, refer to the docs to Create a Cloud Account. Set
backup.aws.cloudAccountNameto its name. - Create an IAM policy with the following JSON, replacing
YOUR_BUCKET_NAME:
- Set
backup.aws.policyNameto the name of the policy created in step 3. - Set
backup.aws.prefixto the folder path where backups will be stored.
GCS
Before enabling backup withprovider: gcp, complete the following in your GCP account:
- Create a GCS bucket. Set
backup.gcp.bucketto its name. - If you do not have a Cloud Account set up, refer to the docs to Create a Cloud Account. Set
backup.gcp.cloudAccountNameto its name. - Grant the Cloud Account’s service account the Storage Admin (
roles/storage.admin) role on that bucket. The chart also bindsroles/storage.objectAdminto the workload identity. - Set
backup.gcp.prefixto the folder path where backups will be stored.
Switch providers with a fresh install, not an upgrade. An identity’s cloud binding is never removed once set — the API merges rather than replaces — so a release switched from
aws to gcp keeps the old provider’s binding attached even though the chart no longer renders it.Restoring a Backup
Backups land atBUCKET/PREFIX/tidb-TIMESTAMP/. Restore with br restore full, run from a workload inside the GVC — *.cpln.local names do not resolve from anywhere else, and the ghcr.io/controlplane-com/backup-images/tidb-backup image is the one that carries a matching br.
AWS S3:
The
br binary version must match your TiDB cluster version. Download it from the TiDB Community Toolkit.Important Notes
- Never upgrade a 1.x release onto 2.0.0 in place — it deletes the GVC the 1.x chart created and everything in it. Install a new release: Migrating from 1.x.
- The GVC must contain every location you list, and may contain more. A missing location is not caught at install: PD exits with
FATAL: locations declared in values are not in GVC .... A PD member that already holds data logs aWARNINGinstead and keeps serving. - PD’s replication factor is fixed when the cluster first bootstraps. It is the number of TiKV nodes you configure, capped at 3, and PD persists it — scaling TiKV up later does not raise it. Start with at least 3 TiKV nodes if you ever want 3-way replication.
- There is no public access to the MySQL port. Reach the server over internal GVC DNS or with
cpln port-forward. - Release names must be unique per org — secrets are org-wide, so two releases with the same name collide even in different GVCs.
- Credentials apply on first initialization only. Rotate with
ALTER USERinside TiDB first, then update the secret, then force a redeployment.
External References
TiDB Documentation
Official TiDB documentation
TiDB Architecture
How PD, TiKV and TiDB Server fit together
TiDB Community Toolkit
Download
br and other TiDB ecosystem toolsBackup and Restore
The BR backup and restore overview
Backup Image Source
Source code for the TiDB backup container image
TiDB Template
View the source files, default values, and chart definition