База данных на том же сервере, что и приложение, или база с открытым в интернет портом 5432 — две самые частые причины ночных инцидентов у небольших проектов. Мы уже разбирали, когда проекту пора уходить с обычного VPS и зачем небольшому проекту приватная сеть. Здесь — практика: собираем связку «приложение + управляемый PostgreSQL», в которой база вообще не видна из интернета.

Что получится в конце:

  • кластер PostgreSQL в приватной сети (VPC) — без публичного адреса;
  • приложение в той же сети ходит к базе по TLS с проверкой сертификата сервера;
  • пароль лежит в секретах приложения, а не в репозитории;
  • есть бэкап, а база одной командой переводится в отказоустойчивую пару.

Схема: приложение и кластер managed PostgreSQL в одной VPC. Из интернета открыт только HTTPS к приложению, к базе доступа нет; приложение ходит к базе по TLS с verify-full

Что такое managed PostgreSQL

Managed PostgreSQL — это PostgreSQL, который обслуживает провайдер: установка, обновления, бэкапы, реплики и переключение при сбое. Вы получаете строку подключения и работаете с базой как обычно — psql, ORM, миграции, — но не администрируете сервер под ней. В Татнет это отдельная услуга Managed PostgreSQL: версии 15–17, один узел или отказоустойчивая пара на Patroni, восстановление на момент времени (PITR).

Всё делаем из терминала через CLI Татнет. То же самое доступно в панели управления — раздел Managed PostgreSQL.

Шаг 0. CLI и ключ

CLI ставить не обязательно — достаточно npx:

npx tatnet@latest --help

Для постоянной работы: npm install -g tatnet. Ключ доступа создаётся в панели, сохраняется командой tatnet auth login, проверяется — tatnet auth status. Подробности — в документации CLI.

Дальше в примерах — проект my-saas. Чтобы не повторять его в каждой команде:

export TATNET_PROJECT=my-saas

Шаг 1. Приватная сеть

Сначала смотрим, какие регионы, версии PostgreSQL и тарифы доступны:

tatnet pg regions -o json

Создаём сеть в нужном регионе. Подсеть — любая приватная, кроме 10.0.0.0/12: этот диапазон зарезервирован под инфраструктуру платформы.

REGION=<id региона из tatnet pg regions>

tatnet vpc create --name app-net --cluster $REGION --subnet 10.20.0.0/24

ID сети понадобится дальше — его покажет tatnet vpc list. Приватные сети на Татнет бесплатны на любом тарифе.

Шаг 2. Кластер PostgreSQL

VPC=<id сети app-net>

tatnet pg create \
  --name app-db \
  --region $REGION \
  --plan db1.small \
  --version 17 \
  --topology single \
  --vpc $VPC \
  --allow 10.20.0.0/24 \
  --database app \
  --db-user app

Что здесь важно:

  • --vpc — кластер получает адрес внутри приватной сети;
  • --allow — список адресов, которым разрешено подключаться. Мы разрешаем только подсеть нашей VPC. Список задаётся отдельно от привязки к сети: если позже понадобится доступ, например, с офисного IP, его добавляют сюда, а не открывают базу целиком;
  • --topology single — один узел. На старте этого достаточно, переход в HA — в шаге 5.

Доступны PostgreSQL 15, 16 и 17. Когда кластер будет готов, адрес подключения покажет команда:

tatnet pg get app-db -o json

Шаг 3. Подключение по TLS с проверкой сервера

Шифровать соединение мало — нужно ещё убедиться, что клиент разговаривает именно с вашей базой. Для этого у каждого кластера свой корневой сертификат (CA):

tatnet pg ca app-db --out cluster-ca.pem

В строке подключения указываем sslmode=verify-full и путь к этому сертификату:

psql "postgresql://app:<пароль>@<адрес>:5432/app?sslmode=verify-full&sslrootcert=cluster-ca.pem"

verify-full проверяет и подпись сертификата, и то, что имя сервера в нём совпадает с адресом, к которому вы подключаетесь. Режимы require и prefer этого не делают.

