# create VM with Rocky Linux 9 dd if=/dev/zero of=/vm/ssd0/aquaris/boot_01.img bs=1G count=1 dd if=/dev/zero of=/vm/ssd0/aquaris/root_01.img bs=1G count=8 dd if=/dev/zero of=/vm/ssd0/aquaris/swap_01.img bs=1G count=2 dd if=/dev/zero of=/vm/ssd0/aquaris/app_01.img bs=1G count=8 virt-install \ --graphics vnc,password=secret,listen=0.0.0.0 \ --name=aquaris \ --vcpus=2 \ --memory=4096 \ --network bridge=br0 \ --network bridge=br0 \ --cdrom=/vm/hdd0/_kit_/Rocky-9.3-x86_64-minimal.iso \ --disk /vm/ssd0/aquaris/boot_01.img \ --disk /vm/ssd0/aquaris/root_01.img \ --disk /vm/ssd0/aquaris/swap_01.img \ --disk /vm/ssd0/aquaris/app_01.img \ --os-variant=rocky9 # VM network setup after creation nmcli connection show nmcli connection show --active nmcli connection modify enp1s0 ipv4.address 192.168.0.101/24 nmcli connection modify enp1s0 ipv4.method manual ipv6.method ignore nmcli connection modify enp1s0 ipv4.gateway 192.168.0.1 nmcli connection modify enp1s0 ipv4.dns 192.168.0.8 nmcli connection modify enp1s0 ipv4.dns-search swgalaxy nmcli connection modify enp2s0 ipv4.address 192.168.1.101/24 ipv4.method manual ipv6.method ignore # list host interfaces hostname -I # set host name hostnamectl hostname aquaris.swgalaxy # install packages dnf install -y gcc make automake readline-devel zlib-devel openssl-devel libicu-devel.x86_64 dnf install -y zip.x86_64 tar.x86_64 libzip.x86_64 unzip.x86_64 bzip2.x86_64 bzip2-devel.x86_64 pigz.x86_64 dnf install -y wget.x86_64 lsof.x86_64 bind-utils tree.x86_64 python3-devel.x86_64 rsync.x86_64 # add data and backup disks # on VM get next letter for devices lsblk # on Dom0 create and attach the disk to VM dd if=/dev/zero of=/vm/ssd0/aquaris/data_01.img bs=1G count=8 dd if=/dev/zero of=/vm/ssd0/aquaris/backup_01.img bs=1G count=4 virsh attach-disk aquaris /vm/ssd0/aquaris/data_01.img vde --driver qemu --subdriver raw --targetbus virtio --persistent virsh attach-disk aquaris /vm/ssd0/aquaris/backup_01.img vdf --driver qemu --subdriver raw --targetbus virtio --persistent # to list the disk of VM virsh domblklist aquaris --details # on VM create partitions, format and mount devices fdisk /dev/vde fdisk /dev/vdf lsblk pvs pvcreate /dev/vde1 pvcreate /dev/vdf1 vgs vgcreate vgdata /dev/vde1 vgcreate vgbackup /dev/vdf1 vgs lvs lvcreate -n data -l 100%FREE vgdata lvcreate -n backup -l 100%FREE vgbackup lvs mkfs.xfs /dev/mapper/vgdata-data mkfs.xfs /dev/mapper/vgbackup-backup mkdir -p /data /backup echo "/dev/mapper/vgdata-data /data xfs defaults 1 1" >> /etc/fstab echo "/dev/mapper/vgbackup-backup /backup xfs defaults 1 1" >> /etc/fstab systemctl daemon-reload mount -a df -hT # build PostgreSQL from sources mkdir -p /app/postgres/product/16.2 mkdir -p /app/staging_area cd /app/staging_area wget https://ftp.postgresql.org/pub/source/v16.2/postgresql-16.2.tar.gz gunzip -c postgresql-16.2.tar.gz | tar -xvf - cd postgresql-16.2 ./configure \ --prefix=/app/postgres/product/16.2 \ --with-ssl=openssl make make install # create user postres and change owner from binaries, data and backup directories groupadd postgres useradd postgres -G postgres -g postgres chown -R postgres:postgres /app /data /backup # create/opdate .bash_profile for postgres user: export PS1="\u@\h:\w> " alias listen='lsof -i -P | grep -i "listen"' alias pgenv='source /app/postgres/admin/scripts/pgenv' # create PostgreSQL instance on port 5501 mkdir -p /app/postgres/admin mkdir -p scripts cd /app/postgres/admin mkdir -p aquaris_5501/divers mkdir -p aquaris_5501/log mkdir -p aquaris_5501/scripts # create a script to source PostgeSQL instance varaiables cat <<'EOF' > /app/postgres/admin/scripts/pgenv export PGPORT=$1 export MYHOST=$(hostname -s) export PGHOME=/app/postgres/product/16.2 export PGDATA=/data/${MYHOST}_${PGPORT} export PGBACKUP=/backup/${MYHOST}_${PGPORT} export PGLOG=/app/postgres/admin/${MYHOST}_${PGPORT}/log/${MYHOST}_${PGPORT}.log export LD_LIBRARY_PATH=$PGHOME/lib:$LD_LIBRARY_PATH export PATH=$PGHOME/bin:$PATH EOF # sinitialize and start PostgreSQL server pgenv 5501 initdb -D $PGDATA # update PostgreSQL instance configuration file # $PGDATA/postgresql.conf listen_addresses = '*' port = 5501 # update $PGDATA/pg_hba.conf in order to allow remote connections using a password cat <<'EOF' >> $PGDATA/pg_hba.conf host all all all md5 EOF # start PostgreSQL instance pg_ctl start -D $PGDATA -l $PGLOG or pg_ctl start --pgdata $PGDATA --log $PGLOG # stop PostgreSQL instance pg_ctl stop -m immediate # create a database + an owner from this database psql postgres=# create role jawa login password 'secret'; postgres=# create database jawa; postgres=# alter database jawa owner to jawa; postgres=# \l postgres=# \du # test connection psql -p 5501 -h aquaris -U jawa # create users for barman: barman(superuser) and streaming_barman(replication) createuser --superuser --replication -P barman createuser --replication -P streaming_barman # update $PGDATA/pg_hba.conf in order to allow replication for streaming_barman user cat <<'EOF' >> $PGDATA/pg_hba.conf host replication streaming_barman all md5 EOF # ensure that following parameter are >10 postgres=# Show max_wal_senders; postgres=# Show max_replication_slots; # otherwise update postgres=# ALTER SYSTEM SET max_wal_senders = 10; postgres=# ALTER SYSTEM SET max_replication_slots = 10;. # Barman can be installed on a remote machine where PosgeSQL binaries are installed # customoze ~/.bashrc on remote machine cat <<'EOF' >> ~/.bashrc export PS1="\u@\h:\w> " alias listen='lsof -i -P | grep -i "listen"' export POSTGRES_HOME=/app/postgres/product/16.2 export LD_LIBRARY_PATH=$POSTGRES_HOME/lib:$LD_LIBRARY_PATH export PATH=$POSTGRES_HOME/bin:$PATH EOF # barman install mkdir /backup/barman mkdir /app/barman cd /app/barman mkdir product conf log run scripts mkdir conf/barman.d mkdir /app/barman/product/barman_3.10.0 python -m venv /app/barman/product/barman_3.10.0 source /app/barman/product/barman_3.10.0/bin/activate python -m pip install --upgrade pip pip install psycopg2 pip install barman barman -v # optinally, activate Barman in .bash_profile cat <<'EOF' >> ~/.bash_profile # Activate Barman source /app/barman/product/barman_3.10.0/bin/activate EOF # store passwords cat <<'EOF' >>~/.pgpass aquaris:5501:*:barman:secret aquaris:5501:*:streaming_barman:secret EOF chmod 0600 ~/.pgpass # test connection psql -h aquaris -p 5501 -U barman -d postgres psql -h aquaris -p 5501 -U streaming_barman -d postgres # create barman global configuration file cat <<'EOF' > /app/barman/conf/barman.conf [barman] ; System user barman_user = postgres ; Directory of configuration files. Place your sections in separate files with .conf extension ; For example place the 'main' server section in /etc/barman.d/main.conf configuration_files_directory = /app/barman/conf/barman.d ; Main directory barman_home = /backup/barman ; Locks directory - default: %(barman_home)s ;barman_lock_directory = /app/barman/run ; Log location log_file = /app/barman/log/barman.log ; Log level (see https://docs.python.org/3/library/logging.html#levels) log_level = INFO ; Default compression level: possible values are None (default), bzip2, gzip, pigz, pygzip or pybzip2 compression = pigz EOF # for the global configuration file, create a symlync .barman.conf in the home directory ln -s /app/barman/conf/barman.conf ~/.barman.conf # target postgres instance example cat <<'EOF' > /app/barman/conf/barman.d/aquaris_5501.conf [aquaris_5501] description = "PostgreSQL instance on aquaris, port 5501" conninfo = host=aquaris port=5501 user=barman dbname=postgres streaming_conninfo = host=aquaris port=5501 user=streaming_barman dbname=postgres backup_method = postgres streaming_archiver = on slot_name = barman create_slot = auto retention_policy = REDUNDANCY 4 EOF # create replication slot barman receive-wal --create-slot aquaris_5501 # create barman CRON script cat <<'EOF' > /app/barman/scripts/barman_cron # Setup environement source ~/.bash_profile # Run barmab CRON tasks barman cron EOF chmod +x /app/barman/scripts/barman_cron # scedule CRON script in crontab every 1 minute crontab -l * * * * * /app/barman/scripts/barman_cron > /app/barman/log/barman_cron.log # force a switch wal on target PostgreSQL instance barman switch-wal --force --archive aquaris_5501 # backup PostgreSQL instance and wait for all the required WAL files to be archived barman backup aquaris_5501 --wait # list registered PostgeSQL servers barman list-servers # list backup of one of all servers barman list-backups all barman list-backups aquaris_5501 # list files of backup required to restore a minimal consistent image # one or more WAL will be included barman list-files aquaris_5501 --target standalone 20240223T165330 # list only WAL that can be used in addition with the backup # that will include necessary WAL to restore a consistent image (as in previous command) + all streamed (and automatically compressed) since the backup barman list-files aquaris_5501 --target wal 20240223T165330 # list all files (base + WAL) availablle for restiore since the backup barman list-files aquaris_5501 --target full 20240223T165330 # show backup informations barman show-backup aquaris_5501 20240223T165330 # verify cecksums of backup files barman verify-backup aquaris_5501 20240220T174149 *************************************************** barman \ recover --remote-ssh-command 'ssh sembla' \ aquaris_5501 latest \ /data/restore barman \ recover --remote-ssh-command 'ssh sembla' \ --get-wal \ aquaris_5501 latest \ /data/restore /app/postgres/product/16.2/bin/pg_ctl \ --pgdata=/data/restore \ -l /tmp/restore.log \ start /app/postgres/product/16.2/bin/pg_ctl \ --pgdata=/data/restore \ -l /tmp/restore.log \ stop barman-wal-restore -U postgres exegol aquaris_5501 --test Bugs Bunny **************************************************