Skip to main content
Version 1.2.0 moves the MinIO backup credentials out of values. They were plain values that landed in your Helm release. They are now a dictionary secret you create before installing, holding accessKey and secretKey. Only affects installs backing up to MinIO.

Overview

TimescaleDB is a time-series database built as a PostgreSQL extension. This template deploys a single-instance PostgreSQL 18 server with the TimescaleDB Community extension preloaded and auto-created, giving you hypertables, columnar compression, continuous aggregates, and retention policies alongside regular relational tables — all through any PostgreSQL client or ORM. Optional PgBouncer connection pooling and scheduled backups to AWS S3, GCS, or a self-hosted MinIO instance are included. Database credentials are not template values. TimescaleDB reads its username, password and database name from a dictionary secret you create before installing, so no password passes through Helm or lands in the release.
Template version 1.1.0 is a breaking security change. config.username and config.password were removed, and an install or upgrade that still sets either one now fails at render instead of silently falling back to a published default password. If you are running 1.0.0, read Upgrading From 1.0.0 or Earlier before you touch the release.
TimescaleDB is licensed under the Timescale License (TSL). It is free to self-host, including all Community features (compression, continuous aggregates, retention); the license only forbids reselling TimescaleDB itself as a managed database service.
TimescaleDB on Control Plane operates as a single-instance deployment, pinned to one replica. Do not scale up the replica count — PostgreSQL is a single-writer database, and additional replicas would run as isolated instances rather than a cluster.

What Gets Created

  • Stateful TimescaleDB Workload — A single-replica PostgreSQL 18 + TimescaleDB 2.28.3 container on port 5432. The extension is preloaded, created automatically in your database, and auto-tuned to the container’s resources at first boot.
  • Volume Set — Persistent storage for the database data directory, with optional autoscaling and 7-day snapshots.
  • Backup Config Secret (optional) — A dictionary secret holding the backup destination. Created only when backup.enabled: true, and it holds no database credentials.
  • Identity & Policy — An identity bound to the TimescaleDB, PgBouncer and backup workloads, and a policy granting it reveal on exactly the credentials secret you created — plus the backup config secret and Cloud Account binding when backup is enabled.
  • PgBouncer Workload (optional) — A PgBouncer connection pooler deployed as a separate workload in front of TimescaleDB.
  • Backup Cron Workload (optional) — A scheduled pg_dumpall backup job that writes compressed SQL dumps to AWS S3, GCS, or MinIO.
The template creates no credential secret of its own. The username, password and database name live only in the prerequisite secret described below.
This template does not create a GVC. You must deploy it into an existing GVC.

Upgrading From 1.0.0 or Earlier

Template versions up to 1.0.0 took the database credentials as plain Helm values, shipped working defaults for them, and wrote those credentials into a chart-owned secret named after the release. Version 1.1.0 removes all of that.
Carrying the old values forward stops the upgrade. The removed keys are rejected at render, so cpln helm upgrade fails and your existing release is left untouched and running, rather than quietly restarting against a different password:
1

Read the credentials the database already uses

Credentials are written into the data directory the first time the volume is initialized, so an existing database keeps whatever it was created with. Recover them from your current values file, or from the secret the old version created — do this before upgrading:
Pass -o yaml. A bare cpln secret reveal prints only a summary table, not the values.
2

Create the prerequisite secret with those same values

Follow Prerequisites, using the existing username, password and database name. Different values here do not change the database — they just leave the workload unable to authenticate.
3

Remove the old keys from your values

Delete config.username, config.password and config.database, and set config.credentialsSecretName to your secret’s name.
4

Upgrade, then rotate the password

After the upgrade succeeds, change any password that came from a 1.0.0 default — those defaults were published in the public template repository, so treat them as compromised. Rotate inside TimescaleDB, then update the secret to match:
RELEASE_NAME-tsdb-config no longer holds credentials. It is now created only when backup.enabled: true, and holds nothing but the backup destination. Anything outside this release that read the username or password from it by name — another workload’s environment, a policy, or a parent chart bundling TimescaleDB as a subchart — must be pointed at the secret you create instead. A reference to a key that no longer exists does not fail loudly; it wedges the referring workload silently.

Prerequisites

