ELMA365 On-Premises > Prepare infrastructure > Databases > High availability infrastructure / PostgreSQL cluster

PostgreSQL cluster

To ensure the correct operation of the system, PostgreSQL version 10–15 is required. The article describes the installation of PostgreSQL 13 for Ubuntu Linux 20.04 and 22.04. You can also refer to the official PostgreSQL documentation.

The installation consists of 10 steps:

  1. Prepare nodes (servers).
  2. Prepare the etcd cluster.
  3. Install PostgreSQL.
  4. Configure PostgreSQL.
  5. Install Patroni.
  6. Configure Patroni.
  7. Prepare the PostgreSQL+Patroni cluster.
  8. Prepare PGBouncer (optional).
  9. Configure HAProxy (postgres block).
  10. Connect to PostgreSQL.

Step 1: Prepare nodes (servers)

Create three nodes (servers) with sequentially numbered host names.

начало внимание

The minimum number of servers for organizing a cluster is three.

конец внимание

In this example, three nodes with the following hostnames and IP addresses are used:

  • postgres-server1.your_domain, 192.168.1.1;
  • postgres-server2.your_domain, 192.168.1.2;
  • postgres-server3.your_domain, 192.168.1.3.

Create the necessary host name mappings in DNS. If not possible, add the required entries in /etc/hosts.

Step 2: Prepare the etcd cluster

  1. Install etcd on all nodes:

sudo apt-get install etcd -y

  1. Stop etcd on all nodes:

sudo systemctl stop etcd

  1. Remove the data directory:

