PostgresSQL Clustering the hard way: Difference between revisions

From wiki.baghirzade.pro
Jump to navigation Jump to search
No edit summary
No edit summary
Line 1: Line 1:
[[File:Screenshot 2025-09-26 153622.jpg|center|thumb|1234x1234px]]
[[File:Screenshot 2025-09-26 153622.jpg|center|thumb|1234x1234px]]
'''<big>Today is the day that you start running PostgresSQL in a cluster! In this tutorial we’ll be setting up a production ready Postgres cluster that’s highly available and fault tolerant using PostgreSQL, etcd, Patroni, HA Proxy, and keepalived. This resilient combination will ensure that you can always reach your database even when a node in the cluster goes down!</big>'''
<big>Today is the day that you start running PostgresSQL in a cluster! In this tutorial we’ll be setting up a production ready Postgres cluster that’s highly available and fault tolerant using PostgreSQL, etcd, Patroni, HA Proxy, and keepalived. This resilient combination will ensure that you can always reach your database even when a node in the cluster goes down!</big>




'''<big>Nodes</big>'''<pre>
 
<big>Nodes</big><pre>
# ha proxy
# ha proxy
192.168.60.100 # haproxy-01
192.168.60.100 # haproxy-01
Line 13: Line 14:
192.168.60.104 # postgres-02
192.168.60.104 # postgres-02
192.168.60.105 # postgres-03
192.168.60.105 # postgres-03
</pre><big>'''PostgreSQL'''</big>
</pre><big>PostgreSQL</big>


<big>'''On postgres nodes install latest postgres.'''</big>
<big>On postgres nodes install latest postgres.</big>


<big>'''Install updated postgres repositories.'''</big><pre>
<big>Install updated postgres repositories.</big><pre>
sudo apt update
sudo apt update
sudo apt install -y postgresql-common
sudo apt install -y postgresql-common
sudo /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh
sudo /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh
</pre>'''<big>We’ll configure postgres later.
</pre><big>We’ll configure postgres later.


Stop and disable the service because Patroni will handle the</big> lifecycle of postgres'''<pre>
Stop and disable the service because Patroni will handle the</big> lifecycle of postgres<pre>
sudo systemctl stop postgresql
sudo systemctl stop postgresql
sudo systemctl disable postgresql
sudo systemctl disable postgresql
</pre><big>'''etcd'''</big>
</pre>etcd</big>


<big>'''Install'''</big>
<big>Install</big>


<big>'''This should be installed on the postgres servers.'''</big>
<big>This should be installed on the postgres servers.</big>


<big>'''Make sure you have <code>wget</code> and <code>curl</code>'''</big><pre>
<big>Make sure you have <code>wget</code> and <code>curl</code></big><pre>
sudo apt update
sudo apt update
sudo apt-get install -y wget curl
sudo apt-get install -y wget curl
</pre><big>'''Find latest release.
</pre><big>Find latest release.


https://github.com/etcd-io/etcd/releases'''</big><pre>
https://github.com/etcd-io/etcd/releases</big><pre>
wget https://github.com/etcd-io/etcd/releases/download/v3.5.17/etcd-v3.5.17-linux-amd64.tar.gz
wget https://github.com/etcd-io/etcd/releases/download/v3.5.17/etcd-v3.5.17-linux-amd64.tar.gz
</pre><big>'''Uncompress and rename.'''</big><pre>tar xvf etcd-v3.5.17-linux-amd64.tar.gz
</pre>Uncompress and rename.</big><pre>tar xvf etcd-v3.5.17-linux-amd64.tar.gz
mv etcd-v3.5.17-linux-amd64 etcd</pre><big>'''Move all binaries into <code>/usr/local/bin/</code> for later use.'''</big><pre>
mv etcd-v3.5.17-linux-amd64 etcd</pre>Move all binaries into <code>/usr/local/bin/</code> for later use.</big><pre>
sudo mv etcd/etcd* /usr/local/bin/
sudo mv etcd/etcd* /usr/local/bin/
</pre><big>'''Check <code>etcd</code> version'''</big><pre>
</pre>Check <code>etcd</code> version</big><pre>
etcd --version
etcd --version
etcdctl version
etcdctl version
</pre><big>'''Let’s create a user for <code>etcd</code> service.'''</big><pre>
</pre>Let’s create a user for <code>etcd</code> service.</big><pre>
sudo useradd --system --home /var/lib/etcd --shell /bin/false etcd
sudo useradd --system --home /var/lib/etcd --shell /bin/false etcd
</pre><big>'''Before configuring <code>etcd</code>, we need to repeat all of these steps for the other 2 nodes.'''</big>
</pre>Before configuring <code>etcd</code>, we need to repeat all of these steps for the other 2 nodes.</big>


