Задача довольно типовая, но мы немного усложним условия и сделаем репликацию двух инстансов PostgreSQL, запущенных в Docker-контейнерах.
Что такое репликация?
Репликация — это механизм синхронизации данных между несколькими серверами баз данных. В нашем случае один сервер будет мастером (primary), который принимает все изменения, а второй — репликой (standby), которая получает и применяет эти изменения. Это обеспечивает отказоустойчивость и возможность распределения нагрузки на чтение.
Почему Docker?
Docker упрощает развёртывание и управление приложениями. Мы будем использовать два контейнера: один для мастера, другой для реплики. Все операции выполняются внутри контейнеров или снаружи с помощью docker exec.
Операции на мастер-хосте (primary)
Первым делом создадим пользователя, от имени которого будет осуществляться репликация. Этот пользователь должен иметь права на репликацию (логин и атрибут REPLICATION).
# Заходим в контейнер с PostgreSQL
docker exec -it postgresql /bin/bash
# Переключаемся на пользователя postgres (внутри контейнера)
su postgres
# Запускаем psql
psql
# Создаём роль для репликации
postgres=# CREATE ROLE replica_user WITH REPLICATION LOGIN PASSWORD 'P@SSWORD';
postgres=# \q
# Выходим из оболочки postgres
exit
# Выходим из контейнера
exit
Пояснение:
REPLICATION— специальный атрибут, разрешающий подключение для потоковой репликации.- Пароль
'P@SSWORD'нужно заменить на свой надёжный пароль.
Теперь в файле pg_hba.conf разрешим подключение этому пользователю с хоста, где будет располагаться реплика (slave). Добавьте строку:
host replication replica_user 10.77.111.108/32 md5
Что это значит?
host— тип подключения (TCP/IP).replication— специальная база данных для репликации.replica_user— имя пользователя.10.77.111.108/32— IP-адрес реплики (замените на свой).md5— метод аутентификации по паролю.
Далее вносим правки в конфигурационный файл PostgreSQL (обычно postgresql.conf). Нам нужно включить логический уровень WAL и подсказки для восстановления:
wal_level = logical
wal_log_hints = on
Пояснение:
wal_level = logical— позволяет использовать логическую репликацию (хотя для потоковой физической репликации достаточноreplica, ноlogicalдаёт больше возможностей).wal_log_hints = on— включает запись «подсказок» в WAL, что помогает избежать повреждений при восстановлении.
Так как мы используем контейнер, перезагрузка службы PostgreSQL выполняется иначе, чем на обычном сервере. Вместо systemctl reload используем pg_ctl reload внутри контейнера:
docker exec -it postgresql /bin/bash
su postgres
pg_ctl reload
exit
exit
Примечание: pg_ctl reload перечитывает конфигурацию без остановки сервера.
Операции на slave-хосте (реплика)
На хосте, где будет работать реплика, выполняем следующие шаги.
- Останавливаем контейнер с PostgreSQL (если он запущен).
В примере используется алиасdcдляdocker-compose:
dc stop postgresql
- Запускаем контейнер в интерактивном режиме, чтобы выполнить команды внутри:
dc run postgresql /bin/bash
- Удаляем существующую базу данных (если она есть). Каталог данных PostgreSQL обычно находится в
/var/lib/postgresql/data/. Удаляем всё содержимое:
rm -rf /var/lib/postgresql/data/*
- Копируем базу данных с мастер-узла с помощью утилиты
pg_basebackup. Эта команда создаёт точную копию данных мастера и автоматически настраивает реплику.
pg_basebackup -h 10.51.0.100 -U replica_user -X stream -C -S replica_1 -v -R -W -D /var/lib/postgresql/data/
Разберём параметры:
-h 10.51.0.100— IP-адрес мастера (замените на свой).-U replica_user— пользователь для репликации.-X stream— включить потоковую передачу WAL-файлов.-C— создать контрольную точку (checkpoint) на мастере.-S replica_1— имя слота репликации (слот должен быть заранее создан на мастере, иначе команда упадёт).-v— подробный вывод.-R— создать файлstandby.signalдля запуска в режиме реплики.-W— дождаться завершения записи WAL.-D /var/lib/postgresql/data/— целевой каталог для данных. Важно: Слот репликацииreplica_1нужно предварительно создать на мастере:
SELECT pg_create_physical_replication_slot('replica_1');
- Выходим из контейнера и запускаем контейнер в обычном режиме:
exit
dc start postgresql
Проверяем статус репликации
Зайдите в контейнер реплики и выполните запрос к мастеру (или к реплике, но статус репликации виден на мастере). Лучше проверить на мастере:
docker exec -it postgresql_master /bin/bash
su postgres
psql
Выполните:
SELECT client_addr, state FROM pg_stat_replication;
Пример вывода:
client_addr | state
--------------+------------
10.77.111.108 | streaming
(1 row)
Что означает state = streaming?
Это значит, что реплика активна и непрерывно получает изменения с мастера.
Опционально: создаём общее хранилище WAL-файлов
Для дополнительной надёжности можно организовать общее NFS-хранилище для WAL-файлов. Это позволит реплике восстанавливаться даже при временной недоступности мастера.
Настройка NFS (по инструкции «Настройка NFS клиент-сервер в CentOS»). Смонтируйте NFS-шару в каталог /mnt/nfs на обоих хостах (мастере и реплике). Внутри создайте подкаталог /mnt/nfs/wal.
Добавляем том монтирования в контейнер (в docker-compose.yml или при запуске):
volumes:
- /mnt/nfs/wal:/wal
Теперь настраиваем архивацию WAL на мастере. В postgresql.conf мастера добавьте:
archive_mode = on
archive_command = 'test ! -f /mnt/nfs/wal/%f && cp %p /mnt/nfs/wal/%f'
Пояснение:
archive_mode = on— включает архивацию.archive_command— копирует каждый завершённый WAL-файл в общую NFS-папку, если его там ещё нет.
На реплике (slave) добавляем параметры для восстановления из архива и очистки старых файлов:
restore_command = 'cp /mnt/nfs/wal/%f %p'
archive_cleanup_command = 'pg_archivecleanup /mnt/nfs/wal/ %r'
Что они делают?
restore_command— при необходимости реплика может восстановить недостающий WAL из общего хранилища.archive_cleanup_command— автоматически удаляет устаревшие WAL-файлы из хранилища, чтобы не забивать диск.
После внесения изменений не забудьте перезагрузить конфигурацию на обоих серверах (pg_ctl reload).
Итог
Мы настроили потоковую репликацию PostgreSQL в Docker с использованием слота репликации и опционально — общего NFS-хранилища для WAL. Такая конфигурация обеспечивает отказоустойчивость и позволяет быстро восстановить реплику в случае сбоя.
Основные моменты:
- Пользователь для репликации должен иметь атрибут
REPLICATION. pg_basebackupс ключом-Rавтоматически создаёт файлstandby.signal.- Слот репликации гарантирует, что мастер не удалит нужные WAL-файлы, пока реплика их не получит.
- Общее NFS-хранилище для WAL — это дополнительный уровень защиты, но не обязателен.





