Deploying a Simple Cluster
September 15, 2026 ยท View on GitHub
This guide describes how to deploy a standard three-node pgEdge Distributed Postgres cluster using the sample playbook included with the collection.
Our simple cluster consists of three pgEdge nodes, each in a separate zone. Spock logical replication runs between all nodes so that writes on any node are replicated to every other node. This topology does not include HA components such as etcd, Patroni, or HAProxy.
Creating an Inventory File
Before running a playbook, create an inventory file that defines your three nodes and assigns each to a distinct zone. The following example of an inventory file uses IP addresses as host identifiers:
all:
vars:
ansible_user: pgedge
pgedge:
vars:
db_password: secret
hosts:
192.168.6.10:
zone: 1
192.168.6.11:
zone: 2
192.168.6.12:
zone: 3
The zone variable must be unique per node. Zones also serve as Snowflake
node IDs, so ensure that each node in the cluster has a distinct integer
value.
Creating a Playbook
Create a playbook file that applies the required roles in order. The following example deploys a simple three-node cluster:
- hosts: pgedge
collections:
- pgedge.platform
roles:
- init_server
- install_repos
- install_pgedge
- setup_postgres
- setup_pgedge
Running the Playbook
Run the playbook with the following command, substituting your inventory file name and path:
ansible-playbook -i inventory.yaml playbook.yaml
After the playbook completes, each node will have a running PostgreSQL instance with Spock and Snowflake extensions installed. All nodes will be subscribed to each other for bidirectional logical replication.
Configuring the Cluster
Override default parameters by setting variables in the inventory or playbook. The following example inventory configures PostgreSQL 17 with a custom database name and user:
pgedge:
vars:
pg_version: 17
db_names:
- mydb
db_user: myuser
db_password: mypassword
A complete list of parameters is available in the Configuration Reference.
Adding Connection Pooling
Every node in the cluster can also run a pgBouncer connection pooler, giving it
a second endpoint on port 6432 beside PostgreSQL's own on 5432. Pooling is
opt-in and cluster-wide, like is_ha_cluster: set pgbouncer_enabled on the
pgedge group and every node gets a pooler in front of its own PostgreSQL.
The following inventory pools all three nodes:
all:
vars:
ansible_user: pgedge
pgedge:
vars:
db_password: secret
pgbouncer_enabled: true
pgbouncer_auth_password: poolsecret
hosts:
192.168.6.10:
zone: 1
192.168.6.11:
zone: 2
192.168.6.12:
zone: 3
pgbouncer_auth_password is the pooler's own PostgreSQL login. It is the one
password the collection writes to disk, and the playbook refuses to run while
it is still the default secret, so set it here or take it from a vault.
Add the two pooling roles to the playbook, gated on pgbouncer_enabled so a
cluster that does not pool is untouched:
- hosts: pgedge
collections:
- pgedge.platform
roles:
- init_server
- install_repos
- install_pgedge
- role: install_pgbouncer
when: pgbouncer_enabled | bool
- setup_postgres
- role: setup_pgbouncer
when: pgbouncer_enabled | bool
- setup_pgedge
After the playbook completes, every node answers on two ports. Clients choose which one they want:
# Direct connection to PostgreSQL
psql -h 192.168.6.10 -p 5432 -U admin demo
# Pooled connection through pgBouncer
psql -h 192.168.6.10 -p 6432 -U admin demo
The two endpoints are not interchangeable. They enforce separate client
authentication rules, so a client that reaches one is not automatically
admitted to the other, and nothing fails a pooled connection over to
PostgreSQL. Out of the box the pooled endpoint admits the cluster's own nodes
and local administration; name any other client in pgbouncer_hba_rules to
admit it to the pooled endpoint, or in custom_hba_rules to admit it to both.
Every PostgreSQL role works through the pooler, including roles created after deployment, because the pooler looks each client's stored credential up rather than keeping a password list of its own. See Pooling Configuration for the pool mode, TLS, and sizing parameters.