pgstef's blog

SELECT * FROM pgstef

Home About me Talks PITR tools View on GitHub

pgBackRest is a well-known powerful backup and restore tool. It offers a lot of possibilities.

In this post, we’ll briefly see how to setup a dedicated repository host to backup an Advanced Server 3-nodes cluster.


The repository host will be called backup-srv and the 3 Advanced Server nodes in Streaming Replication: pg1-srv, pg2-srv, pg3-srv. All the nodes will be running on CentOS 7.

If you’re familiar with Vagrant, here’s a simple Vagrantfile to initiate 4 virtual machines using those names:

# Vagrantfile
Vagrant.configure(2) do |config|
    config.vm.box = 'centos/7'
    config.vm.provider 'libvirt' do |lv|
        lv.cpus = 1
        lv.memory = 1024
    end

    nodes  = 'backup-srv', 'pg1-srv', 'pg2-srv', 'pg3-srv'
    nodes.each do |node|
        config.vm.define node do |conf|
            conf.vm.hostname = node
        end
    end
end

Installation

First of all, pgBackRest and Advanced Server will both require some dependencies located in the EPEL repository. If not already done on your system, add it:

$ sudo yum install -y epel-release

Then, to install Advanced Server on pg1-srv, pg2-srv and pg3-srv, please refer to the official documentation.

In short, install the EDB repository configuration package:

$ sudo yum -y install https://yum.enterprisedb.com/edbrepos/edb-repo-latest.noarch.rpm

Replace the USERNAME:PASSWORD variable in the following command with the username and password of a registered EDB user:

$ sudo sed -i "s@<username>:<password>@USERNAME:PASSWORD@" /etc/yum.repos.d/edb.repo

Update the cache and install Advanced Server:

$ sudo yum makecache
$ sudo yum -y install edb-as13-server

On backup-srv, update the cache and install Advanced Server libs:

$ sudo yum makecache
$ sudo yum -y install edb-as13-server-libs

Now, install pgBackRest and check its version:

$ sudo yum install -y pgbackrest
$ sudo -u postgres pgbackrest version
pgBackRest 2.31

If the latest release package couldn’t be found in the EDB repository, you might need to configure the PGDG yum repositories:

$ sudo yum install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/\
pgdg-redhat-repo-latest.noarch.rpm

Finally, create a basic Advanced Server instance on pg1-srv:

$ sudo -i
root# PGSETUP_INITDB_OPTIONS="-E UTF-8 --data-checksums" /usr/edb/as13/bin/edb-as-13-setup initdb
root# systemctl enable edb-as-13
root# systemctl start edb-as-13

Create a dedicated user on the repository host

The pgbackrest user is created to own the backups and archives repository. Any user can own the repository but it is best not to use postgres or enterprisedb to avoid confusion.

Create the user and the repository location on backup-srv:

$ sudo groupadd pgbackrest
$ sudo adduser -g pgbackrest -n pgbackrest
$ sudo chown pgbackrest: /var/log/pgbackrest
$ sudo mkdir /backup_space
$ sudo chown pgbackrest: /backup_space

For the purpose of this post, we’ve created /backup_space to store locally our backups and archives. The repository can be located on the various supported types as described in the configuration official documentation.

Change directories ownership

Since we’ll execute pgBackRest commands using the enterprisedb system-user on pg1-srv, pg2-srv and pg3-srv, change the pgBackRest default directories ownership:

$ sudo chown -R enterprisedb: /var/lib/pgbackrest
$ sudo chown -R enterprisedb: /var/log/pgbackrest
$ sudo chown -R enterprisedb: /var/spool/pgbackrest

Setup password-less SSH

pgBackRest requires a password-less SSH connection to enable communication between the hosts.

Create the backup-srv key pair:

$ sudo -u pgbackrest ssh-keygen -N "" -t rsa -b 4096 -f /home/pgbackrest/.ssh/id_rsa
$ sudo -u pgbackrest restorecon -R /home/pgbackrest/.ssh

Perform the same operation on all the Advanced Server nodes and authorize the public key from the backup-srv:

$ sudo -u enterprisedb ssh-keygen -N "" -t rsa -b 4096 -f /var/lib/edb/.ssh/id_rsa
$ sudo -u enterprisedb restorecon -R /var/lib/edb/.ssh
$ ssh root@backup-srv cat /home/pgbackrest/.ssh/id_rsa.pub | \
    sudo -u enterprisedb tee -a /var/lib/edb/.ssh/authorized_keys

Authorize the enterprisedb user public keys on the backup-srv:

$ ssh root@pg1-srv cat /var/lib/edb/.ssh/id_rsa.pub | \
    sudo -u pgbackrest tee -a /home/pgbackrest/.ssh/authorized_keys

