PostgreSQL
Edka provisions PostgreSQL on your cluster with
CloudNativePG. Each database is a CloudNativePG
Cluster in a namespace you choose. Its volumes and Secrets stay in your
cluster, and its backups go to a bucket you own.
A PostgreSQL database has Overview, Insights, Logs, Users & DB, Backups, and Settings tabs. A Pooler tab appears when the connection pooler is on.
Prerequisites
Section titled “Prerequisites”- An Edka cluster. For
3or5instances, use at least as many schedulable nodes as instances so each instance runs on its own node. With fewer, the General tab shows a Not enough nodes warning. - For backups, a bucket on Amazon S3, an S3 compatible service, or Google Cloud Storage, with credentials that can write to it. Azure Blob Storage is not a PostgreSQL backup target. See Object Storage.
- For a Tailscale endpoint, the Tailscale add-on installed on the cluster. For a private load balancer, private networking enabled on the cluster.
Create a database
Section titled “Create a database”- Open the cluster and select Databases under Workloads. Select Create Database, then pick PostgreSQL.
- On General, enter the Database name and the Namespace. Both are fixed after creation.
- Pick the PostgreSQL version. The default is
18.6. The overview lists every version. - Set Instance count.
1 instanceruns a single primary.3 instancesor5 instancesadds replicas with synchronous replication and automatic failover. - Set Storage size (Gi), the data volume of each instance, and the
Storage class. The default size is
10. The storage class is fixed after creation. - Under Credentials, set the Database, the Application user that owns it, and the Superuser. All three names are fixed after creation. The form fills in a 24 character Application password and Superuser password. Replace them with your own of at least 8 characters, or keep them.
- Review the other tabs. Each one has working defaults.
- Select Create PostgreSQL.
| Tab | Sets |
|---|---|
| Import | An empty database, a clone, or an import from another server |
| Resources | CPU and memory requests and limits for each instance |
| Extensions | Extensions to install in each database |
| Advanced | Shared preload libraries and PostgreSQL parameters |
| Placement | The node pool and taint toleration |
| Access | External access, its network, and its port |
| Pooling | The PgBouncer connection pooler |
| Backup | WAL archiving and base backups to object storage |
The database is ready when its status reads Ready and Runtime Status on Overview lists every instance as ready with one primary. Creation fails if the instances are not ready within 20 minutes.
Resources and placement
Section titled “Resources and placement”On Resources, each instance requests 100 m of CPU and 256 Mi of memory
by default. CPU limit (m) and Memory limit (Mi) are optional, and empty
means no cap. PostgreSQL is killed if it exceeds the memory limit. Keep
Memory request (Mi) at least twice shared_buffers. The form rejects a
smaller request. Saving a resource change restarts the instances one at a time.
On Placement, pick a Node pool or keep Default cluster placement.
Keep Tolerate node pool taints on when the pool is tainted. Otherwise the
pods stay Pending.
Storage and the WAL volume
Section titled “Storage and the WAL volume”Storage size (Gi) can grow later on a storage class that allows volume expansion. It cannot shrink.
The WAL volume switch on the General tab puts pg_wal on its own
volume, which keeps write-ahead log I/O off the data volume. Set WAL storage
size (Gi) and WAL storage class. You can add the WAL volume after creation.
Once it exists you can grow it, but you cannot remove it or change its storage
class.
Connection pooler
Section titled “Connection pooler”On Pooling, turn on the Connection Pooling switch to put PgBouncer between clients and the primary.
| Field | Default | Meaning |
|---|---|---|
| Pool mode | Transaction | Session keeps one server connection per client |
| Max client connections | 1000 | Concurrent client connections PgBouncer accepts |
| Default pool size | 10 | Server connections per user and database pair |
Edka runs one pooler pod for a single instance and three for 3 or 5
instances. The three pods must run on separate nodes, so a cluster with fewer
than three schedulable nodes leaves some of them Pending.
With the pooler on, the connection details on Overview point at the pooler
service, <name>-pooler-rw, and external access reaches PostgreSQL through the
pooler. The Pooler tab charts queries, transactions, active and waiting
clients, CPU, and memory for the pooler pods.
Connect
Section titled “Connect”On Overview, the Connection Details card builds the connection for you. Pick the network and the user, then copy from Parameters or Connection string. Unlock the card to load passwords. Edka asks for step-up verification first.
Inside the cluster, clients connect to
<name>-rw.<namespace>.svc.cluster.local:5432, or to
<name>-pooler-rw.<namespace>.svc.cluster.local with the pooler on. Both follow
the primary, so a failover does not change the address.
Credentials are in Kubernetes Secrets in the database namespace, each with
username and password keys:
<name>-appfor the application user<name>-superuserfor the superuser<name>-role-<user>for each user added on Users & DB
To change a password, open Settings, then General, and enter a new value under Passwords.
External access
Section titled “External access”On the Access tab, turn on External Access, pick a Network, and set
the Port. The default port is 5432. The networks, hostname, and
certificate work the same for every engine. See
External access.
Require TLS rejects connections without TLS on every network. It is on by
default for new databases. While it is on, clients inside the cluster connect
with sslmode=require. With the pooler on, the external endpoint is the pooler,
which still accepts sessions without TLS.
Once the certificate is issued, Verified connection on Overview shows the client command:
psql "host=<hostname> port=<port> dbname=<database> user=<user> sslmode=verify-full sslrootcert=system"sslrootcert=system needs a PostgreSQL 16 or later client.
Users, databases, and extensions
Section titled “Users, databases, and extensions”The Users & DB tab lists the users and databases Edka provisions beside the application user and its database.
- Add User takes a Username and a Password of at least 8 characters. Superuser and Create databases grant those privileges.
- Add Database takes a Database name and an Owner, which is the application user, the superuser, or a user from this tab.
Save the page to apply the changes. A saved user or database cannot be renamed or removed from this tab.
Extensions are on Settings, under Extensions. Add Extension takes:
- Catalog or Extension name. The catalog lists extensions shipped with
the PostgreSQL image, such as
vector,pg_stat_statements,pg_trgm, andpgcrypto. Extension name is the name used inCREATE EXTENSION. - Target database, the database to install it in.
- Ensure.
Presentinstalls the extension andAbsentdrops it. - Version and Schema, both optional.
PostgreSQL parameters
Section titled “PostgreSQL parameters”The Advanced tab sets server configuration:
- Shared preload libraries, one per line. Changing them restarts the
instances. Libraries that a parameter needs, such as
pg_stat_statements, are added for you. - Parameter Catalog, a searchable list of 35 common parameters, including
max_connections,shared_buffers,work_mem, and theautovacuum_*family. - Custom Parameters for anything not in the catalog.
Memory parameters such as shared_buffers and work_mem need a unit, for
example 512MB. shared_buffers can be at most half of the memory request.
Parameters that CloudNativePG controls, such as archive_command,
listen_addresses, port, and the ssl settings, are rejected.
New databases set pg_stat_statements.max = 10000 and
pg_stat_statements.track = all.
Backups
Section titled “Backups”Backups use the Barman Cloud plugin. It archives WAL continuously and takes base backups, which together allow point in time recovery.
- Open Settings, then Backup. The same tab is in the create form.
- Turn on the Backups switch. On an existing database, turning backups on or off restarts the instances when you save.
- Set Retention from
1to35days. The default is7. Base backups and WAL archives older than this are deleted, so this is also how far back a restore can go. - Set the Path prefix, the folder inside the bucket. The default is
postgres_backup. Backups land in<prefix>/<database-id>/. The database ID follows/databases/in the database page URL. - Pick the storage. With Use a saved object storage integration on, select
an Integration. With it off, pick a Provider:
Amazon S3 / S3-Compatibletakes the S3 bucket, Access key ID, and Secret access key. For MinIO, Ceph, Wasabi, or Hetzner Object Storage, also turn on S3-compatible endpoint and enter the S3 endpoint URL, for examplehttps://fsn1.your-objectstorage.com.Google Cloud Storagetakes the GCS bucket and the Service account JSON.
- Save.
The first base backup starts as soon as backups are on. After that a base backup runs every day at 00:00 UTC. Backups are gzip compressed. On Amazon S3 and Google Cloud Storage they use AES256 server side encryption.
The Backups tab lists each backup under Backup Snapshots with its name, status, method, completion time, and instance. The line above the list reads “Last backup … Recoverable from …” once a base backup completes. Backup now takes an extra backup. It is available when backups are on, the database is ready, and no other backup is running.
Restore to a new database
Section titled “Restore to a new database”A restore always creates a new database in the same Kubernetes cluster and leaves the source unchanged. The source database must still exist. After you delete a database, its backups stay in the bucket but Edka can no longer restore them.
- Open the Backups tab of the source database.
- Under Restore Method, pick one:
- Latest WAL replays every archived change up to the most recent recovery point.
- Specific timestamp restores to a moment between Earliest Point and Latest Safe Target. Enter the time in your local timezone.
- Backup snapshot restores a completed base backup without replaying later changes.
- Under Target, enter the New Database Name, which defaults to
<source>-restored, and the Target Namespace. - Select Start Restore.
Latest Safe Target trails the last archived WAL segment by about five minutes. Restore is unavailable until the first base backup completes.
The new database copies the full configuration of the source: instance count, storage, resources, placement, pooler, external access, parameters, users, extensions, and backup settings. It also keeps the source passwords. It runs the PostgreSQL major version that wrote the backup, and its own backups go to a new folder under the same path prefix.
Import or clone
Section titled “Import or clone”The Import tab of the create form sets where the first data comes from. The choice is fixed after creation.
- Empty database starts with only the database and user from General.
- Clone an existing cluster copies a CloudNativePG cluster running in the
same Kubernetes cluster and namespace with
pg_basebackup. The version, database, and application user follow the Source cluster. - Import from an external PostgreSQL runs
pg_dumpandpg_restoreagainst any PostgreSQL server the cluster can reach.
For an import, set:
- Import type.
Microservicecopies one Source database into the database and user from General.Monolithkeeps the source database and role names. List them under Source databases and Source roles, one per line, or enter*alone for all of them. - Source host, Source port, Connection database (usually
postgres), Source user, and Source password. The user needs read access to everything being imported. The password is stored in the<name>-import-sourceSecret. - SSL mode. The default is
Prefer. UseRequireor stricter for a server reached over the internet. - pg_dump and pg_restore options, one flag per line, for example
--no-owner.
The import runs while the database is being created, and Logs shows its progress. Creation fails if the import has not finished after 24 hours. With backups on, the first base backup starts when the import finishes.
Upgrade PostgreSQL
Section titled “Upgrade PostgreSQL”Open Settings, then General, and pick a newer PostgreSQL version. Save the version change on its own, without other edits. Downgrades are rejected.
- Minor upgrade. Select Apply Upgrade. With replicas, CloudNativePG updates the replicas first and then switches the primary over to an updated replica. A single instance restarts in place.
- Major upgrade. The database goes offline while
pg_upgraderuns, and the replicas are cloned again afterwards. Turn on Acknowledge major upgrade, then select Start Major Upgrade. With backups on, Edka takes a backup before the upgrade and cancels the upgrade if that backup fails. It takes another backup afterwards and refreshes planner statistics withvacuumdb --all --analyze-in-stages. With backups off, take your own backup first.
Monitoring and alerts
Section titled “Monitoring and alerts”Insights charts transactions, connections, CPU, and memory, and reports connection capacity, cache hit ratio, database size, and replication lag. History needs VictoriaMetrics installed on the cluster. Without it the charts cover the current session only.
Current Connections lists client sessions with their query and duration.
Query Statistics shows the top statements from pg_stat_statements. Install
that extension under Settings, then Extensions, to collect them.
With VictoriaMetrics installed, Edka installs the Postgres alert pack when a PostgreSQL database becomes ready. Its ten rules cover unreachable instances, a missing primary, a required manual switchover, stalled WAL archiving, exceeded WAL retention, failed backups, connection saturation, waiting backends, long transactions, and replication lag. See Alert packs.
Delete a database
Section titled “Delete a database”Open Settings, then General, and use the delete section at the bottom.
Type delete me to confirm. Deleting removes the database, its volumes, and its
Kubernetes Secrets from the cluster. Backups stay in the bucket. Remove them
there when you no longer need them. Apps that still use the database block the
delete.
Troubleshooting
Section titled “Troubleshooting”-
Instance or pooler pods stay
Pending. The selected node pool has too few schedulable nodes, or Tolerate node pool taints is off for a tainted pool. The three pooler pods of a3or5instance database each need their own node. -
The Backups tab says “Continuous archiving is on. No completed backup yet.” long after the database is ready. List the backups and read the error on the failed one. Wrong credentials, a missing bucket, or a wrong endpoint URL show up there.
Terminal window kubectl get backups.postgresql.cnpg.io -n <namespace>kubectl describe backups.postgresql.cnpg.io <backup-name> -n <namespace> -
Backup now is disabled. It needs backups on, the database in the Ready state, and no backup already running.
-
The Integration list is empty. Only Amazon S3, S3 compatible, and Google Cloud Storage integrations qualify.
-
An import is still running. Follow it on Logs, or list its pods:
Terminal window kubectl get pods -n <namespace> -l cnpg.io/cluster=<name>,cnpg.io/jobRole=import
For kubectl, the resources of a database named <name> are the Cluster
<name>, the Pooler <name>-pooler-rw, the ScheduledBackup
<name>-backup, and the ObjectStore <name>-backup-store.