<big>'''Let’s configure <code>etcd</code>.'''</big>
<big>Let’s configure <code>etcd</code>.</big>


<big>'''Make dir and edit file.'''</big><pre>
<big>Make dir and edit file.</big><pre>
sudo mkdir -p /etc/etcd
sudo mkdir -p /etc/etcd
sudo mkdir -p /etc/etcd/ssl
sudo mkdir -p /etc/etcd/ssl
</pre><big>'''Linux'''</big><pre>
</pre><big>Linux</big><pre>
sudo apt install openssl
sudo apt install openssl
</pre><big>'''Verify it’s installed and working'''</big><pre>
</pre><big>Verify it’s installed and working</big><pre>
openssl version
openssl version
</pre><big>'''Should see something like:'''</big><pre>
</pre><big>Should see something like:</big><pre>
OpenSSL 3.4.0 22 Oct 2024 (Library: OpenSSL 3.4.0 22 Oct 2024)
OpenSSL 3.4.0 22 Oct 2024 (Library: OpenSSL 3.4.0 22 Oct 2024)
</pre><big>'''Now let’s generate and configure certs'''</big><pre>
</pre><big>Now let’s generate and configure certs</big><pre>
mkdir certs
mkdir certs
cd certs
cd certs
</pre><big>'''Generate cert authority'''</big><pre>
</pre><big>Generate cert authority</big><pre>
openssl genrsa -out ca.key 2048
openssl genrsa -out ca.key 2048
openssl req -x509 -new -nodes -key ca.key -subj "/CN=etcd-ca" -days 7300 -out ca.crt
openssl req -x509 -new -nodes -key ca.key -subj "/CN=etcd-ca" -days 7300 -out ca.crt
</pre><big>'''Generate certificate each node. Note, pay attention to SANS, I am using IP, update with your IP and oh DNS/hostname.
</pre><big>Generate certificate each node. Note, pay attention to SANS, I am using IP, update with your IP and oh DNS/hostname.


node1'''</big><pre>
node1</big><pre>
# Generate a private key
# Generate a private key
openssl genrsa -out etcd-node1.key 2048
openssl genrsa -out etcd-node1.key 2048
Line 101: Line 102:


rm temp.cnf
rm temp.cnf
</pre><big>'''node 2'''</big><pre>
</pre>node 2</big><pre>
# Generate a private key
# Generate a private key
openssl genrsa -out etcd-node2.key 2048
openssl genrsa -out etcd-node2.key 2048
Line 132: Line 133:
# Remove temp file
# Remove temp file
rm temp.cnf
rm temp.cnf
</pre><big>'''node3'''</big><pre>
</pre>node3</big><pre>
# Generate a private key
# Generate a private key
openssl genrsa -out etcd-node3.key 2048
openssl genrsa -out etcd-node3.key 2048
Line 163: Line 164:
# Remove temp file
# Remove temp file
rm temp.cnf
rm temp.cnf
</pre><big>'''List all files'''</big><pre>
</pre>List all files</big><pre>
ls
ls
</pre><big>'''Should see:'''</big><pre>
</pre>Should see:</big><pre>
ca.crt
ca.crt
ca.key
ca.key
Line 177: Line 178:
etcd-node3.csr
etcd-node3.csr
etcd-node3.key
etcd-node3.key
</pre><big>'''Secure copy (<code>scp</code>) the certs to each node:'''</big><pre>
</pre>Secure copy (<code>scp</code>) the certs to each node:</big><pre>
scp ca.crt etcd-node1.crt etcd-node1.key [email protected]:/tmp/
scp ca.crt etcd-node1.crt etcd-node1.key [email protected]:/tmp/
scp ca.crt etcd-node2.crt etcd-node2.key [email protected]:/tmp/
scp ca.crt etcd-node2.crt etcd-node2.key [email protected]:/tmp/
scp ca.crt etcd-node3.crt etcd-node3.key [email protected]:/tmp/
scp ca.crt etcd-node3.crt etcd-node3.key [email protected]:/tmp/
</pre><big>'''Should see:'''</big>
</pre>Should see:</big>


