Внешний сервер PostgreSQL
Дистрибутив Памир всегда разворачивает СУБД PostgreSQL в контейнере database, и выбора
расположения СУБД в инсталляторе нет. При этом уже работающую инсталляцию можно перевести на
внешний сервер PostgreSQL без доработок: все параметры подключения приложение берёт из
переменных окружения, а штатный контейнер СУБД отключается через docker-compose.additional.yml.
Переезд может потребоваться, если СУБД обслуживается отдельной командой, входит в общий кластер с репликацией и резервированием либо должна жить на выделенном узле.
Файл .override.env читает не только приложение, но и сам контейнер СУБД, а для образа
PostgreSQL переменные POSTGRES_USER, POSTGRES_PASSWORD и POSTGRES_DB означают совсем не то,
что для приложения — см. Коллизия имён POSTGRES_*.
Поэтому шаги выполняются строго в порядке: дамп → остановка и отключение database →
.override.env, а откат — в обратном порядке.
Требования к внешнему серверу
- Версия. PostgreSQL 15 и выше. В дистрибутиве поставляется 15.13 (
VERSION.yml, параметрPOSTGRES_VERSION), на нём же проверяются миграции. - Модули contrib. Приложению требуется расширение
tablefunc: на его функцииcrosstab()построены выборки атрибутов пользователей в сервисе авторизации и атрибутов КЕ в СРМ. В сборках Astra Linux и Debian/Ubuntu расширение входит в пакетpostgresql-contrib, в RHEL-подобных — вpostgresql<версия>-contrib. - Сетевой доступ. Сервер должен быть доступен по TCP из контейнеров сети
pamir-net— из неё ходят и сервисы приложения, и экспортеры самомониторинга. Какой адрес при этом видит СУБД, зависит от того, где она стоит, — см. следующий раздел.
Сетевой доступ и pg_hba.conf
Сервисы Памир работают в Docker-сети pamir-net. Её имя и подсеть заданы в compose-файле
дистрибутива явно (172.19.0.0/16, шлюз 172.19.0.1) и при штатной установке сервера не меняются;
изолированная подсеть 172.20.0.0/16 выделяется только Пробе, установленной рядом с сервером
(см. Проба). Фактическую подсеть можно посмотреть командой:
docker network inspect pamir-net --format '{{json .IPAM.Config}}'
Адрес, под которым подключение приходит на сервер PostgreSQL, зависит от того, где стоит СУБД.
СУБД на том же узле, что и контейнеры. Пакет из контейнера идёт на собственный адрес хоста и
доставляется локально, минуя правило MASQUERADE Docker, — сервер видит адрес самого контейнера.
Поэтому в pg_hba.conf разрешается подсеть pamir-net:
host srm app_postgres 172.19.0.0/16 scram-sha-256
host srm,postgres postgres 172.19.0.0/16 scram-sha-256
Новые строки размещаются выше общих правил, которые могли бы перехватить эти подключения;
существующие правила локального доступа сохраняются. В postgresql.conf сервер должен слушать
адрес узла, а не только localhost:
listen_addresses = 'localhost,<IP узла Памир>'
port = 5432
СУБД на отдельном сервере. Пакет из контейнера уходит через физический интерфейс узла, и к нему
применяется MASQUERADE Docker — внешний сервер видит адрес узла Памир, а не адрес
контейнера:
host srm app_postgres <IP узла Памир>/32 scram-sha-256
host srm,postgres postgres <IP узла Памир>/32 scram-sha-256
Правило /32 не сработает, если между узлом Памир и сервером СУБД есть дополнительный
NAT или сетевой шлюз: исходный адрес подменится ещё раз. Поэтому фактический адрес клиента
обязательно проверяется подключением — см. Проверка подключения ниже.
После правки конфигурации PostgreSQL перечитывает её по pg_ctl reload (или
systemctl reload postgresql-15); ошибки в правилах видны в pg_hba_file_rules:
SELECT line_number, error FROM pg_hba_file_rules WHERE error IS NOT NULL;
Подготовительный SQL
Ниже повторяется то, что при первом запуске контейнера database делает штатный скрипт
инициализации init/database/init-database.sh. На внешнем сервере эти команды выполняются
вручную от суперпользователя (psql -U postgres) до первого запуска приложения:
SET password_encryption = 'scram-sha-256';
ALTER ROLE postgres WITH PASSWORD '<пароль суперпользователя>';
CREATE ROLE app_postgres WITH PASSWORD '<пароль роли приложения>';
ALTER ROLE app_postgres LOGIN CREATEDB;
CREATE DATABASE srm OWNER app_postgres;
REVOKE ALL ON DATABASE srm FROM PUBLIC;
GRANT ALL PRIVILEGES ON DATABASE srm TO app_postgres;
Затем, уже подключившись к созданной БД (psql -U postgres -d srm):
CREATE EXTENSION IF NOT EXISTS tablefunc;
где:
password_encryptionфиксирует метод хеширования под правилаscram-sha-256вpg_hba.conf(в PostgreSQL 15 это значение и так по умолчанию);ALTER ROLE postgresзадаёт пароль суперпользователя: на свежем кластере его обычно нет, а приложению он нужен для подключения по TCP подPOSTGRES_SUSER/POSTGRES_SPASSWORD;app_postgres— имя роли приложения, оно же значениеPOSTGRES_USER; может быть любым, но должно совпадать с тем, что записано в.override.env;srm— имя БД приложения, оно же значениеPOSTGRES_DB;LOGINнужен роли для подключения;CREATEDBвыдаётся так же, как в штатном скрипте инициализации;REVOKE ALL … FROM PUBLICзакрывает БД от остальных ролей кластера — на общем сервере это особенно важно;CREATE EXTENSION tablefuncв примере выполняется от суперпользователя — так же, как это делает штатный скрипт инициализации; начиная с PostgreSQL 13 расширение помечено как trusted, поэтому его может создать и владелец БД.
Схемы auth, monitoring, notification, docker_tool, task_tool создаёт alembic при прогоне
миграций (CREATE SCHEMA IF NOT EXISTS в migrations/env.py каждого сервиса), а схема public,
в которой работают СРМ и celery, есть в новой БД по умолчанию. Достаточно, чтобы роль приложения
была владельцем БД srm.
Проверка подключения
Когда роли и БД созданы, а pg_hba.conf поправлен, проверьте подключение из контейнера —
именно оттуда пойдут запросы приложения. Заодно команда показывает, какой адрес видит сервер:
docker exec -it pamir-database-1 psql \
-h <адрес сервера СУБД> -p 5432 -U app_postgres -d srm -W \
-c "SELECT current_database(), current_user, inet_server_addr(), inet_client_addr();"
Повторите проверку для суперпользователя — под ним работает сброс сервиса:
docker exec -it pamir-database-1 psql \
-h <адрес сервера СУБД> -p 5432 -U postgres -d postgres -W \
-c "SELECT current_database(), current_user, inet_server_addr(), inet_client_addr();"
Если правило в pg_hba.conf не подошло, PostgreSQL отказывает в подключении и сам называет
фактический адрес клиента: no pg_hba.conf entry for host "…". Именно этот адрес и нужно
разрешить — при успешном подключении то же значение возвращает inet_client_addr().
Проверка выполняется, пока контейнер database ещё работает, — то есть до его отключения.
Пока оба подключения не проходят, дальше переходить не нужно: без них приложение просто не
поднимется на новой СУБД.
Пароли
В поставке параметры подключения заданы одинаковыми для всех инсталляций:
| Переменная | Значение в поставке | Назначение |
|---|---|---|
POSTGRES_SUSER | postgres | суперпользователь СУБД, используется при сбросе сервиса |
POSTGRES_SPASSWORD | 123456789 | пароль суперпользователя |
POSTGRES_USER | app_postgres | роль приложения |
POSTGRES_PASSWORD | 12345678 | пароль роли приложения |
POSTGRES_DB | srm | БД приложения |
Значения из поставки известны и одинаковы во всех инсталляциях. При переезде на внешний сервер задайте новые пароли для роли приложения и суперпользователя — переносить пароли из локального контейнера не нужно и не следует.
Именно поэтому дамп ролей (pg_dumpall --globals-only) на внешний сервер обычно не
восстанавливают: роль приложения создаётся подготовительным SQL с новым паролем, а восстановление
глобальных объектов вернуло бы старые хеши паролей.
@ в пароле не поддерживаетсяПароли в POSTGRES_PASSWORD и POSTGRES_SPASSWORD не должны содержать @. Строка подключения
собирается подстановкой значений в шаблон
postgresql+<драйвер>://<роль>:<пароль>@<хост>:<порт>/<БД> без экранирования, поэтому первый же
@ внутри пароля воспринимается как разделитель: пароль обрезается по нему, а остаток
приклеивается к имени хоста. Сервис не стартует с ошибкой Name or service not known — адрес
вида ssw0rd@192.168.160.247 не разрешается.
Например, пароль p@ssw0rd разбирается как пароль p и хост ssw0rd@192.168.160.247.
Пока ограничение не снято в коде, выбирайте пароли без @; остальные спецсимволы
(/, :, #, ?, %) в этой позиции разбираются корректно. То же относится к именам ролей
в POSTGRES_USER и POSTGRES_SUSER и к паролю RabbitMQ в RABBITMQ_PASSWORD — там строка
подключения собирается так же.
Docker Compose на хосте Памир
Переезд выполняется командами docker compose, поэтому плагин должен быть установлен на узле
до остановки приложения. Нужна версия из дистрибутива — v2.27.0, она лежит в ISO-образе по
пути deps/docker-compose; порядок установки описан в разделе
Установка docker-compose.
На стенде в системе присутствовал более новый Compose, и с ним контейнеры не запускались.
После установки плагина из дистрибутива (замены имеющегося) сервисы поднялись штатно. Поэтому
на время работ плагин из ISO ставится поверх системного — и как плагин Docker CLI, и как
отдельная команда в PATH:
# /media — точка монтирования ISO-образа дистрибутива
sudo install -Dm755 /media/deps/docker-compose /usr/local/lib/docker/cli-plugins/docker-compose
sudo install -Dm755 /media/deps/docker-compose /usr/local/bin/docker-compose
docker compose version
Ожидается Docker Compose version v2.27.0.
Перенос данных
Все команды выполняются из каталога приложения ($HOME/.pamir или /opt/pamir).
1. Остановить приложение, оставив СУБД
docker compose stop
docker compose start database
docker compose ps database
pamirctl stop на этом шагеpamirctl stop останавливает сервисы и удаляет контейнеры, включая database, — снять дамп
после этого не из чего. Для переезда нужен работающий контейнер СУБД при остановленных сервисах
приложения, а это даёт только docker compose. Тот же приём используется при
восстановлении из резервной копии.
Вместе с database могут подняться его зависимости (rabbitmq, fluent-bit) — это нормально.
2. Снять дамп
Дамп снимается штатными средствами из работающего контейнера database — процедура и все
команды описаны в разделе Резервное копирование СУБД PostgreSQL.
Понадобится дамп БД приложения; дамп ролей
нужен, только если вы намеренно переносите весь кластер вместе с паролями.
Контейнер СУБД в дистрибутиве собран на базе Astra Linux, и в дампе оказываются команды
мандатных меток. Если внешний сервер их не поддерживает (например, PostgreSQL из репозитория
РЕД ОС), восстановление прерывается на MAC LABEL. Дамп для переезда снимается с флагом
--disable-macs — см. Дамп базы данных приложения.
Дамп снимается до того, как в .override.env появятся переменные POSTGRES_*.
Иначе команды резервного копирования подключатся к контейнеру не под тем пользователем —
см. Коллизия имён POSTGRES_*.
3. Восстановить дамп на внешнем сервере
Восстановление выполняется теми же утилитами, но подключение идёт не через docker compose exec,
а напрямую к серверу — например, локально на узле СУБД от имени postgres:
pg_restore -U postgres -p 5432 -d srm \
--clean --if-exists --single-transaction \
< "$HOME/pamir-backups/srm-2026-06-08.dump"
echo $?
Ожидаемый код возврата — 0. При ошибке дальше не переходите: незавершённое восстановление
оставит БД в половинчатом состоянии. Флаг --single-transaction как раз и нужен, чтобы при сбое
не осталось частично загруженных данных.
--no-ownerОбъекты БД srm принадлежат роли приложения. Флаг --no-owner назначил бы всем объектам
владельцем суперпользователя, и приложение потеряло бы доступ (permission denied). Подробнее —
в разделе Восстановление.
Проверьте, что данные на месте и расширение создано:
SELECT schemaname, tableowner, count(*) AS tables
FROM pg_tables
WHERE schemaname NOT IN ('pg_catalog', 'information_schema')
GROUP BY schemaname, tableowner
ORDER BY schemaname, tableowner;
SELECT extname, extversion FROM pg_extension WHERE extname = 'tablefunc';
Владельцем таблиц в схемах приложения должна быть роль приложения, а не суперпользователь.
Отключение локальной СУБД
Сначала контейнер останавливается, и только потом правится compose-файл:
docker compose stop database
profiles: !override [never] исключает сервис из проекта при следующем запуске, но уже
работающий контейнер продолжит работать. Если не остановить его явно, локальная СУБД останется
поднятой и будет занимать порт и память, а часть сервисов может продолжить ходить в неё.
Затем в каталоге приложения ($HOME/.pamir или /opt/pamir) откройте
docker-compose.additional.yml. В поставке файл содержит только якорь логирования
и закомментированные заготовки секций:
x-logging: &flb-logging
driver: fluentd
options:
fluentd-address: "localhost:24224"
fluentd-async: "true"
fluentd-async-reconnect-interval: "10s"
# services:
# volumes:
Файл не заменяется целиком — блок дописывается в конец:
services:
database:
profiles: !override [never]
Если раздел services: в файле уже есть, database добавляется внутрь него — второй раздел
services: создавать нельзя. Сервис database попадает в профиль never, которого нет среди
включённых, и compose исключает его из проекта.
Проверьте, что файл собирается и контейнер остановлен:
docker compose config --quiet
echo $?
docker inspect pamir-database-1 --format '{{.State.Status}}'
Ожидаются код возврата 0 и статус exited.
Сервис database состоит сразу во всех прикладных профилях —
all, app, backend, backend.*, db, db.postgres, debug, migrations. Поэтому ни флаг --profiles
у инсталлятора, ни параметр app_profiles в .pamirctl.yml его не выключают: любой профиль,
с которым поднимается приложение, тянет СУБД за собой. Тег !override нужен, чтобы список
профилей был именно заменён при слиянии compose-файлов, а не дополнен.
docker-compose.additional.ymlЭтот файл предназначен для пользовательских переопределений: он не перезаписывается при
обновлении и исключён из контроля целостности на этапе сборки дистрибутива, поэтому правка
не приводит к записи уровня WARN в лог аудита. Тем же приёмом — profiles: !override [never] —
инсталлятор отключает невыбранные сервисы при
выборочной установке компонентов.
Соседний файл docker-compose.managed.yml инсталлятор ведёт сам, править его вручную не нужно.
Параметры подключения
Параметры подключения записываются в файл .override.env в каталоге приложения. Если файла нет,
его нужно создать:
POSTGRES_HOST=<IP-адрес сервера СУБД>
POSTGRES_PORT=5432
POSTGRES_USER=app_postgres
POSTGRES_PASSWORD=<пароль роли приложения>
POSTGRES_DB=srm
# Используются при сбросе сервиса
POSTGRES_SUSER=postgres
POSTGRES_SPASSWORD=<пароль суперпользователя внешнего сервера>
POSTGRES_HOST — адрес узла, а не localhostЕсли СУБД установлена на том же узле, что и контейнеры, в POSTGRES_HOST всё равно указывается
IP-адрес узла: для контейнера localhost — это он сам, а не хост. По той же причине адрес
127.0.0.1 здесь работать не будет.
Остальные настройки файла сохраняются; повторяющихся определений этих переменных остаться не должно.
Именно .override.env, а не .env: файлы .env и .$SERVICE.env перезаписываются
инсталлятором при каждом обновлении, а .override.env — нет. Он подключён в env_file всех
сервисов приложения и, кроме того, передаётся утилитой pamirctl на уровень проекта, поэтому
значения из него видны и при интерполяции переменных в compose-файлах — это важно для
postgres-exporter, у которого своего env_file нет. Подробнее об иерархии файлов —
в разделе Переменные окружения.
Коллизия имён POSTGRES_*
Файл .override.env подключён в env_file и у контейнера СУБД — после .postgres.env,
то есть его значения перекрывают значения из .postgres.env. При этом для образа PostgreSQL
переменные POSTGRES_USER, POSTGRES_PASSWORD и POSTGRES_DB означают суперпользователя
и служебную БД кластера, а не учётную запись приложения:
| Переменная | Для приложения (Памир) | Для образа PostgreSQL (контейнер database) |
|---|---|---|
POSTGRES_USER | роль приложения (app_postgres) | суперпользователь кластера (postgres) |
POSTGRES_PASSWORD | пароль роли приложения | пароль суперпользователя |
POSTGRES_DB | БД приложения (srm) | служебная БД кластера (postgres) |
Пока локальный контейнер не отключён, значения из .override.env перекроют .postgres.env,
и это приведёт к двум последствиям:
- на пустом томе
pamir_database-datainitdbсоздаст кластер с другим суперпользователем и другой служебной БД, а скрипт инициализации отработает не так, как задумано; - команды из раздела резервного копирования
(
docker compose exec -T database … -U "$POSTGRES_USER") начнут подключаться под ролью приложения вместо суперпользователя.
Отсюда строгий порядок: сначала дамп, затем отключение database, и только потом
.override.env. При откате — в обратном порядке: сначала убрать POSTGRES_* из
.override.env, потом вернуть сервис.
Запуск и миграции
После того как внешний сервер подготовлен, данные восстановлены, сервис database остановлен
и отключён, а параметры подключения записаны, приложение запускается штатно:
pamirctl start
pamirctl status
Проверьте, что сервисы получили новые параметры и подключения дошли до внешнего сервера:
# параметры подключения в контейнере сервиса
docker inspect pamir-auth-1 --format '{{range .Config.Env}}{{println .}}{{end}}' \
| grep -E '^POSTGRES_(HOST|PORT|USER|DB)='
# журнал запуска сервиса
docker logs --since 5m --tail 40 pamir-auth-1
На стороне СУБД должны появиться клиентские подключения роли приложения:
SELECT usename, client_addr, state, count(*) AS connections
FROM pg_stat_activity
WHERE datname = 'srm'
AND usename = 'app_postgres'
AND backend_type = 'client backend'
GROUP BY usename, client_addr, state
ORDER BY client_addr, state;
Если миграции нужно прогнать повторно (например, они не применились при обновлении), выполните процедуру из раздела Повторный запуск миграций БД.
Лицензия в PostgreSQL не хранится: сервис license держит её в каталоге приложения —
data/licenses (installation.key, private_key.pem, license.zip), каталог подключён
к контейнеру bind-монтированием и в переезде не участвует. Тем не менее после переезда
убедитесь, что сервисы лицензию видят:
docker logs --since 10m pamir-auth-1 | grep -i license
Сообщение not found license. The default settings will be used. означает, что лицензия
не получена. Известен случай, когда после работ лицензию пришлось выпускать заново: сформируйте
новый запрос на лицензию в интерфейсе и загрузите полученный файл. Каталог data/licenses при
любых работах трогать не нужно — он входит в
резервную копию конфигурации.
Самомониторинг СУБД
Часть самомониторинга переезжает вместе с приложением, часть нужно поправить руками.
postgres-exporter переезжает сам. Строка подключения собирается интерполяцией из тех же
переменных (DATA_SOURCE_URI, DATA_SOURCE_USER, DATA_SOURCE_PASS в его compose-фрагменте),
поэтому достаточно, чтобы .override.env был подключён на уровне проекта — это делает
pamirctl start. Проверить:
docker inspect pamir-postgres-exporter-1 --format '{{range .Config.Env}}{{println .}}{{end}}' \
| grep -E '^DATA_SOURCE_(URI|USER)='
В адресе подключения должен быть адрес внешнего сервера.
sql-exporter нужно перенастроить вручную. Его строка подключения хранится не в переменных
окружения, а в конфигурации экспортера, и при переезде там остаются прежние адрес и пароль.
Откройте Настройки → Мониторинг → Экспортеры → SQL Exporter → Конфигурация, в задании PAMIR
в разделе connections укажите новые параметры целиком — адрес, порт, БД и пароль:
connections:
- postgres://<роль приложения>:<пароль роли>@<адрес сервера СУБД>:5432/srm?sslmode=disable
Остальную конфигурацию менять не нужно. Через минуту после сохранения в журнале экспортера должны
появиться сообщения Running Query и Query finished без новых ошибок подключения:
docker logs --since 1m --tail 30 pamir-sql-exporter-1
Фетчер КЕ «PostgreSQL Памир». Адрес экземпляра СУБД попадает в БДКЕ из фетчера, и его тоже нужно обновить, иначе КЕ останется с прежним адресом. Откройте Настройки → СРМ → Типы КЕ → Памир → Доступные связи → «PostgreSQL Памир» → ⋮ → Фетчер и в фетчере Save data to attribute укажите:
{"instance":"<адрес сервера СУБД>:5432/srm","auth_module":"pamir"}
Состав атрибутов КЕ «PostgreSQL Памир» описан в разделе Самомониторинг.
После этого проверьте, что метрики поступают: на дашбордах самомониторинга должны обновляться
pg_stat_activity_count, pg_locks_count и sql_pg_relation_size.
В строке подключения postgres-exporter жёстко задан sslmode=disable, а сам внешний сервер
должен быть доступен из контейнеров сети pamir-net, а не только с хоста Docker Engine.
Откат на локальную СУБД
Откат выполняется в обратном порядке.
-
Остановить сервисы приложения:
docker compose stop -
Удалить переменные
POSTGRES_*из.override.env(или сам файл, если больше ничего в нём нет). -
Убрать из
docker-compose.additional.ymlблок сdatabase: profiles: !override [never]и проверить файл:docker compose config --quiet. -
При необходимости перенести данные обратно. Поднимите контейнер СУБД (
docker compose start database) и восстановите дамп по разделу Восстановление. Если томpamir_database-dataне удалялся, в нём осталось состояние на момент переезда — тогда этот шаг не нужен. -
Вернуть прежние адреса в самомониторинге: строку
connectionsуsql-exporterи атрибутinstanceв фетчере КЕ «PostgreSQL Памир» (database:5432/srm). -
Запустить приложение:
pamirctl start, затемpamirctl status.
Порядок шагов 2 и 3 менять нельзя: если вернуть сервис database раньше, чем убраны POSTGRES_*,
контейнер поднимется с параметрами внешнего сервера в роли суперпользовательских — см.
Коллизия имён POSTGRES_*.
Что происходит при обновлении дистрибутива
| Объект | Что с ним происходит |
|---|---|
.env, .postgres.env, .$SERVICE.env, *.autogen | перезаписываются файлами из дистрибутива |
.override.env | не перезаписывается, настройки внешней СУБД сохраняются |
docker-compose.additional.yml | не перезаписывается, сервис database остаётся отключённым |
Миграции (pamir-installer install) | прогоняются на внешней БД — параметры подключения контейнеры миграций получают из .override.env |
uninstall --purge | удаляет локальный том pamir_database-data; данные на внешнем сервере не затрагиваются |
Файл .postgres.env в режиме внешней СУБД не используется вовсе — его читает только контейнер
database, который отключён. Перезапись этого файла при обновлении на работу системы не влияет.
pamirctl startИнсталлятор передаёт на уровень проекта только .env и *.autogen, поэтому при интерполяции
переменных в compose-файлах он видит POSTGRES_HOST=database из .env. Это затрагивает
postgres-exporter, строка подключения которого собирается именно интерполяцией. Команда
pamirctl start подключает .override.env на уровень проекта и пересоздаёт контейнер
с правильным адресом.
Ограничения
- Шифрование соединения с СУБД не поддерживается. Строка подключения собирается из отдельных
переменных (
POSTGRES_USER,POSTGRES_PASSWORD,POSTGRES_HOST,POSTGRES_PORT,POSTGRES_DB,POSTGRES_DRIVER), и параметров TLS в ней нет — задатьsslmode=verify-fullили путь к сертификату через переменные окружения нельзя. Внешний сервер должен находиться в доверенном сетевом сегменте; трафик между приложением и СУБД не шифруется. - Сброс сервиса требует прав суперпользователя. Ручка
/v3/resetподключается к БД подPOSTGRES_SUSER/POSTGRES_SPASSWORDи выполняетREVOKE CONNECT ON DATABASE,pg_terminate_backend(),DROP SCHEMA … CASCADEиCREATE EXTENSION. На внешнем сервере под эти переменные нужна роль с правами суперпользователя, иначе функция сброса работать не будет. - Штатных средств репликации и переключения в Памир нет. Отказоустойчивость внешней СУБД (репликация, failover, резервное копирование) обеспечивается средствами самого сервера PostgreSQL.