CA-сертификат — не секрет, его можно хранить в репозитории рядом с кодом. Секрет — пароль.

Шаг 4. Приложение в той же сети

Подключаем приложение к сети app-net. Для нового приложения — флаг --vpc при создании (tatnet app create ... --vpc $VPC), для существующего:

tatnet app update api --vpc $VPC

При смене сети платформа пересоздаёт реплики приложения — возможен короткий перерыв. При стратегии rolling несколько минут часть реплик ещё работает в старой сети. Если это недопустимо, перед сменой переключите стратегию на recreate.

Сеть должна быть в том же регионе, что и приложение.

Теперь кладём строку подключения в секреты приложения:

tatnet app env set api DATABASE_URL \
  "postgresql://app:<пароль>@<адрес>:5432/app?sslmode=verify-full&sslrootcert=./cluster-ca.pem" \
  --secret

В коде ничего особенного не нужно. Пример для Node.js и драйвера pg:

import fs from "node:fs";
import pg from "pg";

const pool = new pg.Pool({
  connectionString: process.env.DATABASE_URL,
  ssl: {
    ca: fs.readFileSync("./cluster-ca.pem", "utf8"),
    rejectUnauthorized: true, // проверка сертификата и имени сервера
  },
});

Миграции удобно запускать перед каждым выкатом — для этого у приложения есть команда до деплоя: tatnet app update api --predeploy-command "npm run migrate".

Пароль потерялся или утёк — его можно сменить:

tatnet pg reset-password app-db app

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

Шаг 5. Бэкап и переход в HA

Перед рискованной миграцией снимаем полный бэкап с понятной меткой:

tatnet pg backup create app-db before-migration-42
tatnet pg backup list app-db

Кластер поддерживает восстановление на момент времени: данные поднимаются в новый кластер, а текущий остаётся нетронутым. Так можно спокойно сравнить состояние «до» и «после» и забрать из копии только то, что нужно.

Когда проект вырос и простой базы стал стоить денег, переводим её в отказоустойчивую пару на Patroni:

tatnet pg topology app-db ha

Переключение single → HA проходит без простоя. Так же без простоя меняется тариф — узлы ресайзятся по одному, лидер последним:

tatnet pg plan app-db db1.medium

Тариф меняется только вверх: память, vCPU и диск нового тарифа должны быть не меньше текущих. Поэтому начинать стоит с минимально достаточного размера, а не «с запасом».

Сколько это стоит в месяц

Счёт за такую связку складывается из двух частей: тарифа приложения и тарифа кластера PostgreSQL.

  • Кластер — за узел. У одиночного кластера один узел, у HA-пары — два, поэтому переход в HA удваивает стоимость базы. db1.small — 2 vCPU, 4 ГБ памяти и 40 ГБ диска; db1.medium — вдвое больше и вдвое дороже.
  • Почасово. Списание идёт с баланса за каждый час работы узла, так что тестовый кластер, поднятый на вечер, обходится в рубли, а не в месячную подписку.
  • Приложение — по тарифу Татнет Apps. Платные тарифы включают часы Active CPU в месяц, сверх них вычисления оплачиваются почасово.
  • Сеть бесплатна. Приватная сеть ничего не стоит, а публичный IP базе в этой схеме не нужен.

Актуальные цены узлов и тарифов приложений — на странице тарифов: там же видно, во что обойдётся одиночный кластер и HA-пара.

Итого

  1. Сеть: tatnet vpc create.
  2. Кластер в этой сети с allowlist только на её подсеть: tatnet pg create --vpc --allow.
  3. TLS с проверкой сервера: tatnet pg ca + sslmode=verify-full.
  4. Приложение в ту же сеть, строка подключения — в секреты.
  5. Бэкап перед рискованными изменениями, HA — когда простой начнёт стоить денег.

Полный справочник команд — в документации Managed PostgreSQL. Создать первый кластер можно в панели Татнет.