One secret must exist before you install. It holds the credentials your applications put in their connection strings. 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 three keys — username, password and database. TimescaleDB creates that role and that database on first boot, and creates the TimescaleDB extension inside that database:
Set config.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:
Create the secret before installing, or the deployment wedges silently. The template refuses to render when config.credentialsSecretName is blank, but a name pointing at a secret that does not exist installs “successfully” and then never starts. The container never runs, so cpln logs returns zero lines — there is nothing to log, and every summary surface just looks like a slow deploy. The one place the reason appears is status.versions[].message:
Use get-deployments — plain cpln workload get has no versions key and will show you nothing. Creating the missing secret repairs it on its own with no further action, in roughly 5.5 to 10.5 minutes measured across five templates, or run cpln workload force-redeployment RELEASE_NAME-timescaledb --gvc GVC_NAME to clear it in about 90 seconds.
Backups need a bucket, and for AWS or GCP a Control Plane Cloud Account, before they can be enabled — see Backup Prerequisites. Nothing else is required.

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

Configuration

The default values.yaml for this template:

Image and Resources

  • image — The TimescaleDB image tag. Keep it in the default (Community) series; -oss tags remove compression, continuous aggregates, and retention.
  • resources.minCpu / resources.minMemory — Minimum CPU and memory guaranteed to the workload.
  • resources.maxCpu / resources.maxMemory — Maximum CPU and memory the workload can use. timescaledb-tune sizes shared_buffers and worker settings from maxMemory at first boot (for example, shared_buffers becomes ~25% of the memory limit).
Auto-tuning is captured only at first boot, when the data volume is empty. Raising resources.maxMemory on an existing deployment does not retune PostgreSQL — adjust settings manually with ALTER SYSTEM, or uninstall (which deletes the volume set) and reinstall.

Credentials

  • config.credentialsSecretName — Name of the dictionary secret holding username, password and database. TimescaleDB creates that role and that database on first boot, and creates the TimescaleDB extension inside that database. These are the credentials your applications put in their connection strings.
The secret must exist before installing — see Prerequisites. The workload reads it through cpln://secret/... references, so the values appear in neither the Helm release nor the stored workload spec.
The credentials are applied only on first startup, when the data directory is empty. Changing the secret afterwards does not change the running database — it only changes what the workload presents when it authenticates, which will then fail. To rotate on an existing instance, run ALTER ROLE ... WITH PASSWORD inside PostgreSQL first, then update the secret to match.

Storage

  • volumeset.capacity — Initial volume size in GiB (minimum 10).
  • volumeset.autoscaling.enabled — Automatically expand the volume as it fills. When enabled:
    • maxCapacity — Maximum volume size in GiB.
    • minFreePercentage — Trigger a scale-up when free space drops below this percentage.
    • scalingFactor — Multiply the current capacity by this factor when scaling up.

