Перейти к основному содержимому
  1. Posts/
  2. Self-Hosting/

Подключаем приложения к общей PostgreSQL и учимся её обслуживать. Часть 2

·1712 слов·9 минут· loading · loading · ·
Stilicho2011
Автор
Stilicho2011
Пишу о homelab, self-hosting, автоматизации и open-source решениях
Оглавление
Self-Hosting - This article is part of a series.
Part : This Article
Tip

Если вам понравилась эта статья, вы можете стать спонсором на boosty.

Введение
#

В первой части , когда мы подняли общую базу данных PostgreSQL и pgAdmin в Docker мы договорились, что в дальнейшем переведём на неё все сервисы, которым для работы нужна база данных Postgres, вместо того чтобы у каждого приложения был свой собственный контейнер с БД. В той же статье я оставил дисклеймер, что подключение сторонних приложений к единой базе - тема отдельной статьи. Не прошло и трех лет как я выполнил свое обещание. Вот эта статья.

В ней я разберу три вещи, которые логически идут одна за другой:

  1. Как правильно создать пользователя и базу данных под конкретное приложение - но не абы как, а по принципу наименьших привилегий.
  2. Как на практике подключить к нашей общей PostgreSQL реальный сервис - примером послужит Authentik, благо про него в блоге уже есть большая серия статей.
  3. Что вообще значит «обслуживание базы данных» и когда это действительно нужно делать руками, а когда PostgreSQL справляется сам.

Почему не стоит запускать все приложения от одного суперпользователя
#

Самый простой (и самый плохой, даже ужасный) вариант - выдать всем приложениям логин и пароль от суперпользователя postgres, которого мы создали в первой части, и не заморачиваться. Так действительно можно сделать и работать это будет. Как бы. Но у этого подхода есть накопительный негативный эффект, который проявится не сразу, но обязательно проявится не сразу:

  • любое приложение с доступом уровня суперпользователя технически имеет доступ в “чужие” базы данных на этом же сервере;
  • если у одного из приложений будет скомпрометировано (SQL-инъекцию, RCE, да что угодно), скомпрометированным окажется не только его собственная база, а весь инстанс PostgreSQL сразу;
  • бэкапить, чистить логи доступа и разбираться, кто и что сделал с базой, значительно проще, когда у каждого приложения свой пользователь и своя база данных.

Поэтому единственная правильная схема - у каждого приложения своя база данных и свой пользователь, который имеет права только и только на неё.

Дальше показываю, как это сделать в pgAdmin, на примере Authentik - у него, кстати, именно такая схема доступа рекомендована официально (кто бы сомневался, да?).


Создаём пользователя и базу данных для приложения
#

Заходим в pgAdmin (как подключиться к серверу и завести в нём подключение описано в первой части) и повторяем шаги ниже под каждое новое приложение. Пример - для Authentik, у вас может быть любое другое имя пользователя и базы.

Шаг 1. Создаём роль (пользователя)
#

В дереве слева: Servers → ваш Postgres-сервер → Login/Group Roles, ПКМ → Create → Login/Group Role…

  • Вкладка GeneralRole name: authentik
  • Вкладка DefinitionPassword: придумываем пароль, он понадобится в docker-compose.yml приложения
  • Вкладка Privileges → включаем только Can login, всё остальное (superuser, create role, create db и т.д.) оставляем выключенным

Сохраняем. На этом этапе у пользователя authentik нет прав вообще ни на что, кроме права подключиться к серверу - это не просто так, права мы выдадим точечно на следующих шагах.

Шаг 2. Создаём базу данных
#

Databases → ПКМ → Create → Database…

  • Database: authentik
  • Owner: authentik (тот самый пользователь из шага 1)

Сохраняем - база сразу принадлежит нужному пользователю, дополнительно никаких прав выдавать не нужно.

Шаг 3. Даём права на схему public
#

Это обязательный шаг для большинства приложений (включая Authentik) - они создают свои таблицы сами при первом запуске, а для этого им нужно право создавать объекты в схеме. ПКМ по базе authentikQuery Tool, выполняем:

GRANT USAGE, CREATE ON SCHEMA public TO authentik;

Шаг 4. Права на существующие таблицы (если база не пустая)
#

Если вы создаёте базу с нуля - можно пропустить, приложение создаст таблицы уже с правильным владельцем. Но если пересоздаёте базу под уже существующее приложение (например, переезжаете с его собственного контейнера БД на общий, как в этой статье), то на уже перенесённых таблицах права нужно выдать отдельно:

GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO authentik;

Шаг 5. Проверяем, что всё работает
#

В том же Query Tool базы authentik:

CREATE TABLE authentik_test (
    id SERIAL PRIMARY KEY,
    name TEXT
);
INSERT INTO authentik_test (name) VALUES ('ok');
SELECT * FROM authentik_test;
DROP TABLE authentik_test;

Если все четыре команды выполнились без ошибок доступа или еще чего-нибудь , то пользователь и база данных настроены правильно, можно переходить к подключению самого приложения.

Кстати, вот что у нас получилось, если нарисовать таблицу.

КомпонентЗначение
Пользовательauthentik
База данныхauthentik
ПраваCONNECT + CREATE + полный доступ на свою схему, и ничего за её пределами

Подключаем Authentik к общей PostgreSQL
#

Если вы разворачиваете Authentik с нуля - следуйте статье про первую настройку, но с одним отличием: не создавайте в docker-compose.yml собственный контейнер postgresql для Authentik - у нас уже есть общий, из первой части этой серии.

Убираем сервис postgresql из compose-файла Authentik и добавляем сервис Authentik в ту же docker-сеть database, где живёт наш общий Postgres:

services:
  server:
    image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2026.5.1} # проверьте актуальный тег на странице релизов перед установкой
    command: server
    environment:
      AUTHENTIK_SECRET_KEY: ваш_секретный_ключ
      AUTHENTIK_POSTGRESQL__HOST: postgres          # имя контейнера с общей БД из первой части
      AUTHENTIK_POSTGRESQL__NAME: authentik
      AUTHENTIK_POSTGRESQL__USER: authentik
      AUTHENTIK_POSTGRESQL__PASSWORD: пароль_из_шага_1
      AUTHENTIK_POSTGRESQL__PORT: 5432
    networks:
      - proxy
      - database                                    # та же сеть, где сидит общий postgres
    # остальные переменные и redis - без изменений, смотрите статью про первую настройку

networks:
  proxy:
    external: true
  database:
    external: true
Note

Правильно все чувствительные данные вынести в отдельный .env файл

Если раньше Authentik стучался в свою базу по внутреннему docker-имени authentik-postgresql, то теперь он идёт в тот же контейнер postgres, что и все остальные подключённые сервисы - просто под своим собственным логином, паролем и именем базы, которые мы завели в предыдущем разделе. Со стороны PostgreSQL это два полностью изолированных друг от друга «мира», физически работающих на одном инстансе.

Warning

Если вы переносите уже работающий Authentik со своей базы на общую, а не разворачиваете с нуля - обязательно снимите дамп через pg_dump со старого контейнера и восстановите его в новую базу через pg_restore или psql, прежде чем менять переменные окружения и удалять старый контейнер. Порядок действий для этого сценария - тема отдельного разговора, здесь не буду его упрощать до пары строк, чтобы не создавать ощущение, что это просто и тривиально.

Тот же принцип - отдельная роль, отдельная база, GRANT только на свою схему - работает для любого другого приложения: Nextcloud, Linkwarden, Vaultwarden и всех остальных сервисов и контейнеров, которые умеют работать с внешней PostgreSQL.


Базовое обслуживание PostgreSQL
#

Здесь важно сразу развенчать один миф: PostgreSQL не нужно вручную обслуживать в режиме «раз в неделю захожу и жму VACUUM». В PostgreSQL по умолчанию включён процесс autovacuum - фоновый демон, который сам следит за таблицами и запускает VACUUM/ANALYZE, когда накопилось достаточно «мёртвых» строк (удалённых или изменённых, но ещё физически не освобождённых).

Для подавляющего большинства self-hosted сценариев домашнего масштаба autovacuum справляется полностью сам, и ничего руками делать не нужно. Я бы даже сказал, что никогда ничего не делайте с базой данных, если не понимаете всех рисков.

Ручное обслуживание имеет смысл только в конкретных ситуациях:

VACUUM и VACUUM ANALYZE
#

VACUUM;
VACUUM ANALYZE;

VACUUM помечает место, занятое удалёнными/устаревшими строками, как свободное для повторного использования - но не возвращает его операционной системе, диск физически не уменьшается.

VACUUM ANALYZE дополнительно обновляет статистику по таблицам, которую использует планировщик запросов - полезно запустить руками после массовой загрузки или удаления большого объёма данных одной операцией, когда не хочется ждать, пока до этого дойдёт autovacuum.

