Інкрементальні бекапи postgresql з pgbackrest - курс молодого бійця від розробника

Дисклеймер

Я розробник. Я пишу код, з базою даних взаємодію лише як користувач. Я в жодному разі не претендую на посаду системного адміністратора і, тим більше, dba. Але...

Так сталося, що мені потрібно було організувати резервне копіювання postgresql бази даних. Жодних хмар — тримай SSH і зроби, щоб усе працювало і не просило грошей. Що ми робимо у таких випадках? Правильно, пхаємо pgdump в cron, щодня бекапім все в архів і якщо зовсім розійшлися - відправляємо цей архів кудись подалі.

Цього разу складність полягала в тому, що за планами база мала рости приблизно на +- 100 МБ на день. Зрозуміло, вже через пару тижнів бажання бекапит все pgdump'ом відпаде. Тут на допомогу приходять інкрементальні бекапи.

Цікаво? Ласкаво просимо під кат.

Інкрементальний бекап – різновид резервної копії, коли копіюються не всі файли джерела, а лише нові та змінені з моменту створення попередньої копії.

Як і будь-який розробник, абсолютно не бажаючий (на той момент) розбиратися в тонкощах postgres я хотів знайти зелену кнопку. Ну, знаєте, як у AWS, DigitalOcean: натиснув одну кнопку - отримав реплікацію, натиснув другу - налаштував бекапи, третю - все відкотив на кілька годин тому. Кнопки та красивого GUIшного інструменту я не знайшов. Якщо ви знаєте такий (безкоштовний чи дешевий) – напишіть про це у коментарях.

Гуляючи я знайшов два інструменти pgbarman и pgbackrest. З першим у мене просто не задалося (дуже мізерна документація, намагався все підняти по старовинних мануалах), а ось у другого документація виявилася на рівні, але й не без вади. Щоб спростити роботу тим, хто зіткнеться з подібним завданням і було написано цю статтю.

Дочитавши цю статтю, ви навчитеся робити інкрементальні бекапи, зберігати їх на віддалений сервер (репозиторій з бекапами) і відновлювати їх у разі втрати даних або інших проблем на основному сервері.

Підготовка

Для відтворення мануалу вам знадобляться два VPS. Перший буде сховищем (репозиторієм, на якому лежать бекапи), а другий, власне, сам сервер з postgres (у моєму випадку 11 версія postgres).

