In this brief blog post, we will talk about Barman cloud utilities, which greatly ease the process of storing backups on cloud platforms like GCP, AWS, Azure, etc. Backups are of paramount importance, and in PostgreSQL, we also need to retain the WAL files, which can be used for various purposes like incremental backups or some PITR/ad-hoc recoveries. These requirements can be fulfilled at an instant pace with the help of these cloud-native utilities, which we are going to discuss next.
In order to use the tools, we need to install/set them up in the Postgres environment where we plan to execute the backup operation.
Installation of Barman cloud utilities
For the demo purpose, I installed it on Red Hat 9, but it can be installed on other OS platforms as well.
1 2 | shell> dnf install barman shell> dnf install barman-cli |
Note – For Red Hat distribution “barman-cli-cloud” package automatically included in “barman-cli” package. For other platforms like Debian/Ubuntu we need to install “barman-cli-cloud” also.
We also need to resolve certain dependencies based on the environment.
1 2 3 | shell> dnf install python3-pip ### for GCP shell> pip3 install google-cloud-storage ### for GCP shell> pip3 install boto3 ### for AWS |
Authentication
GCP (Google Cloud Platform)
We can download a JSON-based key (gcs-key.json) from the GCP service account for the associated user/account. We also need to make sure the folder storage role and other permissions are attached to the target bucket for writing, reading, listing, and other bucket-related events.
The authentication is supported only via the environment variable “GOOGLE_APPLICATION_CREDENTIALS” as below for the GCP platform.
1 2 | shell> su postgres bash> export GOOGLE_APPLICATION_CREDENTIALS="/var/lib/pgsql/gcs-key.json" |
We can also persist the above changes by putting them under “~/.bashrc” OR “~/.bash_profile” of the “postgres“ user.
1 2 3 | shell> su postgres bash> cat ~/.bashrc bash> export GOOGLE_APPLICATION_CREDENTIALS="/var/lib/pgsql/gcs-key.json" |
1 2 3 4 5 6 7 8 9 | bash> cat ~/.bash_profile [ -f /etc/profile ] && source /etc/profile PGDATA=/var/lib/pgsql/17/data export PGDATA export GOOGLE_APPLICATION_CREDENTIALS="/var/lib/pgsql/gcs-key.json" # If you want to customize your settings, # Use the file below. This is not overridden # by the RPMS. |
1 | bash> source ~/.bash_profile |
AWS (Amazon Web Services)
For AWS, we need to install the “awscli tool” in order to set up the profile and authentication to interact with the S3/Bucket.
1 | shell> dnf install awscli |
1 2 3 4 5 6 7 | shell> su postgres bash> aws configure --profile barman-cloud AWS Access Key ID [None]: xxx AWS Secret Access Key [None]: xxx Default region name [None]: us-east-1 Default output format [None]: json |
The details can be verified as below.
1 2 3 4 5 | bash> cat ~/.aws/credentials [barman-cloud] aws_access_key_id = xxx aws_secret_access_key = xxx |
Backup
Taking a full backup is just a matter of executing the below single command.
1 2 | shell> su postgres bash> barman-cloud-backup --cloud-provider google-cloud-storage gs://ajtestbucket25/backup/ pg17 --verbose |
Note – Here “pg17” is the server name which will create the folder with the same name in the bucket as well. It’s not mandatory to use the exact name and we can use any naming here. This will be required in fetching the backup/recovery related details and information.
Output:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 2025-03-05 16:36:48,713 [18870] INFO: Starting backup '20250305T163648' 2025-03-05 16:36:48,796 [18870] INFO: Uploading 'pgdata' directory '/var/lib/pgsql/17/data' as 'data.tar' 2025-03-05 16:36:49,630 [18870] INFO: Uploading 'pg_control' file from '/var/lib/pgsql/17/data/global/pg_control' to 'data.tar' with path 'global/pg_control' 2025-03-05 16:36:49,630 [18870] INFO: Stopping backup '20250305T163648' 2025-03-05 16:36:49,710 [18870] INFO: Restore point 'barman_20250305T163648' successfully created 2025-03-05 16:36:49,710 [18870] INFO: Uploading 'backup_label' file to 'data.tar' with path 'backup_label' 2025-03-05 16:36:49,710 [18870] INFO: Marking all the uploaded archives as 'completed' 2025-03-05 16:36:49,730 [18886] INFO: Upload process started (worker 0) 2025-03-05 16:36:49,830 [18886] INFO: Uploading 'backup/pg17/base/20250305T163648/data.tar', part '1' (worker 0) 2025-03-05 16:36:51,883 [18886] INFO: Completing 'backup/pg17/base/20250305T163648/data.tar' (worker 0) 2025-03-05 16:36:51,884 [18870] INFO: Calculating backup statistics 2025-03-05 16:36:51,885 [18870] INFO: Uploading 'backup/pg17/base/20250305T163648/backup.info' 2025-03-05 16:36:52,082 [18870] INFO: Backup end at LSN: 0/C000158 (00000001000000000000000C, 00000158) 2025-03-05 16:36:52,083 [18870] INFO: Backup completed (start time: 2025-03-05 16:36:48.713561, elapsed time: 3 seconds) 2025-03-05 16:36:52,085 [18886] INFO: Upload process stopped (worker 0) |
We have some extra parameters to enhance/control the whole backup and upload process.
1 2 3 4 5 | Compression options such as ( -z / --gzip, -j / --bzip2), --snappy etc) Parallel upload with (-J / --jobs) option. Chunk size and limit control with (--min-chunk-size) Data upload bandwidth (--max-bandwidth) Encryption while uploading (-e / --encryption) |
The above example was taken from the GCP platform. For others, like AWS and Azure, all we need to do is replace the “–cloud-provider” option with one of the values below.
- aws-s3
- azure-blob-storage.
- google-cloud-storage.
Backup status and listing
By using the “barman-cloud-backup-list” utility, we can list all the backups.
1 | bash> barman-cloud-backup-list --cloud-provider google-cloud-storage gs://ajtestbucket25/backup/ pg17 |
Output:
1 2 | Backup ID End Time Begin Wal Archival Status Name 20250305T163648 2025-03-05 16:36:49 00000001000000000000000C |
To gain more insight into the particular backup, we can use the “barman-cloud-backup-show” utility. This will show all the metadata details about the backup.
1 | bash> barman-cloud-backup-show --cloud-provider google-cloud-storage gs://ajtestbucket25/backup/ pg17 20250302T160056 |
Output:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | Backup 20250305T163648: Server Name : cloud System Id : 7478359102289506833 Status : DONE PostgreSQL Version : 170004 PGDATA directory : /var/lib/pgsql/17/data Estimated Cluster Size : 179.7 MiB Server information: Checksums : off WAL summarizer : off Base backup information: Timeline : 1 Begin WAL : 00000001000000000000000C End WAL : 00000001000000000000000C Begin time : 2025-03-05 16:36:48.747980+00:00 End time : 2025-03-05 16:36:49.631210+00:00 Copy time : 2 seconds Begin Offset : 40 End Offset : 344 Begin LSN : 0/C000028 End LSN : 0/C000158 |
WAL archiving/backup
Preserving WAL files is an important consideration for PITR purposes and can also be used as an incremental backup.
To enable WAL archiving, we can use the “barman-cloud-wal-archive” utility in the Postgres “archive_command“ directly. This will copy the WAL files over the remote buckets.
1 2 | archive_mode = on archive_command = 'barman-cloud-wal-archive --cloud-provider google-cloud-storage gs://ajtestbucket25/backup/ pg17 %p' |
For the changes to take effect, we need to restart the service.
1 | shell> systemctl restart postgresql-17 |
Verify the configuration change:
1 2 3 4 5 6 7 | postgres=# show archive_mode; -[ RECORD 1 ]+--- archive_mode | on postgres=# show archive_command; -[ RECORD 1 ]---+--------------------------------------------------------------------------------------------------- archive_command | barman-cloud-wal-archive --cloud-provide google-cloud-storage gs://ajtestbucket25/backup/ pg17 %p |
The utility can be run manually also, especially handy for troubleshooting purposes or some quick testing.
1 2 | shell> su postgres bash> barman-cloud-wal-archive --cloud-provider google-cloud-storage gs://ajtestbucket25/backup/ pg17 /var/lib/pgsql/17/data/pg_wal/00000001000000000000000F -vvv |
Output:
1 2 3 4 5 6 7 8 | .. 2025-03-05 17:40:04,030 [84967] DEBUG: upload_fileobj to backup/pg17/wals/0000000100000000/00000001000000000000000F 2025-03-05 17:40:04,030 [84967] DEBUG: blob initiated 2025-03-05 17:40:04,082 [84967] DEBUG: https://storage.googleapis.com:443 "POST /upload/storage/v1/b/ajtestbucket25/o?uploadType=resumable HTTP/1.1" 200 0 2025-03-05 17:40:04,668 [84967] DEBUG: https://storage.googleapis.com:443 "PUT /upload/storage/v1/b/ajtestbucket25/o?uploadType=resumable&upload_id=AHMx-iGrMDn3qeQuIUgIrOx6yO5IbEziVRM9mlZ-kwWHSQST_dsN2AjwLhYk_rQWbOPjicyLte5K7vwNsVDoXMxtiJMzrRSWlyXC7ZfoXvePRA HTTP/1.1" 200 1012 ... |
To verify the WALs, we can either directly check the bucket or list the files from the invoking source itself.
1 | bash> gsutil ls -R gs://ajtestbucket25/ |
Output:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | ... gs://ajtestbucket25/backup/pg17/wals/0000000100000000/: gs://ajtestbucket25/backup/pg17/wals/0000000100000000/00000001000000000000000D gs://ajtestbucket25/backup/pg17/wals/0000000100000000/00000001000000000000000E gs://ajtestbucket25/backup/pg17/wals/0000000100000000/00000001000000000000000F gs://ajtestbucket25/backup/pg17/wals/0000000100000000/000000010000000000000010 gs://ajtestbucket25/backup/pg17/wals/0000000100000000/000000010000000000000011 gs://ajtestbucket25/backup/pg17/wals/0000000100000000/000000010000000000000012 gs://ajtestbucket25/backup/pg17/wals/0000000100000000/000000010000000000000013 gs://ajtestbucket25/backup/pg17/wals/0000000100000000/000000010000000000000014 gs://ajtestbucket25/backup/pg17/wals/0000000100000000/000000010000000000000015 ... |
Similarly with WAL archiving as well we have some extra options to control and better perform the archiving process.
1 2 3 4 | Compression options (-z / --gzip, -j / --bzip2, --xz, --snappy, --zstd, --lz4). Encryption while uploading ( -e / --encryption). Defining max block size (--max-block-size) in case of parallel chunk uploading. Max parallel chunks upload limit with (--max-concurrency) |
Restoring backup
First, we need to stop the database service and empty the existing data directory “/var/lib/pgsql/17/data/”. Probably better to take a backup of the data directory before removals.
1 2 | shell> systemctl stop postgresql-17 shell> rm -rf /var/lib/pgsql/17/data |
Data restoration also comes very handy with the help of “barman-cloud-restore” utility. All we need to do is pass the backup ID “20250305T163648 “to the command.
1 2 | shell> su postgres bash > barman-cloud-restore --cloud-provider google-cloud-storage gs://ajtestbucket25/backup/ pg17 20250302T160056 /var/lib/pgsql/17/data/ -vv |
Output:
1 2 3 4 5 6 7 8 9 10 11 | ... 2025-03-05 17:46:37,593 [85386] INFO: Restoring from backup_id: 20250305T163648 2025-03-05 17:46:37,593 [85386] DEBUG: list_bucket: backup/pg17/base/20250305T163648/, / 2025-03-05 17:46:37,621 [85386] DEBUG: https://storage.googleapis.com:443 "GET /storage/v1/b/ajtestbucket25/o?projection=noAcl&prefix=backup%2Fpg17%2Fbase%2F20250305T163648%2F&delimiter=%2F&prettyPrint=false HTTP/1.1" 200 1787 2025-03-05 17:46:37,622 [85386] DEBUG: objects ['backup/pg17/base/20250305T163648/backup.info', 'backup/pg17/base/20250305T163648/data.tar'] 2025-03-05 17:46:37,622 [85386] DEBUG: dirs [] 2025-03-05 17:46:37,622 [85386] INFO: Found file from backup '20250305T163648' of server 'pg17': backup/pg17/base/20250305T163648/data.tar 2025-03-05 17:46:37,622 [85386] DEBUG: Extracting backup/pg17/base/20250305T163648/data.tar to /var/lib/pgsql/17/data/ (no compression) 2025-03-05 17:46:37,622 [85386] DEBUG: GCS.remote_open ... |
Once the files are copied to the target data directory “/var/lib/pgsql/17/data/,” we need to run the recovery process to ensure a consistent restore.
1) create the recovery signal file inside the data directory.
1 | bash> touch /var/lib/pgsql/17/data/recovery.signal |
2) Make sure to disable or comment out the archive_command temporarily to prevent writing to the same bucket path again.
1 | #archive_command = 'barman-cloud-wal-archive --cloud-provider google-cloud-storage gs://ajtestbucket25/backup/ pg17 %p' |
Restoring WAL
The “barman-cloud-wal-restore” utility fetches the required remote WAL file and copies it to the target “pg_wal” folder again. This works the same as the native “restore_command.“
3) Next, add the restore_command and set the “recovery_target_timeline” in “/var/lib/pgsql/17/data/postgresql.conf” file.
1 2 | restore_command = 'barman-cloud-wal-restore --cloud-provider google-cloud-storage gs://ajtestbucket25/backup/ pg17 %f %p' recovery_target_timeline='latest' |
We can also do a quick test by running the direct “barman-cloud-wal-restore“ command.
1 | bash> barman-cloud-wal-restore --cloud-provider google-cloud-storage gs://ajtestbucket25/backup/ pg17 00000001000000000000000D /var/lib/pgsql/17/data/pg_wal/ -vv |
4) Finally, start the Postgres service and verify the tables and data.
1 | shell> systemctl start postgresql-17 |
Final thoughts
Although we already have the native Barman solution for taking remote backups, with the introduction of the cloud-native tool “barman-cloud-*,” running backups over different cloud platforms is super handy now. The recovery process itself is pretty simple. All we need to do is restore the backup + desired WAL file. This setup also eliminates the need to have a separate Barman server and a set of other configurations, as we are directly running the tools in the Postgres environment. It’s still possible to use the cloud features with the native Barman server-style setup by using various hook scripts.