$ ssh root@pg2-srv cat /var/lib/edb/.ssh/id_rsa.pub | \
    sudo -u pgbackrest tee -a /home/pgbackrest/.ssh/authorized_keys

$ ssh root@pg3-srv cat /var/lib/edb/.ssh/id_rsa.pub | \
    sudo -u pgbackrest tee -a /home/pgbackrest/.ssh/authorized_keys

To test the connection:

# From the Advanced Server nodes
$ sudo -u enterprisedb ssh pgbackrest@backup-srv

# From the backup server
$ sudo -u pgbackrest ssh enterprisedb@pg1-srv
$ sudo -u pgbackrest ssh enterprisedb@pg2-srv
$ sudo -u pgbackrest ssh enterprisedb@pg3-srv

In case you’d use Vagrant boxes, it might be needed to enable the SSH password authentication to proceed with the key exchange:

$ sudo -i
root# sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/g' /etc/ssh/sshd_config    
root# systemctl restart sshd.service
root# passwd

Configuration

We’ll now prepare the configuration for our stanza called demo.

The stanza name is totally up to you. It is often tempting to name the stanza after the primary instance but a better name describes the databases contained in it. Because the stanza name will be used for the primary and all replicas it is more appropriate to choose a name that describes the actual function of the cluster, such as app or dw, rather than the local instance name, such as main or prod.

Update the backup-srv pgBackRest configuration file:

# /etc/pgbackrest.conf
[global]
repo1-path=/backup_space
repo1-retention-full=2
log-level-console=info
log-level-file=debug
start-fast=y
delta=y

[demo]
pg1-host=pg1-srv
pg1-host-user=enterprisedb
pg1-path=/var/lib/edb/as13/data

Update the pg1-srv pgBackRest configuration file:

# /etc/pgbackrest.conf
[global]
repo1-host=backup-srv
repo1-host-user=pgbackrest
log-level-console=info
log-level-file=debug
delta=y

[demo]
pg1-path=/var/lib/edb/as13/data
pg1-user=enterprisedb
pg1-port=5444 

Configure archiving in the postgresql.conf file:

listen_addresses = '*'
archive_mode = on
archive_command = 'pgbackrest --stanza=demo archive-push %p'

The Advanced Server instance must be restarted after making these changes and before performing a backup.

$ sudo systemctl restart edb-as-13

Let’s finally create the stanza and check the configuration on the backup-srv:

$ sudo -iu pgbackrest pgbackrest --stanza=demo stanza-create
...
P00   INFO: stanza-create command end: completed successfully

$ sudo -iu pgbackrest pgbackrest --stanza=demo check
...
P00   INFO: check command end: completed successfully

Perform a backup

Let’s take our first backup on the backup-srv from the pg1-srv primary server:

$ sudo -iu pgbackrest pgbackrest --stanza=demo --type=full backup
P00   INFO: backup command begin 2.31: ...
P00   INFO: execute non-exclusive pg_start_backup(): backup begins after the requested immediate checkpoint completes
P00   INFO: backup start archive = 000000010000000000000004, lsn = 0/4000028
P00   INFO: full backup size = 49.9MB
P00   INFO: execute non-exclusive pg_stop_backup() and wait for all WAL segments to archive
P00   INFO: backup stop archive = 000000010000000000000004, lsn = 0/4000138
P00   INFO: check archive for segment(s) 000000010000000000000004:000000010000000000000004
P00   INFO: new backup label = 20210114-160602F
P00   INFO: backup command end: completed successfully
P00   INFO: expire command begin 2.31: ...
P00   INFO: expire command end: completed successfully

The info command can be executed from any server where pgBackRest is correctly configured:

# From the Advanced Server nodes
$ sudo -iu enterprisedb pgbackrest --stanza=demo info
stanza: demo
    status: ok
    cipher: none

    db (current)
        wal archive min/max (13-1): 000000010000000000000002/000000010000000000000004

        full backup: 20210114-160602F
            timestamp start/stop: 2021-01-14 16:06:02 / 2021-01-14 16:06:28
            wal start/stop: 000000010000000000000004 / 000000010000000000000004
            database size: 49.9MB, backup size: 49.9MB
            repository size: 8MB, repository backup size: 8MB

# From the backup server
$ sudo -iu pgbackrest pgbackrest --stanza=demo info
stanza: demo
    status: ok
    cipher: none

    db (current)
        wal archive min/max (13-1): 000000010000000000000002/000000010000000000000004

        full backup: 20210114-160602F
            timestamp start/stop: 2021-01-14 16:06:02 / 2021-01-14 16:06:28
            wal start/stop: 000000010000000000000004 / 000000010000000000000004
            database size: 49.9MB, backup size: 49.9MB
            repository size: 8MB, repository backup size: 8MB

