Убирает свой Postgres — БД физически переезжает на VPS с Vaultwarden
backend будет жить на отдельном, ещё не арендованном VPS — свой контейнер `db` и бэкапы (scripts/backup.sh) здесь больше не нужны и переехали в netrunner-data, где Postgres теперь физически стоит. DATABASE_URL собирается из DB_HOST/DB_PORT (внешний IP того VPS) с обязательным sslmode=require — трафик пересекает публичную сеть между двумя разными серверами. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+16
-20
@@ -6,17 +6,22 @@
|
|||||||
# (например `openssl rand -base64 24`) и никогда не коммитить .env с настоящим
|
# (например `openssl rand -base64 24`) и никогда не коммитить .env с настоящим
|
||||||
# значением (см. .gitignore — .env/.env.* уже исключены).
|
# значением (см. .gitignore — .env/.env.* уже исключены).
|
||||||
#
|
#
|
||||||
# ДЛЯ ЛОКАЛЬНЫХ ТЕСТОВ НА ТВОЕМ ПК:
|
# Postgres физически стоит НЕ на этом VPS, а на отдельном сервере вместе с
|
||||||
# DATABASE_URL=postgres://netrunner_admin:CHANGE_ME_DB_PASSWORD@<ip-впс>:5432/netrunner
|
# Vaultwarden (см. netrunner-data/docker-compose.yml, сервис `db`) — этот
|
||||||
#
|
# бэкенд подключается к нему по сети. Полный DATABASE_URL собирает сам
|
||||||
# ДЛЯ ЗАПУСКА НА САМОЙ ВПС (Через Docker Compose):
|
# docker-compose.prod.yml из DB_USER/DB_PASSWORD/DB_HOST/DB_PORT/DB_NAME ниже
|
||||||
# DATABASE_URL=postgres://netrunner_admin:CHANGE_ME_DB_PASSWORD@db:5432/netrunner
|
# (не пишите его здесь отдельной строкой — env_file не подставляет ${...},
|
||||||
|
# в отличие от самого docker-compose, так что отдельная строка DATABASE_URL
|
||||||
DATABASE_URL=postgres://netrunner_admin:CHANGE_ME_DB_PASSWORD@db:5432/netrunner
|
# тут просто не сработает). sslmode=require обязателен: без него подключение
|
||||||
|
# к hostssl-правилу в pg_hba.conf того сервера будет отклонено.
|
||||||
|
|
||||||
DB_USER=netrunner_admin
|
DB_USER=netrunner_admin
|
||||||
DB_NAME=netrunner
|
DB_NAME=netrunner
|
||||||
DB_PASSWORD=CHANGE_ME_DB_PASSWORD
|
DB_PASSWORD=CHANGE_ME_DB_PASSWORD
|
||||||
|
# IP VPS, где физически стоит Postgres (netrunner-data). Совпадает с DATA_VPS_IP
|
||||||
|
# в CI-переменных netrunner-data.
|
||||||
|
DB_HOST=CHANGE_ME_DB_HOST_IP
|
||||||
|
DB_PORT=5432
|
||||||
|
|
||||||
# Кеш курса TON (не источник истины — если недоступен, приложение просто
|
# Кеш курса TON (не источник истины — если недоступен, приложение просто
|
||||||
# ходит в TonAPI напрямую на каждый инвойс, как раньше).
|
# ходит в TonAPI напрямую на каждый инвойс, как раньше).
|
||||||
@@ -30,18 +35,9 @@ ARGON_SALT=CHANGE_ME_ARGON_SALT_MIN_16_CHARS
|
|||||||
GRAFANA_PASSWORD=CHANGE_ME_GRAFANA_PASSWORD
|
GRAFANA_PASSWORD=CHANGE_ME_GRAFANA_PASSWORD
|
||||||
TON_MASTER_WALLET=UQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKK8y
|
TON_MASTER_WALLET=UQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKK8y
|
||||||
|
|
||||||
# =====================================================================
|
# Бэкапы Postgres (pg_dump + опциональный rclone) теперь настраиваются в
|
||||||
# === БЭКАПЫ POSTGRES (см. scripts/backup.sh, сервис `backup` в
|
# netrunner-data/.env (там же, где физически стоит БД) — см.
|
||||||
# === docker-compose.prod.yml) ===
|
# netrunner-data/scripts/backup.sh. Здесь их больше нет.
|
||||||
# =====================================================================
|
|
||||||
# Без RCLONE_REMOTE/RCLONE_CONFIG_CONTENT бэкапы всё равно снимаются каждые
|
|
||||||
# BACKUP_INTERVAL_SEC (по умолчанию 6ч) и хранятся локально в volume
|
|
||||||
# netrunner_db_backups — но только на этом же VPS. Для реальной защиты от
|
|
||||||
# падения диска/потери сервера нужна офсайт-копия:
|
|
||||||
# BACKUP_INTERVAL_SEC=21600
|
|
||||||
# BACKUP_RETENTION_DAYS=14
|
|
||||||
# RCLONE_REMOTE=b2:netrunner-backups
|
|
||||||
# RCLONE_CONFIG_CONTENT содержимое rclone.conf одной переменной, см. rclone.conf.example
|
|
||||||
|
|
||||||
# Опционально: без него оплата через @CryptoBot вернёт "provider not
|
# Опционально: без него оплата через @CryptoBot вернёт "provider not
|
||||||
# supported", остальные провайдеры продолжают работать. Токен — у @CryptoBot:
|
# supported", остальные провайдеры продолжают работать. Токен — у @CryptoBot:
|
||||||
@@ -98,7 +94,7 @@ COOKIE_SECURE=true
|
|||||||
# === DEPLOYMENT & REPOSITORY SETTINGS ===
|
# === DEPLOYMENT & REPOSITORY SETTINGS ===
|
||||||
# =====================================================================
|
# =====================================================================
|
||||||
GHCR_TOKEN=ghp_ТВОЙ_ТОКЕН_ОТ_ГИТХАБА_ДЛЯ_ДОСТУПА_К_РЕЕСТРУ
|
GHCR_TOKEN=ghp_ТВОЙ_ТОКЕН_ОТ_ГИТХАБА_ДЛЯ_ДОСТУПА_К_РЕЕСТРУ
|
||||||
VPS_IP=77.110.106.113
|
VPS_IP=CHANGE_ME_VPS_IP
|
||||||
DEPLOY_DIR=/root/netrunner-core
|
DEPLOY_DIR=/root/netrunner-core
|
||||||
BINARY_NAME=netrunner-control-plane
|
BINARY_NAME=netrunner-control-plane
|
||||||
# Образ, который тянет прод-стек (docker-compose.prod.yml).
|
# Образ, который тянет прод-стек (docker-compose.prod.yml).
|
||||||
|
|||||||
+11
-56
@@ -1,6 +1,15 @@
|
|||||||
# =====================================================================
|
# =====================================================================
|
||||||
# PRODUCTION — VPS только тянет готовый образ из GHCR и запускает его.
|
# PRODUCTION — VPS только тянет готовый образ из GHCR и запускает его.
|
||||||
# Никакой компиляции Rust на сервере. Деплой = pull + migrate + up.
|
# Никакой компиляции Rust на сервере. Деплой = pull + migrate + up.
|
||||||
|
#
|
||||||
|
# ВАЖНО: своего Postgres здесь больше нет. БД физически стоит на отдельном
|
||||||
|
# VPS (см. netrunner-data/docker-compose.yml — там же Vaultwarden, тот же
|
||||||
|
# Postgres-процесс, вторая база) и слушает по сети, не в одном
|
||||||
|
# Docker-стеке с этим compose. DATABASE_URL ниже указывает на DB_HOST:DB_PORT
|
||||||
|
# (внешний IP того VPS), не на "db" как раньше — и требует sslmode=require,
|
||||||
|
# т.к. трафик идёт по публичной сети между двумя разными серверами. Бэкапы
|
||||||
|
# тоже переехали туда же (netrunner-data/scripts/backup.sh) — дампить
|
||||||
|
# логичнее там, где физически лежат данные.
|
||||||
# =====================================================================
|
# =====================================================================
|
||||||
services:
|
services:
|
||||||
# One-shot: применяет миграции и завершается. Требует только DATABASE_URL.
|
# One-shot: применяет миграции и завершается. Требует только DATABASE_URL.
|
||||||
@@ -9,10 +18,7 @@ services:
|
|||||||
container_name: netrunner-migrate
|
container_name: netrunner-migrate
|
||||||
command: ["./netrunner-control-plane", "--migrate"]
|
command: ["./netrunner-control-plane", "--migrate"]
|
||||||
environment:
|
environment:
|
||||||
- DATABASE_URL=postgres://${DB_USER}:${DB_PASSWORD}@db:5432/${DB_NAME}
|
- DATABASE_URL=postgres://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT:-5432}/${DB_NAME}?sslmode=require
|
||||||
depends_on:
|
|
||||||
db:
|
|
||||||
condition: service_healthy
|
|
||||||
restart: "no"
|
restart: "no"
|
||||||
networks:
|
networks:
|
||||||
- netrunner_grid
|
- netrunner_grid
|
||||||
@@ -28,12 +34,10 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
- APP_ENV=production
|
- APP_ENV=production
|
||||||
- FRONTEND_DIR=/app/frontend/dist
|
- FRONTEND_DIR=/app/frontend/dist
|
||||||
- DATABASE_URL=postgres://${DB_USER}:${DB_PASSWORD}@db:5432/${DB_NAME}
|
- DATABASE_URL=postgres://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT:-5432}/${DB_NAME}?sslmode=require
|
||||||
volumes:
|
volumes:
|
||||||
- ./keys:/app/keys:ro
|
- ./keys:/app/keys:ro
|
||||||
depends_on:
|
depends_on:
|
||||||
db:
|
|
||||||
condition: service_healthy
|
|
||||||
redis:
|
redis:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
migrate:
|
migrate:
|
||||||
@@ -47,24 +51,6 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- netrunner_grid
|
- netrunner_grid
|
||||||
|
|
||||||
db:
|
|
||||||
image: postgres:16-alpine
|
|
||||||
container_name: netrunner-db
|
|
||||||
restart: always
|
|
||||||
environment:
|
|
||||||
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
|
||||||
POSTGRES_USER: ${DB_USER}
|
|
||||||
POSTGRES_DB: ${DB_NAME}
|
|
||||||
volumes:
|
|
||||||
- netrunner_db_data:/var/lib/postgresql/data
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD-SHELL", "pg_isready -U ${DB_USER} -d ${DB_NAME}"]
|
|
||||||
interval: 5s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 5
|
|
||||||
networks:
|
|
||||||
- netrunner_grid
|
|
||||||
|
|
||||||
redis:
|
redis:
|
||||||
image: redis:7-alpine
|
image: redis:7-alpine
|
||||||
container_name: netrunner-redis
|
container_name: netrunner-redis
|
||||||
@@ -75,31 +61,6 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- netrunner_grid
|
- netrunner_grid
|
||||||
|
|
||||||
# Периодический pg_dump + опциональная офсайт-копия через rclone (см.
|
|
||||||
# scripts/backup.sh). RCLONE_REMOTE/RCLONE_CONFIG — задать в .env, если нужна
|
|
||||||
# копия за пределы этого VPS (настоятельно рекомендуется — единственная
|
|
||||||
# локальная копия на volume ничем не защищена от падения диска этой машины).
|
|
||||||
backup:
|
|
||||||
image: postgres:16-alpine
|
|
||||||
container_name: netrunner-backup
|
|
||||||
restart: always
|
|
||||||
entrypoint: ["/bin/sh", "/scripts/backup.sh"]
|
|
||||||
environment:
|
|
||||||
- DATABASE_URL=postgres://${DB_USER}:${DB_PASSWORD}@db:5432/${DB_NAME}
|
|
||||||
- BACKUP_DIR=/backups
|
|
||||||
- BACKUP_INTERVAL_SEC=${BACKUP_INTERVAL_SEC:-21600}
|
|
||||||
- BACKUP_RETENTION_DAYS=${BACKUP_RETENTION_DAYS:-14}
|
|
||||||
- RCLONE_REMOTE=${RCLONE_REMOTE:-}
|
|
||||||
- RCLONE_CONFIG_CONTENT=${RCLONE_CONFIG_CONTENT:-}
|
|
||||||
volumes:
|
|
||||||
- ./scripts/backup.sh:/scripts/backup.sh:ro
|
|
||||||
- netrunner_db_backups:/backups
|
|
||||||
depends_on:
|
|
||||||
db:
|
|
||||||
condition: service_healthy
|
|
||||||
networks:
|
|
||||||
- netrunner_grid
|
|
||||||
|
|
||||||
# ==========================================
|
# ==========================================
|
||||||
# МОНИТОРИНГ
|
# МОНИТОРИНГ
|
||||||
# ==========================================
|
# ==========================================
|
||||||
@@ -161,13 +122,7 @@ services:
|
|||||||
|
|
||||||
networks:
|
networks:
|
||||||
netrunner_grid:
|
netrunner_grid:
|
||||||
# Явное имя (не дефолтный <project>_netrunner_grid) — на этот же bridge
|
|
||||||
# снаружи подключается netrunner-data/docker-compose.yml (Vaultwarden) как
|
|
||||||
# external-сеть, ссылаясь по этому фиксированному имени.
|
|
||||||
name: netrunner_grid
|
|
||||||
driver: bridge
|
driver: bridge
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
netrunner_db_data:
|
|
||||||
netrunner_db_backups:
|
|
||||||
grafana_data:
|
grafana_data:
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
# Конфиг rclone для офсайт-копии бэкапов Postgres (см. scripts/backup.sh).
|
|
||||||
#
|
|
||||||
# 1. Скопировать этот файл в rclone.conf (рядом с docker-compose.prod.yml на VPS)
|
|
||||||
# и заполнить реальными данными удалённого хранилища (Backblaze B2, S3,
|
|
||||||
# другой VPS по SFTP — что угодно, что поддерживает rclone).
|
|
||||||
# 2. Прописать в .env: RCLONE_REMOTE=b2:netrunner-backups (имя секции ниже
|
|
||||||
# + путь/бакет), совпадающее с именем секции [remote-name] тут.
|
|
||||||
# 3. Пустой/незаполненный rclone.conf — не ошибка: офсайт-копия просто не
|
|
||||||
# выполнится (см. лог "не удалось скопировать"), локальный дамп всё равно
|
|
||||||
# создаётся каждый цикл.
|
|
||||||
#
|
|
||||||
# Пример для Backblaze B2:
|
|
||||||
# [b2]
|
|
||||||
# type = b2
|
|
||||||
# account = YOUR_B2_ACCOUNT_ID
|
|
||||||
# key = YOUR_B2_APPLICATION_KEY
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
# Периодический pg_dump с опциональной офсайт-копией. Запускается как отдельный
|
|
||||||
# долгоживущий контейнер (см. docker-compose.prod.yml/docker-compose.dev-remote.yml,
|
|
||||||
# сервис `backup`) — сам себе крон через бесконечный цикл + sleep, без внешнего
|
|
||||||
# cron-демона в образе postgres:16-alpine.
|
|
||||||
#
|
|
||||||
# Обязательные переменные окружения: DATABASE_URL, BACKUP_DIR (примонтированный volume).
|
|
||||||
# Опциональные: BACKUP_INTERVAL_SEC (по умолчанию 21600 = 6ч), BACKUP_RETENTION_DAYS
|
|
||||||
# (по умолчанию 14), RCLONE_REMOTE (например "b2:netrunner-backups" — если не задан,
|
|
||||||
# офсайт-копия просто пропускается, бэкапы остаются только локально на VPS) и
|
|
||||||
# RCLONE_CONFIG_CONTENT (содержимое rclone.conf целиком, одной строкой/переменной
|
|
||||||
# окружения — без bind-mount'а файла, чтобы не требовать его существования на диске
|
|
||||||
# при первом деплое).
|
|
||||||
set -eu
|
|
||||||
|
|
||||||
BACKUP_DIR="${BACKUP_DIR:-/backups}"
|
|
||||||
INTERVAL="${BACKUP_INTERVAL_SEC:-21600}"
|
|
||||||
RETENTION_DAYS="${BACKUP_RETENTION_DAYS:-14}"
|
|
||||||
|
|
||||||
mkdir -p "$BACKUP_DIR"
|
|
||||||
|
|
||||||
if [ -n "${RCLONE_REMOTE:-}" ] && ! command -v rclone >/dev/null 2>&1; then
|
|
||||||
echo "[backup] Устанавливаю rclone для офсайт-копий..."
|
|
||||||
apk add --no-cache rclone >/dev/null
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -n "${RCLONE_CONFIG_CONTENT:-}" ]; then
|
|
||||||
mkdir -p /root/.config/rclone
|
|
||||||
printf '%s\n' "$RCLONE_CONFIG_CONTENT" > /root/.config/rclone/rclone.conf
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "[backup] Запущен. Интервал: ${INTERVAL}с, хранение: ${RETENTION_DAYS}д, офсайт: ${RCLONE_REMOTE:-<не настроен>}"
|
|
||||||
|
|
||||||
while true; do
|
|
||||||
timestamp=$(date -u +%Y%m%dT%H%M%SZ)
|
|
||||||
dump_file="$BACKUP_DIR/netrunner_${timestamp}.sql.gz"
|
|
||||||
|
|
||||||
echo "[backup] $(date -u +%FT%TZ) Снимаю дамп -> $dump_file"
|
|
||||||
if pg_dump "$DATABASE_URL" | gzip > "$dump_file.tmp"; then
|
|
||||||
mv "$dump_file.tmp" "$dump_file"
|
|
||||||
echo "[backup] Готово: $(du -h "$dump_file" | cut -f1)"
|
|
||||||
else
|
|
||||||
echo "[backup] ОШИБКА: pg_dump упал, файл не сохранён" >&2
|
|
||||||
rm -f "$dump_file.tmp"
|
|
||||||
sleep "$INTERVAL"
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -n "${RCLONE_REMOTE:-}" ]; then
|
|
||||||
if rclone copy "$dump_file" "$RCLONE_REMOTE" 2>&1; then
|
|
||||||
echo "[backup] Скопировано на $RCLONE_REMOTE"
|
|
||||||
else
|
|
||||||
echo "[backup] ОШИБКА: не удалось скопировать на $RCLONE_REMOTE (локальная копия сохранена)" >&2
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Локальная ротация — офсайт-копия (если настроена) хранится по правилам
|
|
||||||
# самого remote, это не отменяет отдельную политику хранения там.
|
|
||||||
find "$BACKUP_DIR" -name 'netrunner_*.sql.gz' -mtime "+${RETENTION_DAYS}" -delete
|
|
||||||
|
|
||||||
sleep "$INTERVAL"
|
|
||||||
done
|
|
||||||
Reference in New Issue
Block a user