VACUUM FULL
#

VACUUM FULL;

Это единственная команда, которая реально уменьшает файл базы на диске - она физически пересобирает таблицу. Но у этой операции есть своя цена: VACUUM FULL берёт эксклюзивную блокировку на таблицу на всё время операции - никто не сможет ни читать, ни писать в неё, пока команда не закончится.

На большой таблице сервиса в проде это может означать заметный простой. Использовать стоит точечно - например, после разового удаления огромного количества строк (почистили старые логи, снесли половину базы) - а не как рутинную операцию по расписанию. Но в принципе в homelab необходимость этой операции - что-то из области фантастики.

REINDEX
#

REINDEX DATABASE authentik;

Пересобирает индексы базы данных с нуля. Индексы в PostgreSQL тоже приводят со временем к «раздутию» (bloat), особенно на таблицах с частыми обновлениями - REINDEX полезен, если вы заметили, что запросы стали заметно медленнее, чем раньше, хотя объём данных не сильно вырос.

Note

Для доступа к консоли конкретной базы выполните docker exec -it postgres psql -U authentik -d authentik (замените имена на свои) - или выполняйте те же команды через Query Tool в pgAdmin, как в разделе про создание базы выше. Не забывайте ; в конце каждой команды.

Если у вас пользователь Authentik и периодически отваливается worker
#

Отдельный практический случай, который стоит держать в голове именно владельцам Authentik. Если время от времени вылетает ошибка про недоступный/отвалившийся worker - на моей практике чаще всего помогает прогнать полный набор команд обслуживания сразу, а не по одной:

  1. Подключаемся к консоли контейнера с базой (у меня это внешний контейнер с общей БД, как в этой статье, только не в Docker - у вас может быть иначе, если Authentik ещё не перевезён на общий Postgres):
docker exec -it postgres psql -U authentik -d authentik
  1. Выполняем весь набор команд обслуживания подряд:
VACUUM;
VACUUM ANALYZE;
VACUUM FULL;
REINDEX DATABASE authentik;

У меня это сняло проблему и больше она не появлялась. Но, как я уже писал выше, VACUUM FULL блокирует таблицу целиком на время выполнения - на боевом сервере с реальной нагрузкой стоит выполнять в определенный период времени.

Note

Официального issue на GitHub, который бы прямо связывал именно эту ошибку worker’а с необходимостью VACUUM, нет - в трекере Authentik есть несколько соседних тем про проблемы worker’а с PostgreSQL после отказа от Redis в версии 2025.10.0 (#19302, #20644), но в них решение было не через VACUUM, а через код в новых версиях и тюнинг подключений. Единственный issue, где VACUUM ANALYZE явно и с цифрами помог (#24179), - про деградацию скорости из-за JIT-компилятора Postgres на почве устаревшей статистики, а не про сам worker. Так что описанный выше способ - это моя личная рабочая практика, а не задокументированное решение от разработчиков. Делаете на свой страх и риск.

Подробнее про обслуживание PostgreSQL - в официальной документации.


Итог
#

Теперь у нас есть не просто «база данных в докере», а рабочая схема: общий инстанс PostgreSQL, у каждого приложения - изолированный пользователь и своя база с правами только на неё, и понимание, когда обслуживание нужно делать руками, а когда PostgreSQL прекрасно справляется сам через autovacuum. Дальше можно постепенно переводить остальные self-hosted сервисы с их собственных контейнеров БД на эту общую схему - принцип для всех одинаковый, отличаются только имена пользователя и базы.

Self-Hosting - This article is part of a series.
Part : This Article

Related

Начальная установка PostgreSQL и pgAdmin в Docker с помощью Docker Compose для новичков. Часть 1

··1894 слов·9 минут· loading · loading
Подробная инструкция по установке и настройке PostgreSQL на сервере. Рассмотрены шаги по установке, созданию пользователей и баз данных, настройке резервного копирования и базовой безопасности для стабильной и надёжной работы.

Authentik: настройка Reputation Policy

··500 слов·3 минут· loading · loading
Пошаговая настройка Reputation Policy и GeoIP в Authentik для ограничения доступа по IP-репутации и странам, с разбором типовых сценариев защиты.

Настройка email-уведомлений в Authentik

··399 слов·2 минут· loading · loading
Пошаговое руководство по настройке email-уведомлений в Authentik: подключение SMTP, включение уведомлений о событиях, настройка шаблонов писем и проверка доставки.