Prepare the servers for Streaming Replication

On the pg1-srv server, create a specific user for the replication:

$ sudo -iu enterprisedb psql -d postgres
postgres=# CREATE ROLE replic_user WITH LOGIN REPLICATION PASSWORD 'mypwd';

Configure pg_hba.conf:

host   replication   replic_user   pg2-srv   md5
host   replication   replic_user   pg3-srv   md5

Reload configuration:

$ sudo systemctl reload edb-as-13

Configure ~enterprisedb/.pgpass on pg2-srv and pg3-srv:

$ echo "*:*:replication:replic_user:mypwd" >> ~enterprisedb/.pgpass
$ chown enterprisedb: ~enterprisedb/.pgpass
$ chmod 0600 ~enterprisedb/.pgpass

Setup the standby servers

Configure /etc/pgbackrest.conf on pg2-srv and pg3-srv:

[global]
repo1-host=backup-srv
repo1-host-user=pgbackrest
log-level-console=info
log-level-file=debug
delta=y

[demo]
pg1-path=/var/lib/edb/as13/data
pg1-user=enterprisedb
pg1-port=5444
recovery-option=primary_conninfo=host=pg1-srv user=replic_user port=5444

As you may notice, it is the same configuration as on pg1-srv with the extra recovery-option. The idea is to automatically configure the Streaming Replication connection string with the restore command.

Then, make sure the configuration is correct by executing the info command. It should print the same output as above.

Restore the backup taken from the pg1-srv server on pg2-srv and pg3-srv:

$ sudo -iu enterprisedb pgbackrest --stanza=demo --type=standby --no-delta restore
P00   INFO: restore command begin 2.31: ...
P00   INFO: restore backup set 20210114-160602F
P00   INFO: write updated /var/lib/edb/as13/data/postgresql.auto.conf
P00   INFO: restore global/pg_control (performed last to ensure aborted restores cannot be started)
P00   INFO: restore command end: completed successfully

The restore will add extra information to the postgresql.auto.conf file:

# Recovery settings generated by pgBackRest restore...
primary_conninfo = 'host=pg1-srv user=replic_user port=5444'
restore_command = 'pgbackrest --stanza=mycluster archive-get %f "%p"'

The --type=standby option creates the standby.signal needed for Advanced Server to start in standby mode. All we have to do now is to start the Advanced Server instances:

$ sudo systemctl enable edb-as-13
$ sudo systemctl start edb-as-13

If the replication setup is correct, you should see those processes on the pg1-srv server:

$ sudo -iu enterprisedb ps -o pid,cmd fx
  PID CMD
 2868 ps -o pid,cmd fx
  653 /usr/edb/as13/bin/edb-postmaster -D /var/lib/edb/as13/data
  ... 
 2781  \_ postgres: walsender replic_user ... streaming ...
 2784  \_ postgres: walsender replic_user ... streaming ...

We now have a 3-nodes cluster working with Streaming Replication and archives recovery as safety net.


Take backups from the standby servers

Add the following settings to the pgBackRest configuration file on backup-srv, in the [demo] stanza section:

pg2-host=pg2-srv
pg2-host-user=enterprisedb
pg2-path=/var/lib/edb/as13/data
pg3-host=pg3-srv
pg3-host-user=enterprisedb
pg3-path=/var/lib/edb/as13/data
backup-standby=y

Now, perform a backup fetching the data from the first standby server found in the configuration:

$ sudo -iu pgbackrest pgbackrest --stanza=demo --type=full backup
P00   INFO: backup command begin 2.31: ...
P00   INFO: execute non-exclusive pg_start_backup(): backup begins after the requested immediate checkpoint completes
P00   INFO: backup start archive = ..., lsn = ...
P00   INFO: wait for replay on the standby to reach ...
P00   INFO: replay on the standby reached ...
P00   INFO: full backup size = 49.9MB
P00   INFO: execute non-exclusive pg_stop_backup() and wait for all WAL segments to archive
P00   INFO: backup stop archive = ..., lsn = ...
P00   INFO: check archive for segment(s) ...
P00   INFO: new backup label = ...
P00   INFO: backup command end: completed successfully
P00   INFO: expire command begin 2.31: ...
P00   INFO: expire command end: completed successfully

Conclusion

As you can see, the backup command is executed from the repository host and the restore command on the Advanced Server nodes.

The repository host may even be configured to backup multiple Advanced Server clusters by setting up multiple stanzas.