<big>'''<code>ssh</code> into each node'''</big>
<big><code>ssh</code> into each node</big>


<big>'''We need to move certs from <code>/tmp</code> to ssl location (<code>/etc/etcd/ssl</code>)'''</big><pre>
<big>We need to move certs from <code>/tmp</code> to ssl location (<code>/etc/etcd/ssl</code>)</big><pre>
sudo mkdir -p /etc/etcd/ssl
sudo mkdir -p /etc/etcd/ssl
sudo mv /tmp/etcd-node*.crt /etc/etcd/ssl/
sudo mv /tmp/etcd-node*.crt /etc/etcd/ssl/
Line 193: Line 194:
sudo chmod 600 /etc/etcd/ssl/etcd-node*.key
sudo chmod 600 /etc/etcd/ssl/etcd-node*.key
sudo chmod 644 /etc/etcd/ssl/etcd-node*.crt /etc/etcd/ssl/ca.crt
sudo chmod 644 /etc/etcd/ssl/etcd-node*.crt /etc/etcd/ssl/ca.crt
</pre><big>'''Configure
</pre><big>Configure


Create our config'''</big><pre>
Create our config</big><pre>
sudo nano /etc/etcd/etcd.env
sudo nano /etc/etcd/etcd.env
</pre>
</pre>

Revision as of 11:55, 26 September 2025

Today is the day that you start running PostgresSQL in a cluster! In this tutorial we’ll be setting up a production ready Postgres cluster that’s highly available and fault tolerant using PostgreSQL, etcd, Patroni, HA Proxy, and keepalived. This resilient combination will ensure that you can always reach your database even when a node in the cluster goes down!


Nodes

# ha proxy
192.168.60.100 # haproxy-01
192.168.60.101 # haproxy-02
192.168.60.102 # haproxy-03

# postgres
192.168.60.103 # postgres-01
192.168.60.104 # postgres-02
192.168.60.105 # postgres-03

PostgreSQL

On postgres nodes install latest postgres.

Install updated postgres repositories.

sudo apt update
sudo apt install -y postgresql-common
sudo /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh

We’ll configure postgres later. Stop and disable the service because Patroni will handle the lifecycle of postgres

sudo systemctl stop postgresql
sudo systemctl disable postgresql

etcd

Install

This should be installed on the postgres servers.

Make sure you have wget and curl

sudo apt update
sudo apt-get install -y wget curl

Find latest release. https://github.com/etcd-io/etcd/releases

wget https://github.com/etcd-io/etcd/releases/download/v3.5.17/etcd-v3.5.17-linux-amd64.tar.gz

Uncompress and rename.

tar xvf etcd-v3.5.17-linux-amd64.tar.gz
mv etcd-v3.5.17-linux-amd64 etcd

Move all binaries into /usr/local/bin/ for later use.

sudo mv etcd/etcd* /usr/local/bin/

Check etcd version

etcd --version etcdctl version

Let’s create a user for etcd service.

sudo useradd --system --home /var/lib/etcd --shell /bin/false etcd

Before configuring etcd, we need to repeat all of these steps for the other 2 nodes.

Let’s configure etcd.

Make dir and edit file.

sudo mkdir -p /etc/etcd
sudo mkdir -p /etc/etcd/ssl

Linux

sudo apt install openssl

Verify it’s installed and working

openssl version

Should see something like:

OpenSSL 3.4.0 22 Oct 2024 (Library: OpenSSL 3.4.0 22 Oct 2024)

Now let’s generate and configure certs

mkdir certs cd certs

Generate cert authority

openssl genrsa -out ca.key 2048 openssl req -x509 -new -nodes -key ca.key -subj "/CN=etcd-ca" -days 7300 -out ca.crt

Generate certificate each node. Note, pay attention to SANS, I am using IP, update with your IP and oh DNS/hostname. node1

# Generate a private key
openssl genrsa -out etcd-node1.key 2048

# Create temp file for config
cat > temp.cnf <<EOF
[ req ]
distinguished_name = req_distinguished_name
req_extensions = v3_req
[ req_distinguished_name ]
[ v3_req ]
subjectAltName = @alt_names
[ alt_names ]
IP.1 = 192.168.60.103
IP.2 = 127.0.0.1
EOF

