[PostgreSQL, Администрирование баз данных, Серверное администрирование] Инкрементальные бэкапы PostgreSQL с pgBackRest. Часть 2. Шифрование, загрузка в S3, восстановление на новый сервер, PITR

Автор Сообщение
news_bot ®

Стаж: 6 лет 9 месяцев
Сообщений: 27286

Создавать темы news_bot ® написал(а)
08-Сен-2020 14:30

Данная статья — продолжение статьи «Инкрементальные бэкапы postgresql с pgbackrest — курс молодого бойца от разработчика».
В первой части мы научились делать инкрементальные бэкапы, загружать их на удаленный сервер (репозиторий с бэкапами) и откатываться на последний бэкап.
В этой статье мы научимся шифровать бэкапы, загружать их в S3-совместимое хранилище (вместо второго сервера-репозитория), восстанавливаться на чистый кластер и, наконец, восстанавливаться на определенный момент времени (point in time recovery, PITR).

Момент
Автор не претендует на роль DBA, но иногда любит настроить и посмотреть все сам.
Подготовка
Для воспроизведения данного мануала нам понадобится:
  • Cервер с базой данных (на него мы установим pgbackrest);
  • S3 хранилище (вы можете использовать Amazon или любое S3 совместимое, я буду использовать Amazon S3);
  • Третий сервер. По желанию. На нем мы потренируемся разворачивать postgresql и pgbackrest с нуля, разворачивая существующий бекап из S3 хранилища (сервер сгорел, переезд и т.п.);

Подразумевается, что postgresql у вас уже установлен, а следовательно пользователь postgres тоже имеется.
Процесс установки pgbackrest я описал в предыдущей статье, но на всякий случай продублирую еще раз (напоминаю: перед установкой создайте себе sudo пользователя — я буду использовать sudo пользователя с юзернеймом pgbackrest).
Чтобы у вас было меньше проблем при воспроизведении инструкции — курсивом я прописываю где, каким пользователем и с какими правами я исполнял команду во время написания и проверки статьи.
Пойдем мы по такому пути:
Настроим postgresql и pgbackrest
Настроим шифрование бэкапов (две строчки)
Научимся делать бэкап и отправлять в S3 хранилище (пять строчек)
Сделаем бэкап
Представим, что сломали кластер, развернемся на новом сервере, подключим существующий S3 репозиторий и накатим бэкап
Посмотрим на PITR (Point In Time Recovery): восстановимся на определенный момент времени (допустим, pgbackrest забэкапил уже drop table, а нам нужно откатиться на 4 часа назад, когда табличка еще существовала)
Поехали!
Установка pgBackRest
sudo пользователь или root:
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 postgres:postgres /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 postgres:postgres /etc/pgbackrest/pgbackrest.conf

7. Проверяем:
pgbackrest version

Настройка postgresql и pgBackRest
sudo пользователь или root:
1. Внесем необходимые настройки в 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

2. Внесем необходимые настройки в файл конфигурации pgbackrest (/etc/pgbackrest/pgbackrest.conf):
[main]
pg1-path=/var/lib/postgresql/11/main
[global]
log-level-file=detail
repo1-cipher-pass=tr5+BXdfdoxeyUqfo6AzLTrW+c+Jfd/1QbQj2CDMMBwtB0YGH3EJajry4+Eeen6D
repo1-cipher-type=aes-256-cbc
repo1-path=/var/lib/pgbackrest
repo1-retention-full=2 # Параметр, указывающий сколько хранить полных бэкапов. Т.е. если у вас есть два полных бэкапа и вы создаете третий, то самый старый бэкап будет удален. Можно произносить как "хранить не более двух полных бэкапов" - по аналогии с ротациями логов.
repo1-type=s3
repo1-s3-bucket=pgbackrest-part2-tutorial
repo1-s3-endpoint=s3.us-east-1.amazonaws.com
repo1-s3-region=us-east-1
repo1-s3-key=9wdS3G8U5wz7kNsFWVGck7DDZ7DtVDtbM
repo1-s3-key-secret=A9zRmW16zXKt2vVA8mmNsFWy2mUAPYHa
start-fast=y
[global:archive-push]
compress-level=3

Как вы поняли, тут мы сразу настроили шифрование и настроили поддержку S3 хранилища.
P.S. Комментариев в конфиге быть не должно.
P.S. Чтобы сгенерировать надежный ключ шифрования можно воспользоваться командой:
openssl rand -base64 48

Создание хранилища
sudo пользователь или root:
sudo mkdir -m 770 /var/lib/pgbackrest
sudo chown -R postgres /var/lib/pgbackrest/
sudo -u postgres pgbackrest --stanza=main stanza-create

Если все получилось, то в S3-бакете вы увидите файлы, которые сгенерировал pgbackrest.
Делаем бэкап:
sudo пользователь или root:
sudo -u postgres pgbackrest --log-level-console=info --stanza=main backup

pgBackRest создаст первый полный бэкап. При желании вы можете запустить команду бэкапа повторно и убедиться, что система создаст инкрементальный бэкап.
Если вы хотите повторно сделать полный бэкап, то укажите дополнительный флаг:
sudo -u postgres pgbackrest --log-level-console=info --stanza=main --type=full backup

Посмотреть список бэкапов можно с помощью команды:
sudo -u postgres pgbackrest --stanza=main info

Восстанавливаем бэкап:
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()"

