Overview
PgDog is a PostgreSQL connection pooler, load balancer and query router written in Rust. It speaks the PostgreSQL wire protocol on port6432, so applications change only their connection string: PgDog multiplexes many client connections onto a small pool of real backend connections, sends writes to a primary backend and spreads SELECT queries across replica backends.
This template deploys the proxy only — it does not run PostgreSQL. Point it at an existing PostgreSQL or PostgreSQL Highly Available install, or at any external PostgreSQL endpoint. Every credential comes from a secret you create before installing, so no password passes through Helm values.
What Gets Created
pgdog.toml; your secrets are injected into the container as environment variables, and the startup script writes the [admin] table and users.toml from them each time the container starts. The template creates no secret that contains a credential, and uninstalling never deletes yours.
Prerequisites
Both kinds of secret must exist before you install. Secrets are org-level, so no GVC flag is involved. A PostgreSQL backend must also be running, with the role and database your pooled users will connect as.Create one credentials secret per pooled user
username and password. PgDog checks client logins against this pair and opens its backend connections with it, so it must be a real PostgreSQL role on the backend:username and password keys, and PgDog ignores its extra database key.Set users[0].credentialsSecretName to this name.Create the admin password secret
plain, whose payload is the password for PgDog’s admin database. It is deliberately separate from the pooled-user secrets, so an application that can read its own credentials cannot also reach the admin database:printf, not echo — echo adds a trailing newline, and the startup script refuses to start with a password that contains one.Set admin.passwordSecretName to this name.Read a secret back when you need it
-o yaml is required — a bare cpln secret reveal prints only a summary table:Installation
Install with your backend, one pooled user and the admin secret.databases and users are lists, and setting one field of a list entry with --set replaces the whole list, so set every field of each entry:
DATABASE must be a real database on the backend, and users[0].database must match a databases[].name. With the PostgreSQL template, POSTGRES_WORKLOAD_NAME is that release’s RELEASE_NAME-postgres workload.
To install using another method, follow the instructions for it:
UI
CLI
Terraform
Pulumi
Configuration
Image and Resources
The PgDog image, the CPU and memory reservation (minCpu, minMemory) and limit (maxCpu, maxMemory), and the number of proxy replicas:
replicas.
Backend Databases
Each entry becomes a[[databases]] block in pgdog.toml. Entries that share a name form one cluster: PgDog sends writes to the primary entry and reads to the replica entries.
WORKLOAD_NAME.GVC_NAME.cpln.local — a bare workload name does not resolve for every workload type.
Pooled Users
Each entry becomes a[[users]] block in users.toml. The username and password come from the dictionary secret named by credentialsSecretName; only the routing target is a value:
username and password pair:
reveal target to the policy for each secret automatically. Two entries may name the same secret, which routes one role to two databases.
Connection Pooling
Timeouts
All values are in milliseconds:Load Balancing
How reads are spread acrossreplica backends. With readWriteSplit: include_primary the primary also serves reads:
Admin Database
PgDog’s built-in admin database for pool statistics and introspection. The database and user names are values; the password comes from the opaque secret you created:Authentication and Logging
Access
Internal access controls which workloads may reach the proxy. Public access opens a TCP load balancer on port6432 to the internet:
type: workload-list, list each allowed caller in workloads as //gvc/GVC_NAME/workload/WORKLOAD_NAME. A change to either access setting can take several minutes to take effect; re-test with a real PostgreSQL client before concluding it did not apply.
Connecting
Applications connect exactly as they would to PostgreSQL, on port6432. The username and password are those in the pooled user’s credentials secret (cpln secret reveal SECRET_NAME -o yaml).
admin.user and run SHOW POOLS or SHOW CLIENTS to inspect the pools.
Operations
Rotating Credentials
PgDog builds its config files once, when the container starts, so changing a secret has no effect until the workload is redeployed. Because a pooled user’s pair is also PgDog’s backend login, change the role’s password in PostgreSQL first, then update the secret by applying it whole:type: opaque and data holding encoding: plain and payload: NEW-VALUE. Then redeploy so PgDog picks up the new values:
Upgrading From 1.0.0
Version 1.0.0 took the pooled-user and admin passwords as Helm values, with working defaults published in the public template repository. Version 1.1.0 moves every credential into secrets you create and renames the resource limits:Create the secrets
Update your values
users[].name, users[].password and admin.password. Set users[].credentialsSecretName and admin.passwordSecretName, and rename resources.cpu and resources.memory to resources.maxCpu and resources.maxMemory if you had overridden them.Run the upgrade
databases and users entry:Scaling and Availability
PgDog is stateless and holds no data, so a restart or reschedule only drops open client connections; give applications a reconnect policy. The default is one replica, and every upgrade replaces it. To run more proxies, raisereplicas. Each replica keeps its own pool, so the backend sees up to replicas × pooling.defaultPoolSize connections per pool — lower defaultPoolSize accordingly and keep the total under the backend’s max_connections. The template ships with a single replica; running several has not been verified.
Troubleshooting
Workload never becomes ready and cpln logs returns nothing
Workload never becomes ready and cpln logs returns nothing
cpln logs prints zero lines.Cause: a secret named by admin.passwordSecretName or a users[].credentialsSecretName does not exist, so the container never starts.Fix: read the deployment message — it is the only place the missing secret is named:The secret <name> no longer exists. Workload updates are paused until the secret is added or the reference to the secret removed. under status.versions[].message. Create that secret (Prerequisites); the workload recovers on its own after several minutes, or force a redeployment to skip the wait.Container exits at start with a FATAL message
Container exits at start with a FATAL message
cpln logs shows a line beginning FATAL:.Cause: a secret exists but a value in it is unusable. FATAL: ... is missing or empty names the secret and key that is empty or absent (a credentials secret needs both username and password). FATAL: ... contains a newline means the value has a trailing newline, usually from creating it with echo.Fix: recreate or re-apply the named secret with the right keys, using printf '%s' rather than echo for an opaque value (Rotating Credentials), then force a redeployment.Clients get could not translate host name
Clients get could not translate host name
could not translate host name "RELEASE_NAME-pgdog" to address.Cause: the bare workload name does not resolve for PgDog’s workload type.Fix: use the fully qualified host RELEASE_NAME-pgdog.GVC_NAME.cpln.local. Apply the same rule to every databases[].host that points at a workload in the GVC.Logins through PgDog are rejected
Logins through PgDog are rejected
6432 but authentication fails, or PgDog cannot open backend connections.Cause: PgDog uses the pooled user’s username and password for the backend connection too, so the pair must be a real role on the backend with access to the target database. A password changed in PostgreSQL but not in the secret — or changed in the secret without a redeployment — produces the same failure.Fix: compare cpln secret reveal SECRET_NAME -o yaml with the role on the backend, make them match, then force a redeployment.Install or upgrade fails at render
Install or upgrade fails at render
cpln helm install or cpln helm upgrade exits before touching any resource with a message such as users[0].database is "...", which is not a name in .Values.databases or At least one entry is required in .Values.databases.Cause: a users[].database does not match any databases[].name, or a list was replaced by a partial --set (setting one field of a list entry drops the others), or a 1.0.0 key is still set (Upgrading From 1.0.0).Fix: pass every field of each databases and users entry, make each users[].database match a databases[].name, and remove the old keys.Important Notes
- Create every pooled-user credentials secret and the admin password secret before you install; a missing one wedges the workload with no log output.
- PgDog is a proxy only — the PostgreSQL backend, its roles and its databases must already exist.
- Clients connect on port
6432, not5432, using the fully qualifiedRELEASE_NAME-pgdog.GVC_NAME.cpln.local. - Each pooled user’s credentials are also PgDog’s backend login, so they must match a real PostgreSQL role.
- A changed secret takes effect only after
cpln workload force-redeployment. - In
transactionmode, session state (SETvariables, temporary tables, advisory locks) is not kept between transactions; usesessionif your application depends on it. - On 1.0.0, treat the published default passwords as compromised and choose new ones when you upgrade.