axe/compose.prod.yaml

161 lines
6.4 KiB
YAML
Raw Permalink Normal View History

2026-10-18 19:07:25 +00:00
# Прод-стек: db, minio, api и web в ОДНОЙ сети; наружу отдаёт только
# web (порт 80). Postgres и MinIO портов наружу не пробрасывают вовсе —
# они видны только контейнерам приложения.
#
# Образы api и web заранее собраны CI (или вручную):
2026-10-18 19:07:25 +00:00
# docker build -t building-mgmt-api:latest . # в этом репо
# docker build -t building-mgmt-web:latest . # в репо web
#
# Запуск и обновление (env-файл живёт на сервере, в git не входит):
# docker compose -p building-mgmt \
# --env-file /opt/building-mgmt/.env \
# -f compose.prod.yaml up -d --wait
#
# Имя проекта (-p) закреплено: по нему считается имя сети. CI и
2026-10-18 19:07:25 +00:00
# ручной запуск обязаны давать одно и то же имя, иначе web не найдёт
# api и стек разъедется на два.
#
# ${VAR} берутся из env-файла (--env-file): секреты в YAML не
# дублируются. `:?` — фейл-фаст: без обязательной переменной compose
# упадёт при разборе файла, а не поднимет стек с пустым паролем.
services:
db:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_USER: ${POSTGRES_USER:?POSTGRES_USER is required}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}
POSTGRES_DB: ${POSTGRES_DB:?POSTGRES_DB is required}
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
interval: 5s
timeout: 5s
retries: 12
# Потолок памяти: без него при аномалии postgres сожрёт всю машину.
# Подправьте под ресурсы сервера.
mem_limit: 1g
networks:
- app
# Портов нет: наружу база не видна, только сеть app.
minio:
# Образ собирается из официального бинарника релиза 2024-07-26 —
# версии до ухода MinIO из опенсорса (см. deploy/minio/Dockerfile).
build:
context: deploy/minio
image: minio/minio:RELEASE.2024-07-26T20-48-21Z
restart: unless-stopped
command: server /data
environment:
# Ключи MinIO — это же S3-ключи приложения: одна пара секретов
# вместо двух.
MINIO_ROOT_USER: ${S3_ACCESS_KEY:?S3_ACCESS_KEY is required}
MINIO_ROOT_PASSWORD: ${S3_SECRET_KEY:?S3_SECRET_KEY is required}
volumes:
- miniodata:/data
healthcheck:
test: ["CMD-SHELL", "wget -q -O /dev/null http://localhost:9000/minio/health/live || exit 1"]
interval: 5s
timeout: 5s
retries: 12
mem_limit: 512m
networks:
- app
# Портов нет: S3 и консоль видна только сеть app. Разовый проброс
# консоли для отладки:
# docker compose -p building-mgmt --env-file /opt/building-mgmt/.env \
# -f compose.prod.yaml run --rm -p 9443:9001 minio server /data --console-address :9001
api:
image: building-mgmt-api:latest
# build: — на случай ручной сборки без CI: если образа нет,
2026-10-18 19:07:25 +00:00
# compose соберёт его из этого же репо; готовый образ не трогает.
build:
context: .
restart: unless-stopped
depends_on:
db:
condition: service_healthy
minio:
condition: service_healthy
environment:
# Ссылки на сервисы внутри сети подставляются сами — в env-файле
# их держать не нужно (там только секреты и внешние настройки).
- DATABASE_URL=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}?sslmode=disable
- S3_ENDPOINT=http://minio:9000
# path-style обязателен: поддоменные имена внутри сети не резолвятся.
- S3_USE_PATH_STYLE=true
# Дальше — передача значений из env-файла (--env-file): не
# заданная переменная просто не попадёт в контейнер, и упадут
# дефолты приложения (тот же JWT_SECRET/S3 фейл-фаст на старте).
- S3_REGION
- S3_BUCKET
- S3_ACCESS_KEY
- S3_SECRET_KEY
- JWT_SECRET
- APP_ENV
- COOKIE_SECURE
- TRUSTED_PROXIES
- CORS_ORIGINS
- LOG_LEVEL
- LOG_FORMAT
- GIN_MODE
- SWAGGER
- APP_BASE_URL
- PHOTO_MAX_BYTES
- PHOTO_MAX_PER_TICKET
- TICKET_RETENTION_DAYS
- DB_MAX_CONNS
- DB_MIN_CONNS
- DB_MAX_CONN_LIFETIME
- DB_MAX_CONN_IDLE_TIME
- SMTP_HOST
- SMTP_PORT
- SMTP_USER
- SMTP_PASSWORD
- SMTP_FROM
- SMTP_TLS
- DATA_ENCRYPTION_KEY
- TELEGRAM_BOT_TOKEN
- TELEGRAM_API_URL
- TELEGRAM_NOTIFY_AFTER
- TELEGRAM_TICK_EVERY
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://localhost:8080/ping || exit 1"]
interval: 30s
timeout: 3s
retries: 5
# Датасерверу 15 секунд на завершение текущих запросов (graceful
# shutdown внутри api рассчитан на 15s), потом SIGKILL.
stop_grace_period: 20s
mem_limit: 512m
networks:
- app
# Портов нет: API доступен только web-контейнеру.
web:
# Образ собирается в репо веба: docker build -t building-mgmt-web:latest .
image: building-mgmt-web:latest
restart: unless-stopped
depends_on:
api:
condition: service_healthy
ports:
# Единственный порт наружу. TLS терминалирует перед этим nginx
# (балансировщик / Caddy / Traefik), HSTS веб отдаёт сам.
- "80:80"
mem_limit: 256m
networks:
- app
networks:
app:
driver: bridge
volumes:
pgdata:
miniodata: