161 lines
6.4 KiB
YAML
161 lines
6.4 KiB
YAML
|
|
# Прод-стек: db, minio, api и web в ОДНОЙ сети; наружу отдаёт только
|
|||
|
|
# web (порт 80). Postgres и MinIO портов наружу не пробрасывают вовсе —
|
|||
|
|
# они видны только контейнерам приложения.
|
|||
|
|
#
|
|||
|
|
# Образы api и web заранее собраны Drone (или вручную):
|
|||
|
|
# 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) закреплено: по нему считается имя сети. Drone и
|
|||
|
|
# ручной запуск обязаны давать одно и то же имя, иначе 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: — на случай ручной сборки без Drone: если образа нет,
|
|||
|
|
# 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:
|