PostgresSQL Clustering the hard way: Difference between revisions
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>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> | </pre><big>PostgreSQL</big> | ||
<big> | <big>On postgres nodes install latest postgres.</big> | ||
<big> | <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> | </pre><big>We’ll configure postgres later. | ||
Stop and disable the service because Patroni will handle the</big> lifecycle of postgres | 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> | </pre>etcd</big> | ||
<big> | <big>Install</big> | ||
<big> | <big>This should be installed on the postgres servers.</big> | ||
<big> | <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> | </pre><big>Find latest release. | ||
https://github.com/etcd-io/etcd/releases | 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> | </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> | 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> | </pre>Check <code>etcd</code> version</big><pre> | ||
etcd --version | etcd --version | ||
etcdctl version | etcdctl version | ||
</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> | </pre>Before configuring <code>etcd</code>, we need to repeat all of these steps for the other 2 nodes.</big> | ||
<big> | <big>Let’s configure <code>etcd</code>.</big> | ||
<big> | <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> | </pre><big>Linux</big><pre> | ||
sudo apt install openssl | sudo apt install openssl | ||
</pre><big> | </pre><big>Verify it’s installed and working</big><pre> | ||
openssl version | openssl version | ||
</pre><big> | </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> | </pre><big>Now let’s generate and configure certs</big><pre> | ||
mkdir certs | mkdir certs | ||
cd certs | cd certs | ||
</pre><big> | </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> | </pre><big>Generate certificate each node. Note, pay attention to SANS, I am using IP, update with your IP and oh DNS/hostname. | ||
node1 | 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> | </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> | </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> | </pre>List all files</big><pre> | ||
ls | ls | ||
</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> | </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> | </pre>Should see:</big> | ||
<big> | <big><code>ssh</code> into each node</big> | ||
<big> | <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> | </pre><big>Configure | ||
Create our config | 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
- Generate a private key
openssl genrsa -out etcd-node2.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.104 IP.2 = 127.0.0.1 EOF
- 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
- 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
- Verify the cert and be sure you see Subject Name Alternative
openssl x509 -in etcd-node2.crt -text -noout | grep -A1 "Subject Alternative Name"
- Remove temp file
rm temp.cnf
node3
- Generate a private key
openssl genrsa -out etcd-node3.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.105 IP.2 = 127.0.0.1 EOF
- 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
- 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
- Verify the cert and be sure you see Subject Name Alternative
openssl x509 -in etcd-node3.crt -text -noout | grep -A1 "Subject Alternative Name"
- 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