sudo rm -rf /var/lib/etcd/*

  1. Move the default configuration file:

sudo mv /etc/default/etcd{,.original}

  1. Create and open a new configuration file for editing:

sudo nano /etc/default/etcd

  1. Add the example configurations for the postgres-server1.your_domain node:

ETCD_NAME="postgres-server1"
ETCD_DATA_DIR="/var/lib/etcd/default"
ETCD_HEARTBEAT_INTERVAL="1000"
ETCD_ELECTION_TIMEOUT="5000"
ETCD_LISTEN_PEER_URLS="http://192.168.1.1:2380"
ETCD_LISTEN_CLIENT_URLS="http://192.168.1.1:2379,http://localhost:2379"
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://192.168.1.1:2380"
ETCD_INITIAL_CLUSTER="postgres-server1=http://192.168.1.1:2380,postgres-server2=http://192.168.1.2:2380,postgres-server3=http://192.168.1.3:2380"
ETCD_INITIAL_CLUSTER_STATE="new"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-postgres-cluster"
ETCD_ADVERTISE_CLIENT_URLS="http://192.168.1.1:2379"
ETCD_ENABLE_V2="true"
ETCD_INITIAL_ELECTION_TICK_ADVANCE="false"

Example configurations with enabling TLS/SSL for the postgres-server1.your_domain node:

  1. Add the example configurations to the file for the postgres-server2.your_domain node:

ETCD_NAME="postgres-server2"
ETCD_DATA_DIR="/var/lib/etcd/default"
ETCD_HEARTBEAT_INTERVAL="1000"
ETCD_ELECTION_TIMEOUT="5000"
ETCD_LISTEN_PEER_URLS="http://192.168.1.2:12380"
ETCD_LISTEN_CLIENT_URLS="http://192.168.1.2:2379,http://127.0.0.1:2379"
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://192.168.1.2:12380"
ETCD_INITIAL_CLUSTER="postgres-server1=http://192.168.1.1:12380,postgres-server2=http://192.168.1.2:12380,postgres-server3=http://192.168.1.3:12380"
ETCD_INITIAL_CLUSTER_STATE="new"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-postgres-cluster"
ETCD_ADVERTISE_CLIENT_URLS="http://192.168.1.2:2379"
ETCD_ENABLE_V2="true"
ETCD_INITIAL_ELECTION_TICK_ADVANCE="false"

Example configurations with enabling TLS/SSL for the postgres-server2.your_domain:

  1. Add the example configurations to the file for the postgres-server3.your_domain node:

ETCD_NAME="postgres-server3"
ETCD_DATA_DIR="/var/lib/etcd/default"
ETCD_HEARTBEAT_INTERVAL="1000"
ETCD_ELECTION_TIMEOUT="5000"
ETCD_LISTEN_PEER_URLS="http://192.168.1.3:2380"
ETCD_LISTEN_CLIENT_URLS="http://192.168.1.3:2379,http://localhost:2379"
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://192.168.1.3:2380"
ETCD_INITIAL_CLUSTER="postgres-server1=http://192.168.1.1:2380,postgres-server2=http://192.168.1.2:2380,postgres-server3=http://192.168.1.3:2380"
ETCD_INITIAL_CLUSTER_STATE="new"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-postgres-cluster"
ETCD_ADVERTISE_CLIENT_URLS="http://192.168.1.3:2379"
ETCD_ENABLE_V2="true"
ETCD_INITIAL_ELECTION_TICK_ADVANCE="false"

Example configurations with enabling TLS/SSL for the postgres-server3.your_domain:

Let's review the provided parameters:

  • ETCD_NAME: Unique name within the cluster;
  • ETCD_LISTEN_CLIENT_URLS: Connection point for clients in the cluster;
  • ETCD_ADVERTISE_CLIENT_URLS: URLs through which other cluster nodes can be found.;
  • ETCD_LISTEN_PEER_URLS: Connection point for other nodes in the cluster;
  • ETCD_INITIAL_ADVERTISE_PEER_URLS: Initial URLs through which other nodes can find it;
  • ETCD_INITIAL_CLUSTER_TOKEN: Token for the cluster, must be the same on all nodes.;
  • ETCD_INITIAL_CLUSTER: List of nodes in the cluster at startup;
  • ETCD_INITIAL_CLUSTER_STATE: Can take two values: new and existing;
  • ETCD_DATA_DIR: Location of the cluster's data directory;
  • ETCD_ELECTION_TIMEOUT: Time in milliseconds between the last received notification from the cluster leader and attempting to take over the leader role on the follower node;
  • ETCD_HEARTBEAT_INTERVAL: Time in milliseconds between leader notifications sent by the leader node to inform others that it is still the leader;
  • ETCD_CERT_FILE: Path to the server certificate file;
  • ETCD_KEY_FILE: Path to the private key file;
  • ETCD_TRUSTED_CA_FILE: Path to the root CA file;
  • ETCD_CLIENT_CERT_AUTH: Can take two values: true and false;
  • ETCD_PEER_CERT_FILE: Path to the server certificate file;
  • ETCD_PEER_KEY_FILE: Path to the private key file;
  • ETCD_PEER_TRUSTED_CA_FILE: Path to the root CA file;
  • ETCD_PEER_CLIENT_CERT_AUTH: Can take two values: true and false;
  1. Restart etcd on all nodes:

sudo systemctl restart etcd

  1. Check the cluster status.

For a cluster without TLS:

sudo etcdctl cluster-health

For a cluster with TLS:

sudo etcdctl -C https://postgres-server1.your_domain:2379 --key-file /path/to/private.key --cert-file /path/to/public.crt --ca-file /path/to/certCA.pem cluster-health

Step 3: Install PostgreSQL

начало внимание

Hardware requirements for ELMA365 on PostgreSQL can be found in System requirements for ELMA365 On-Premises Enterprise.

конец внимание

  1. To install PostgreSQL, add the official repository postgresql:

sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -

  1. Update package cache:

sudo apt update

  1. Install PostgreSQL on all nodes:

sudo apt install postgresql-13 -y

Step 4: Configure PostgreSQL

начало внимание

For the password, the following characters are allowed:

  • Uppercase Latin letters: A to Z
  • Lowercase Latin letters: a to z
  • Digits: 0 to 9
  • Symbols: -_

Reserved (invalid) symbols:

! * ' ( ) ; : @ & = + $ , / ? % # [ ]

конец внимание

Actions for the node postgres-server1.your_domain:

  1. Create a new role elma365 with the password SecretPassword:

sudo -u postgres psql -c \
"CREATE ROLE elma365 WITH login password 'SecretPassword';"

  1. Create a database elma365 with owner elma365:

sudo -u postgres psql -c \
"CREATE DATABASE elma365 WITH OWNER elma365;"

  1. Add necessary extensions for the database elma365:

sudo -u postgres psql -d elma365 -c \
"CREATE EXTENSION \"uuid-ossp\"; CREATE EXTENSION pg_trgm;"

  1. Create a new role replicator with the password ReplicatorPassword for working with replicas. It must match the Patroni settings in the block postgresql - authentication - replication and the list of allowed PostgreSQL hosts in the file pg_hba.conf:

sudo -u postgres psql -c \
"CREATE USER replicator WITH REPLICATION ENCRYPTED PASSWORD 'ReplicatorPassword';"

  1. Set a password for the postgres user:

sudo -u postgres psql -c "ALTER USER postgres PASSWORD 'PostgresPassword';"

  1. Stop PostgreSQL:

systemctl stop postgresql

Actions for the nodes postgres-server2.your_domain and postgres-server3.your_domain:

  1. Stop PostgreSQL:

systemctl stop postgresql

  1. Remove the data directory on the nodes postgres-server2.your_domain and postgres-server3.your_domain:

rm -rf /var/lib/postgresql/13/main

Step 5: Install Patroni

  1. Install Patroni and PIP on all nodes:

sudo apt-get install python3-pip python3-dev libpq-dev -y
sudo apt-get install patroni -y

  1. Install dependencies for Patroni to work on all nodes:

pip3 install psycopg2-binary
pip3 install wheel
pip3 install python-etcd

Step 6: Configure Patroni

  1. Create a configuration file:

sudo nano /etc/patroni/config.yml

  1. Place an example initial configuration in the created /etc/patroni/config.yml file, changing the IP addresses for each node in the cluster. Pay attention to the comments in this file.

Example initial configuration

Example initial configuration to enable TLS/SSL support in Patroni

  1. Make the postgres user the owner of the configuration directory:

sudo chown postgres:postgres -R /etc/patroni
sudo chmod 700 /etc/patroni

Step 7: Prepare PostgreSQL+Patroni cluster

  1. Start the Patroni service on the postgres-server1.your_domain node, and then on the nodes postgres-server2.your_domain and postgres-server3.your_domain:

sudo systemctl enable --now patroni.service

  1. Check the cluster status:

patronictl -c /etc/patroni/config.yml list

Step 8: Prepare PGBouncer (optional)

PGBouncer is designed to manage a connection pool to PostgreSQL, minimizing the overhead associated with establishing new connections to PostgreSQL. For information on installing and configuring PGBouncer, refer to Install PGBouncer.

Step 9: Configure HAProxy (postgres block)

Configure a high availablility HAProxy  to handle requests to PostgreSQL and load balance between the nodes of the PostgreSQL cluster. For more details, refer to Configure HAProxy for PostgreSQL.

Step 10: Connecto to PostgreSQL

Connection string to connect to the PostgreSQL cluster:

psqlUrl: postgresql://elma365:SecretPassword@haproxy-server.your_domain:5000/elma365?sslmode=disable

Connection string to connect to the PostgreSQL cluster for read-only access:

psqlUrl: postgresql://elma365:SecretPassword@haproxy-server.your_domain:5001/elma365?sslmode=disable

Connecting to the PostgreSQL cluster with TLS/SSL

Found a typo? Highlight the text, press ctrl + enter and notify us