Internal Access

  • internalAccess.type — Controls which workloads can connect to TimescaleDB on port 5432:
  • internalAccess.workloads — When type is workload-list, the list of workload links (e.g. //gvc/GVC_NAME/workload/WORKLOAD_NAME) allowed to connect.

Public Access

  • publicAccess.enabled — When true, exposes port 5432 through a TCP load balancer and assigns a public *.cpln.app canonical endpoint.
Public access is unencrypted — the image ships no TLS certificates, so connections over the public endpoint are plaintext. Keep publicAccess.enabled: false and use internal access unless you accept plaintext connections.

PgBouncer Connection Pooling

PgBouncer is an optional connection pooler that sits in front of TimescaleDB and multiplexes application connections into a smaller pool of real database connections. This reduces connection overhead and protects the database from exhaustion under high concurrency. When enabled, PgBouncer is deployed as a separate workload and becomes the primary connection endpoint for your applications:
  • pgbouncer.enabled — Enable or disable PgBouncer.
  • pgbouncer.poolMode — Controls how connections are reused:
  • pgbouncer.defaultPoolSize — Number of real database connections PgBouncer maintains per pool (default: 25).
  • pgbouncer.maxClientConn — Maximum number of client connections PgBouncer accepts (default: 1000).
  • pgbouncer.replicas — Number of PgBouncer instances. PgBouncer is stateless and can be scaled horizontally for high-throughput workloads.
  • pgbouncer.resources.cpu / pgbouncer.resources.memory — Resources allocated to each PgBouncer replica.
PgBouncer shares the same credentials and identity as the TimescaleDB workload — no additional secrets or IAM configuration is required. Its userlist.txt and pgbouncer.ini are generated at container start from the same credentials secret, so PgBouncer stays in step with the database automatically.

Backup

Backup is disabled by default. When enabled, a cron workload runs pg_dumpall on the configured schedule and uploads a compressed SQL dump to AWS S3, GCS, or a MinIO-compatible endpoint.
  • backup.enabled — Enable scheduled backups.
  • backup.image — The backup container image. Match its tag to the server major version — 18.1.0 for the default PostgreSQL 18 image, 17.1.0 for a PostgreSQL 17 image.
  • backup.schedule — Cron expression for backup frequency (default: daily at 2am UTC).
  • backup.provideraws, gcp, or minio.
  • backup.resources.cpu / backup.resources.memory — Resources for the backup cron container.
Complete the backup prerequisites for your provider before enabling backup.

Connecting

Using TimescaleDB

Any PostgreSQL client or ORM works unchanged. Turn a regular table into a hypertable (automatically partitioned by time) and query it with time buckets:
From here you can add columnar compression, continuous aggregates, and retention policies — all Community features included in the default image.

Backup Prerequisites

AWS S3

Before enabling backup with provider: aws, complete the following in your AWS account:
1

Create a bucket

Create an S3 bucket. Set backup.aws.bucket to its name and backup.aws.region to its region.
2

Set up a Cloud Account

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

Create an IAM policy

Create an IAM policy with the JSON below, replacing YOUR_BUCKET_NAME, then set backup.aws.policyName to the policy’s name and backup.aws.prefix to the folder path for backups.
Version 1.1.1 narrows AWS backup permissions. This version removes aws::ReadOnlyAccess from the backup identity. That AWS managed policy granted read access to every bucket in your AWS account and contains no write actions at all, so it was never carrying the backup itself — but it was silently supplying any read action your own bucket-scoped policy happened to omit.Update your IAM policy to the full action list below before upgrading. If it already matches, no action is needed. The identity now carries cpln-connector and your bucket-scoped policy only, which is strictly narrower than before. Nothing else changes.

GCS

Before enabling backup with provider: gcp, complete the following in your GCP account:
1

Create a bucket

Create a GCS bucket. Set backup.gcp.bucket to its name.
2

Set up a Cloud Account

If you do not have one, create a Cloud Account for your GCP project. Set backup.gcp.cloudAccountName to its name — access is keyless, with no stored credentials.
Grant the Storage Admin role (roles/storage.objectAdmin scoped to the bucket also works) to the GCP service account created for the Cloud Account. Set backup.gcp.prefix to the folder path for backups.

MinIO

Before enabling backup with provider: minio, ensure your MinIO instance (or any S3-compatible endpoint) is accessible:
1

Create a bucket

Create a bucket on the server. Set backup.minio.bucket to its name.
2

Set the endpoint

Set backup.minio.endpoint to the S3 API address including the port. For the minio marketplace template deployed in the same GVC, use http://WORKLOAD_NAME:9000.
3

Set credentials

Set backup.minio.accessKey and backup.minio.secretKey to credentials with access to the bucket. For the MinIO template, these match the admin.username and admin.password values. Set backup.minio.prefix to the folder path for backups.
MinIO backup requires no Control Plane Cloud Account — credentials are passed directly to the backup job.

Restoring a Backup

Restoring a TimescaleDB dump is not the vanilla PostgreSQL procedure. The target server must run the same TimescaleDB extension version as the dump, and the replay must be wrapped in timescaledb_pre_restore() and timescaledb_post_restore(). Run the following from a client with access to the backup bucket and to a fresh database:
Restore replays a full-cluster dump. Run it against a fresh instance, not a database that already holds data you want to keep.
AWS S3:
For GCS, replace the download with gsutil cp "gs://BUCKET_NAME/PREFIX/BACKUP_FILE.sql.gz" -. For MinIO, add --endpoint-url "http://MINIO_ENDPOINT:9000" to the aws s3 cp command and export the MinIO access and secret keys as AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY.

Important Notes

  • Create the credentials secret before installing. The deployment wedges silently without it, and cpln logs returns zero lines — see Prerequisites for the one command that names the missing secret.
  • Do not scale this workload. It is single-writer PostgreSQL, pinned to one replica. Additional replicas would run as isolated instances, not a cluster.
  • Auto-tuning is captured at first boot only. timescaledb-tune sizes memory settings from the container limit when the volume is empty; raising resources.maxMemory later does not retune.
  • Public access is unencrypted. The image ships no TLS certificates — keep publicAccess.enabled: false unless you accept plaintext connections.
  • Keep the image tag in the default (Community) series. -oss tags remove compression, continuous aggregates, and retention policies. If you pin a different pgXX server image, match backup.image to the same major (17.1.0 for PostgreSQL 17).
  • Uninstall deletes the volume set. A final snapshot is kept for 7 days; enable backups if the data matters long-term.

External References

TimescaleDB Documentation

Official TimescaleDB documentation

Hypertables

Hypertables, compression, continuous aggregates, and retention

PgBouncer Documentation

PgBouncer configuration reference

TimescaleDB Template

View the source files, default values, and chart definition