Production-ready Helm chart for PgDog with high availability, security, and resource management features.
✅ Resource limits with guaranteed QoS (1GB:1CPU ratio)
✅ PodDisruptionBudget for high availability
✅ Pod anti-affinity for spreading across nodes
✅ ExternalSecrets integration for secure credential management
✅ ServiceAccount and RBAC with minimal permissions
✅ Pinned image versions for production deployments
- Install Helm
- Configure
kubectlto point to your K8s cluster - Add our Helm repository:
helm repo add pgdogdev https://helm.pgdog.dev - Configure databases and users in
values.yaml - Install:
helm install <name> pgdogdev/pgdog -f values.yaml
All resources will be created in <name> namespace.
Configuration is done via values.yaml. All PgDog settings from
pgdog.toml and users.toml are supported. General settings
([general] section) are top level. Use camelCase format instead
of snake_case, for example: checkout_timeout becomes
checkoutTimeout.
workers: 2
defaultPoolSize: 15
openMetricsPort: 9090
logFormat: json
logLevel: infoBy default, the chart uses the appVersion from Chart.yaml as the image
tag. This ensures the chart deploys a known-compatible version of PgDog
without requiring explicit configuration.
To override with a specific version:
image:
repository: ghcr.io/pgdogdev/pgdog
tag: "v1.2.3" # Pin to specific version
pullPolicy: IfNotPresentTo pin to an exact build, use a digest instead of a tag:
image:
repository: ghcr.io/pgdogdev/pgdog
digest: "sha256:abc123def456..." # Immutable reference
pullPolicy: IfNotPresentWhen digest is specified, it takes precedence over tag.
Legacy format (still supported for backward compatibility):
image:
name: ghcr.io/pgdogdev/pgdog:main
pullPolicy: AlwaysAdd databases to databases list:
databases:
- name: "prod"
host: "10.0.0.1"Add users to users list:
users:
- name: "alice"
database: "prod"
password: "hunter2" # See ExternalSecrets for secure storageAdd mirrors to mirrors list. For example:
mirrors:
- sourceDb: "prod"
destinationDb: "staging"Ensures minimum pod availability during voluntary disruptions (enabled by default):
podDisruptionBudget:
enabled: true
minAvailable: 1 # At least 1 pod always availableSpreads pods across nodes for better reliability (enabled by default):
podAntiAffinity:
enabled: true
type: soft # "soft" (preferred) or "hard" (required)By default, ConfigMap changes are not automatically picked up by
running pods. Enable restartOnConfigChange to trigger a rolling
restart whenever the rendered config changes:
restartOnConfigChange: trueThis injects a checksum/config pod annotation that changes when the
config template output changes, causing Kubernetes to roll the pods.
Securely manage credentials using ExternalSecrets operator:
Option 1: Create ExternalSecret with chart
externalSecrets:
enabled: true
create: true
secretStoreRef:
name: aws-secrets-manager
kind: SecretStore
remoteRefs:
- secretKey: users.toml
remoteRef:
key: pgdog/usersOption 2: Use existing ExternalSecret
externalSecrets:
enabled: true
create: false
secretName: "my-secret" # Name of Secret you createdIf you manage Kubernetes Secrets yourself (via kubectl, sealed-secrets,
SOPS, etc.), point the chart at them directly instead of putting secret
values in values.yaml. This works without the ExternalSecrets operator.
Set usersSecret.name to reference a Secret you created that holds the
users.toml file. The chart then skips rendering its own users Secret and
mounts yours instead:
usersSecret:
name: my-pgdog-users # existing Secret in the same namespace
key: users.toml # key holding the users.toml content (default: users.toml)Create the Secret, for example:
kubectl create secret generic my-pgdog-users \
--from-file=users.toml=./users.tomlThe value is mounted at /etc/secrets/pgdog/users.toml regardless of the
key name. A custom key is remapped automatically.
PgDog reads the Datadog API key from the DD_API_KEY environment variable.
Reference an existing Secret and the chart injects it as DD_API_KEY, so the
key is never written into pgdog.toml (or the ConfigMap):
otel:
endpoint: https://otlp.example.com/v1/metrics # your OTLP endpoint
datadogApiKeySecret:
name: my-datadog # existing Secret in the same namespace
key: dd-api-key # key holding the API key (default: dd-api-key)Create the Secret, for example:
kubectl create secret generic my-datadog \
--from-literal=dd-api-key=<your-datadog-api-key>This is mutually exclusive with the inline otel.datadogApiKey, which writes
the key into the ConfigMap as plaintext and should be avoided.
If both are set, the inline value takes precedence.
RBAC with minimal permissions is enabled by default:
serviceAccount:
create: true
annotations: {}
rbac:
create: trueDefault resources use Guaranteed QoS with 1GB:1CPU ratio:
resources:
requests:
cpu: 1000m # 1 CPU
memory: 1Gi # 1GB
limits:
cpu: 1000m
memory: 1GiYou can set noCpuLimits: true to omit CPU limits. This allows containers to use idle CPU on the host.
noCpuLimits: true
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
memory: 512MiPrometheus metrics can be collected with a sidecar. Enable by
configuring prometheusPort:
prometheusPort: 9091
# Resources for Prometheus sidecar
prometheusResources:
requests:
cpu: 100m
memory: 100Mi
limits:
cpu: 100m
memory: 100MiMake sure it's different from openMetricsPort. You can configure
Prometheus in templates/prom/config.yaml.
To send metrics to Grafana Cloud or a Grafana instance, configure the remote write settings:
grafanaRemoteWrite:
url: "https://prometheus-prod-XX-XXX.grafana.net/api/prom/push"
basicAuth:
username: "123456" # Grafana Cloud user ID
password: "your-api-key" # Grafana Cloud API key
queueConfig:
capacity: 10000
maxShards: 50
minShards: 1
maxSamplesPerSend: 5000
batchSendDeadline: 5s
minBackoff: 30ms
maxBackoff: 5sThe queueConfig settings use Prometheus defaults and can be tuned
for performance. Remote write is automatically enabled when url is
set.
Add plugins to the plugins list. Each plugin requires a name; config is
optional and accepts inline TOML content. When config is provided, a
<name>.toml file is added to the ConfigMap and mounted at
/etc/pgdog/<name>.toml.
plugins:
- name: pgdog_routing
config: |
[routing]
key = "value"
- name: pgdog_authConfigure socket-level TCP keep-alive behavior (optional):
tcpKeepalive: true
tcpTime: 7200000 # 2 hours (ms) before first keepalive probe
tcpInterval: 75000 # 75 seconds (ms) between keepalive probes
tcpRetries: 9 # Number of keepalive probes before connection is droppedThese settings control the TCP keep-alive behavior for database connections. All time values are in milliseconds. If not specified, system defaults are used.
Contributions are welcome. Please open a pull request / issue with requested changes.
MIT