# Create a csr
openssl req -new -key etcd-node1.key -out etcd-node1.csr \
  -subj "/C=US/ST=YourState/L=YourCity/O=YourOrganization/OU=YourUnit/CN=etcd-node1" \
  -config temp.cnf

# Sign the cert
openssl x509 -req -in etcd-node1.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
  -out etcd-node1.crt -days 7300 -sha256 -extensions v3_req -extfile temp.cnf

# Verify the cert and be sure you see Subject Name Alternative

openssl x509 -in etcd-node1.crt -text -noout | grep -A1 "Subject Alternative Name"

# Remove temp file

rm temp.cnf

node 2

  1. Generate a private key

openssl genrsa -out etcd-node2.key 2048

  1. Create temp file for config

cat > temp.cnf <<EOF [ req ] distinguished_name = req_distinguished_name req_extensions = v3_req [ req_distinguished_name ] [ v3_req ] subjectAltName = @alt_names [ alt_names ] IP.1 = 192.168.60.104 IP.2 = 127.0.0.1 EOF

  1. Create a csr

openssl req -new -key etcd-node2.key -out etcd-node2.csr \

 -subj "/C=US/ST=YourState/L=YourCity/O=YourOrganization/OU=YourUnit/CN=etcd-node2" \
 -config temp.cnf
  1. Sign the cert

openssl x509 -req -in etcd-node2.csr -CA ca.crt -CAkey ca.key -CAcreateserial \

 -out etcd-node2.crt -days 7300 -sha256 -extensions v3_req -extfile temp.cnf
  1. Verify the cert and be sure you see Subject Name Alternative

openssl x509 -in etcd-node2.crt -text -noout | grep -A1 "Subject Alternative Name"

  1. Remove temp file

rm temp.cnf

node3

  1. Generate a private key

openssl genrsa -out etcd-node3.key 2048

  1. Create temp file for config

cat > temp.cnf <<EOF [ req ] distinguished_name = req_distinguished_name req_extensions = v3_req [ req_distinguished_name ] [ v3_req ] subjectAltName = @alt_names [ alt_names ] IP.1 = 192.168.60.105 IP.2 = 127.0.0.1 EOF

  1. Create a csr

openssl req -new -key etcd-node3.key -out etcd-node3.csr \

 -subj "/C=US/ST=YourState/L=YourCity/O=YourOrganization/OU=YourUnit/CN=etcd-node3" \
 -config temp.cnf
  1. Sign the cert

openssl x509 -req -in etcd-node3.csr -CA ca.crt -CAkey ca.key -CAcreateserial \

 -out etcd-node3.crt -days 7300 -sha256 -extensions v3_req -extfile temp.cnf
  1. Verify the cert and be sure you see Subject Name Alternative

openssl x509 -in etcd-node3.crt -text -noout | grep -A1 "Subject Alternative Name"

  1. Remove temp file

rm temp.cnf

List all files

ls

Should see:

ca.crt ca.key ca.srl etcd-node1.crt etcd-node1.csr etcd-node2.crt etcd-node2.csr etcd-node2.key etcd-node3.crt etcd-node3.csr etcd-node3.key

Secure copy (scp) the certs to each node:

scp ca.crt etcd-node1.crt etcd-node1.key [email protected]:/tmp/ scp ca.crt etcd-node2.crt etcd-node2.key [email protected]:/tmp/ scp ca.crt etcd-node3.crt etcd-node3.key [email protected]:/tmp/

Should see:

ssh into each node

We need to move certs from /tmp to ssl location (/etc/etcd/ssl)

sudo mkdir -p /etc/etcd/ssl
sudo mv /tmp/etcd-node*.crt /etc/etcd/ssl/
sudo mv /tmp/etcd-node*.key /etc/etcd/ssl/
sudo mv /tmp/ca.crt /etc/etcd/ssl/
sudo chown -R etcd:etcd /etc/etcd/
sudo chmod 600 /etc/etcd/ssl/etcd-node*.key
sudo chmod 644 /etc/etcd/ssl/etcd-node*.crt /etc/etcd/ssl/ca.crt

Configure Create our config

sudo nano /etc/etcd/etcd.env