Дисклеймер
Я розробник. Я пишу код, з базою даних взаємодію лише як користувач. Я в жодному разі не претендую на посаду системного адміністратора і, тим більше, 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()"
Насправді є можливість відновити конкретний бекап на його ім'я. Тут я лише
3. Запускаємо кластер:
sudo pg_ctlcluster 11 main start
Після відновлення бекапу нам необхідно виконати повторний бекап:
Репозиторій (pgbackrest користувач):
sudo pgbackrest --stanza=main backup
На цьому все. Насамкінець хочу нагадати, що я в жодному разі не намагаюся будувати із себе senior dba і при найменшій нагоді використовуватиму хмари. В даний час сам починаю вивчати різні теми на кшталт резервного копіювання, реплікацій, моніторингу тощо. і про результати пишу невеликі звіти, щоб зробити невеликий внесок у співтовариство та залишити собі невеликі шпаргалки.
У наступних статтях постараюся розповісти про додаткові фічі - відновлення даних на чистий кластер, шифрування бекапів та публікацію на S3, бекапи через rsync.
Джерело: habr.com