Мається на увазі, що на сервері з postgres у вас є root, sudo користувач, користувач postgres і сам postgres встановлений (користувач postgres створюється автоматично при установці postgresql), а на сервері-репозиторії є root і sudo користувач (у мануалі буде використовуватись ім'я користувача pgbackrest) .

Щоб у вас було менше проблем при відтворенні інструкції – курсивом я прописую де, яким користувачем та з якими правами я виконував команду під час написання та перевірки статті.

Установка pgbackrest

Репозиторій (користувач pgbackrest):

1. Завантажуємо архів з pgbackrest та переносимо його вміст у папку /build:

sudo mkdir /build
sudo wget -q -O - 
       https://github.com/pgbackrest/pgbackrest/archive/release/2.18.tar.gz | 
       sudo tar zx -C /build

2. Встановлюємо необхідні для збирання залежності:

sudo apt-get update
sudo apt-get install build-essential libssl-dev libxml2-dev libperl-dev zlib1g-dev 
       libpq-dev

3. Збираємо pgbackrest:

cd /build/pgbackrest-release-2.18/src && sudo ./configure
sudo make -s -C /build/pgbackrest-release-2.18/src

4. Копіюємо виконуваний файл в директорію /usr/bin:

sudo cp /build/pgbackrest-release-2.18/src/pgbackrest /usr/bin
sudo chmod 755 /usr/bin/pgbackrest

5. Pgbackrest потребує наявність perl. Встановлюємо:

sudo apt-get install perl

6. Створюємо директорії для логів, даємо їм певні права:

sudo mkdir -p -m 770 /var/log/pgbackrest
sudo chown pgbackrest:pgbackrest /var/log/pgbackrest
sudo mkdir -p /etc/pgbackrest
sudo mkdir -p /etc/pgbackrest/conf.d
sudo touch /etc/pgbackrest/pgbackrest.conf
sudo chmod 640 /etc/pgbackrest/pgbackrest.conf
sudo chown pgbackrest:pgbackrest /etc/pgbackrest/pgbackrest.conf

7. Перевіряємо:

pgbackrest version

Postgres сервер (sudo користувач або root):

Процес установки pgbackrest на сервері з postgres аналогічний процесу установки на репозиторії (так, pgbackrest повинен стояти на обох серверах), але в 6-му пункті другу та останню команди:

sudo chown pgbackrest:pgbackrest /var/log/pgbackrest
sudo chown pgbackrest:pgbackrest /etc/pgbackrest/pgbackrest.conf

замінюємо на:

sudo chown postgres:postgres /var/log/pgbackrest
sudo chown postgres:postgres /etc/pgbackrest/pgbackrest.conf

Налагодження взаємодії між серверами через passwordless SSH

Для того, щоб pgbackrest коректно працював, необхідно налаштувати взаємодію між сервером postgres і репозиторієм по файлу-ключу.

Репозиторій (користувач pgbackrest):

Створюємо пару ключів:

mkdir -m 750 /home/pgbackrest/.ssh
ssh-keygen -f /home/pgbackrest/.ssh/id_rsa 
       -t rsa -b 4096 -N ""

Увага! Вказані вище команди виконуємо без sudo.

Postgres сервер (sudo користувач або root):

Створюємо пару ключів:

sudo -u postgres mkdir -m 750 -p /var/lib/postgresql/.ssh
sudo -u postgres ssh-keygen -f /var/lib/postgresql/.ssh/id_rsa 
       -t rsa -b 4096 -N ""

Репозиторій (sudo користувач):

Копіюємо публічний ключ postgres сервера на сервер-репозиторій:

(echo -n 'no-agent-forwarding,no-X11-forwarding,no-port-forwarding,' && 
       echo -n 'command="/usr/bin/pgbackrest ${SSH_ORIGINAL_COMMAND#* }" ' && 
       sudo ssh root@<postgres_server_ip> cat /var/lib/postgresql/.ssh/id_rsa.pub) | 
       sudo -u pgbackrest tee -a /home/pgbackrest/.ssh/authorized_keys

На цьому кроці запитає пароль від root користувача. Вводити потрібно саме пароль root користувача postgres сервера!

Postgres сервер (sudo користувач):

Копіюємо публічний ключ репозиторію на сервер з postgres:

(echo -n 'no-agent-forwarding,no-X11-forwarding,no-port-forwarding,' && 
       echo -n 'command="/usr/bin/pgbackrest ${SSH_ORIGINAL_COMMAND#* }" ' && 
       sudo ssh root@<repository_server_ip> cat /home/pgbackrest/.ssh/id_rsa.pub) | 
       sudo -u postgres tee -a /var/lib/postgresql/.ssh/authorized_keys

На цьому кроці запитає пароль від root користувача. Вводити потрібно саме пароль root користувача репозиторію!

перевіряємо:

Репозиторій (root користувач, для чистоти експерименту):

sudo -u pgbackrest ssh postgres@<postgres_server_ip>

Postgres сервер (root користувач, для чистоти експерименту):

sudo -u postgres ssh pgbackrest@<repository_server_ip>

Переконуємось, що без проблем отримуємо доступ.

Налаштування сервера postgres

Postgres сервер (sudo користувач або root):

1. Дозволимо «стукати» на postgres сервер із зовнішніх ip. Для цього відредагуємо файл postgresql.conf (перебуває в папці /etc/postgresql/11/main), додавши в нього рядок:

listen_addresses = '*'

Якщо такий рядок вже є, або розкоментуйте його, або встановіть значення параметра як '*'.

У файлі pg_hba.conf (так само знаходиться в папці /etc/postgresql/11/main) додаємо наступні рядки:

hostssl  all  all  0.0.0.0/0  md5
host  all  all  0.0.0.0/0  md5

де:

hostssl/host - подключаемся через SSL (или нет)
all - разрешаем подключение ко всем базам
all - имя пользователя, которому разрешаем подключение (всем)
0.0.0.0/0 - маска сети с которой можно подключаться
md5 - способ шифрования пароля

2. Внесемо необхідні налаштування в postgresql.conf (Він знаходиться в папці /etc/postgresql/11/main) для роботи pgbackrest:

archive_command = 'pgbackrest --stanza=main archive-push %p' # Где main - название кластера. При установке postgres автоматически создает кластер main.
archive_mode = on
max_wal_senders = 3
wal_level = replica

3. Внесемо необхідні налаштування у файл конфігурації pgbackrest (/etc/pgbackrest/pgbackrest.conf):

[main]
pg1-path=/var/lib/postgresql/11/main

[global]
log-level-file=detail
repo1-host=<repository_server_ip>

4. Перезавантажимо postgresql:

sudo service postgresql restart

Налаштування сервера-репозиторію

Репозиторій (pgbackrest користувач):

Внесемо необхідні налаштування у файл конфігурації pgbackrest
(/etc/pgbackrest/pgbackrest.conf):

[main]
pg1-host=<postgres_server_ip>
pg1-path=/var/lib/postgresql/11/main

[global]
repo1-path=/var/lib/pgbackrest
repo1-retention-full=2 # Параметр, указывающий сколько хранить полных бэкапов. Т.е. если у вас есть два полных бэкапа и вы создаете третий, то самый старый бэкап будет удален. Можно произносить как "хранить не более двух бэкапов" - по аналогии с ротациями логов. Спасибо @Aytuar за исправление ошибки.
start-fast=y # Начинает резервное копирование немедленно, прочитать про этот параметр можно тут https://postgrespro.ru/docs/postgrespro/9.5/continuous-archiving

Створення сховища

Репозиторій (pgbackrest користувач):

Створюємо нове сховище для кластера основний:

sudo mkdir -m 770 /var/lib/pgbackrest
sudo chown -R pgbackrest /var/lib/pgbackrest/
sudo -u pgbackrest pgbackrest --stanza=main stanza-create

Перевірка

Postgres сервер (sudo користувач або root):

Перевіряємо на postgres сервері:

sudo -u postgres pgbackrest --stanza=main --log-level-console=info check

Репозиторій (pgbackrest користувач):

Перевіряємо на сервері-репозиторії:

sudo -u pgbackrest pgbackrest --stanza=main --log-level-console=info check

Переконуємося, що у висновку бачимо рядок "check command end: completed successfully".

Втомилися? Переходимо до найцікавішого.

Робимо бекап

Репозиторій (pgbackrest користувач):

1. Виконуємо резервне копіювання:

sudo -u pgbackrest pgbackrest --stanza=main backup

2. Переконуємося, що бекап був створений:

ls /var/lib/pgbackrest/backup/main/

Pgbackrest створить перший повний бекап. За бажанням ви можете запустити команду бекапу повторно і переконатися, що система створить інкрементальний бекап.

Якщо ви хочете повторно зробити повний бекап, то вкажіть додатковий прапор:

sudo -u pgbackrest pgbackrest --stanza=main --type=full backup

Якщо ви хочете докладний висновок у консоль, то також вкажіть:

sudo -u pgbackrest pgbackrest --stanza=main --type=full --log-level-console=info backup

Відновлюємо бекап

Postgres сервер (sudo користувач або root):

1. Зупиняємо працюючий кластер:

sudo pg_ctlcluster 11 main stop

2. Відновлюємося з бекапу:

sudo -u postgres pgbackrest --stanza=main --log-level-console=info --delta --recovery-option=recovery_target=immediate restore

Щоб відновити базу в стан останнього ПОВНОГО бекапу, використовуйте команду без вказівки recovery_target:

sudo -u postgres pgbackrest --stanza=main --log-level-console=info --delta restore

Важливо! Після відновлення може виявитися так, що база зависне в режимі відновлення (будуть помилки в дусі ERROR: cannot execute DROP DATABASE in a read-only transaction). Щиро кажучи, я ще не зрозумів, із чим це пов'язано. Вирішується наступним чином (потрібно буде трохи почекати після виконання команди):

sudo -u postgres psql -c "select pg_wal_replay_resume()"

Насправді є можливість відновити конкретний бекап на його ім'я. Тут я лише вкажу посилання на опис цієї фічі у документації. Розробники радять використовувати цей параметр з обережністю та пояснюють чому. Від себе можу додати, що його використовував. Якщо потрібно, переконайтеся, що після відновлення база вийшла з recovery mode (select pg_is_in_recovery() повинен показати «f») і про всяк випадок зробіть повний бекап після відновлення.

3. Запускаємо кластер:

sudo pg_ctlcluster 11 main start

Після відновлення бекапу нам необхідно виконати повторний бекап:

Репозиторій (pgbackrest користувач):

sudo pgbackrest --stanza=main backup

На цьому все. Насамкінець хочу нагадати, що я в жодному разі не намагаюся будувати із себе senior dba і при найменшій нагоді використовуватиму хмари. В даний час сам починаю вивчати різні теми на кшталт резервного копіювання, реплікацій, моніторингу тощо. і про результати пишу невеликі звіти, щоб зробити невеликий внесок у співтовариство та залишити собі невеликі шпаргалки.

У наступних статтях постараюся розповісти про додаткові фічі - відновлення даних на чистий кластер, шифрування бекапів та публікацію на S3, бекапи через rsync.

Джерело: habr.com

Додати коментар або відгук