UPD: Как я понял, данная ошибка возникает из-за того, что после восстановления с указанием recovery_target=immediate pgbackrest ставит БД на паузу. Чтобы этого не было, нужно дополнительно указать некоторые флаги (их значение можете прочитать тут и тут):
sudo -u postgres pgbackrest --stanza=main --log-level-console=info --delta --recovery-option=recovery_target=immediate --target-action=promote --type=immediate restore

На самом деле, есть возможность восстановить конкретный бэкап по его имени. Здесь я лишь укажу ссылку на описание данной фичи в документации. Разработчики советуют использовать данный параметр с осторожностью и объясняют почему. От себя могу добавить, что я его использовал. Главное убедитесь, что после восстановления база вышла из recovery mode (select pg_is_in_recovery() должен показать «f») и на всякий случай сделайте полный бэкап после восстановления.
3. Запускаем кластер:
sudo pg_ctlcluster 11 main start

После восстановления бэкапа выполним повторный бэкап:
sudo -u postgres pgbackrest --log-level-console=info --stanza=main backup

Восстанавливаем бэкап на чистый кластер:
Давайте представим, что произошло что-то ужасное — сервер сгорел (упал, затопило, потеряли доступ). Нужно восстановить все на новый, чистый сервер. На новом сервере мы уже завели sudo пользователя, установили pgbackrest, установили postgresql и у нас появился чистый и свежий main кластер.
Все, что нам нужно сделать — настроить конфиг postgresql и pgBackRest аналогично тем, что были на прежнем сервере, перезапустить postgresql и выполнить порядок команд, аналогичный восстановлению:
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  --target-action=promote --type=immediate restore

P.S. Нюансы и тонкости данной команды я описал выше. 
3. Запускаем кластер:
sudo pg_ctlcluster 11 main start

После восстановления бэкапа нам необходимо выполнить повторный бэкап:
sudo -u postgres pgbackrest --log-level-console=info --stanza=main backup

Вот, собственно, и все. Пожар потушен.
Point In Time Recovery (PITR)
Давайте представим такую ситуацию, что в 16:00 был создан бэкап, а в 18:05 мы случайно стерли важную табличку в которую за 2 часа успело попасть очень много важных данных, которые не хотелось бы потерять. PgBackRest за счет PostgreSQL предоставляет нам такую возможность: мы можем откатиться на конкретный момент времени, при условии, что у нас достаточное кол-во информации для восстановления.
Работает это так:
  • Мы говорим, что хотим откатиться на момент времени 18:04;
  • pgBackRest ищет последний актуальный бэкап (16:00);
  • Восстанавливает его, но накатывает не все, а лишь то, что мы успели сделать до 18.04;

P.S. построен этот механизм на WAL логах. Почитать можно здесь.
Выполнить восстановление на конкретный момент времени (предварительно остановив кластер) можно данной командой:
sudo -u postgres pgbackrest --stanza=main --log-level-console=info --delta --type=time "--target=2020-09-06 18:27:24.561458+02" --target-action=promote restore

Важное замечание — PostgreSQL может воспроизводить WAL логи только вперед, но не назад. Что это значит на практике?
Допустим, в 16:00 был создан бэкап. В 18:05 мы случайно удалили таблицу, а в 18:10 снова был создан бэкап с уже удаленной таблицей. Когда вы попытаетесь сделать PITR — pgBackRest возьмет бэкап, который был создан в 16:00 и накатит сверху все то, что было до 18:05, а не возьмет бэкап, который был создал в 18:10 и будет откатывать все назад. Это важно понимать. Более подробно данный механизм описан здесь.
Предположим, вы сделали бэкап, в который уже попала информации о удалении таблицы. С помощью флага --set скажем, какой бэкап нужно использовать за базу (тот, в котором таблица еще была). pgBackRest возьмет данный бэкап и накатит все то, что было до удаления таблицы.
sudo -u postgres pgbackrest --stanza=main --log-level-console=info --delta --type=time --set=20200905-183838F_20200906-182612I "--target=2020-09-06 18:27:24.561458+02" --target-action=promote restore

P.S. Команду для получения списка бэкапов я показал выше.
Запустим кластер. После запуска изучим файл /var/log/postgresql/postgresql-11-main.log. В нем нас интересуют следующие строки, показывающие, что восстановление на указанный момент времени произошло успешно:
starting point-in-time recovery to 2020-09-07 11:26:52.493127+02
...
recovery stopping before commit of transaction 576, time 2020-09-07 11:27:14.584496+02
...
last completed transaction was at log time 2020-09-07 11:24:09.583761+02

Вот и все. Настоятельно советую поэкспериментировать с данным инструментом перед применением его в бою.
===========
Источник:
habr.com
===========

Похожие новости: Теги для поиска: #_postgresql, #_administrirovanie_baz_dannyh (Администрирование баз данных), #_servernoe_administrirovanie (Серверное администрирование), #_postgresql, #_administrirovanie_baz_dannyh (администрирование баз данных), #_postgres, #_bekap_bazy_dannyh (бэкап базы данных), #_postgresql, #_administrirovanie_baz_dannyh (
Администрирование баз данных
)
, #_servernoe_administrirovanie (
Серверное администрирование
)
Профиль  ЛС 
Показать сообщения:     

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы

Текущее время: 22-Ноя 13:33
Часовой пояс: UTC + 5