refactor: объединить docker-compose_db.yml в docker-compose.yml через profiles
Два файла и две команды разворачивания заменены одним docker-compose.yml. postgres/redis перенесены туда же за профилем local-db — не поднимаются по умолчанию (app по умолчанию идёт на внешние DB_HOST/REDIS_HOST из .env), включаются явно через --profile local-db up -d. Проверено `docker compose config` в обоих режимах. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
29
README.md
29
README.md
@@ -35,23 +35,21 @@
|
|||||||
Сервис `api` **не публикует порты наружу** — доступен только контейнеру `web-react` внутри Docker-сети. Браузер обращается к `/api/*`, nginx внутри `web-react` перенаписывает и проксирует запрос на `api:8000` (см. `web-react/nginx.conf`). Пользователь никогда не обращается к API напрямую.
|
Сервис `api` **не публикует порты наружу** — доступен только контейнеру `web-react` внутри Docker-сети. Браузер обращается к `/api/*`, nginx внутри `web-react` перенаписывает и проксирует запрос на `api:8000` (см. `web-react/nginx.conf`). Пользователь никогда не обращается к API напрямую.
|
||||||
|
|
||||||
PostgreSQL и Redis могут запускаться как:
|
PostgreSQL и Redis могут запускаться как:
|
||||||
- отдельным compose-файлом `docker-compose_db.yml` (локально в Docker)
|
- сервисами `postgres`/`redis` в том же `docker-compose.yml`, за профилем `local-db` (локально в Docker)
|
||||||
- внешними сервисами (отдельный сервер, managed service) — достаточно прописать нужные `REDIS_HOST`/`DB_HOST` в переменных окружения
|
- внешними сервисами (отдельный сервер, managed service) — достаточно прописать нужные `REDIS_HOST`/`DB_HOST` в `.env`, профиль `local-db` не поднимать
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Быстрый старт
|
## Быстрый старт
|
||||||
|
|
||||||
### 1. Инфраструктура (PostgreSQL + Redis)
|
Один файл `docker-compose.yml` на всё. По умолчанию поднимает только приложение (`api` + `web-react` + `stats`) — БД и Redis ожидаются внешними (`DB_HOST`/`REDIS_HOST` в `.env`, см. «Переменные окружения»).
|
||||||
|
|
||||||
```bash
|
|
||||||
docker compose -f docker-compose_db.yml up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. Приложение
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
# Только приложение (внешние БД/Redis из .env)
|
||||||
docker compose up -d --build
|
docker compose up -d --build
|
||||||
|
|
||||||
|
# + локальные PostgreSQL и Redis в Docker (профиль local-db)
|
||||||
|
docker compose --profile local-db up -d --build
|
||||||
```
|
```
|
||||||
|
|
||||||
| Адрес | Что |
|
| Адрес | Что |
|
||||||
@@ -134,8 +132,7 @@ api-copp/
|
|||||||
├── .env.example # шаблон переменных окружения без секретов
|
├── .env.example # шаблон переменных окружения без секретов
|
||||||
├── Dockerfile.api # образ API
|
├── Dockerfile.api # образ API
|
||||||
├── Dockerfile.stats # образ дашборда статистики
|
├── Dockerfile.stats # образ дашборда статистики
|
||||||
├── docker-compose.yml # API + web-react + Stats
|
├── docker-compose.yml # api + web-react + stats (+ postgres/redis за профилем local-db)
|
||||||
├── docker-compose_db.yml # PostgreSQL + Redis
|
|
||||||
│
|
│
|
||||||
├── bd/
|
├── bd/
|
||||||
│ ├── __init__.py # Settings (pydantic), make_engine()
|
│ ├── __init__.py # Settings (pydantic), make_engine()
|
||||||
@@ -604,7 +601,7 @@ ALTER TABLE radar_results ADD COLUMN IF NOT EXISTS image_path VARCHAR(512);
|
|||||||
|
|
||||||
### 11. Реальные секреты в `docker-compose.yml` ✅
|
### 11. Реальные секреты в `docker-compose.yml` ✅
|
||||||
|
|
||||||
**Проблема:** пароли БД/Redis, `SECRET_KEY`, `ADMIN_KEY` были прописаны в открытом виде прямо в `docker-compose.yml` и `docker-compose_db.yml`, закоммичены в git.
|
**Проблема:** пароли БД/Redis, `SECRET_KEY`, `ADMIN_KEY` были прописаны в открытом виде прямо в `docker-compose.yml` (тогда ещё вместе с отдельным `docker-compose_db.yml`), закоммичены в git.
|
||||||
|
|
||||||
**Решение:** значения вынесены в `.env` (в `.gitignore`, не коммитится), compose-файлы читают их через `${VAR}`. Шаблон без секретов — `.env.example`. **Важно:** старые значения уже есть в истории git (коммит `71887b0`) — сама по себе эта правка их не отзывает, реальные пароли на серверах БД/Redis нужно ротировать отдельно.
|
**Решение:** значения вынесены в `.env` (в `.gitignore`, не коммитится), compose-файлы читают их через `${VAR}`. Шаблон без секретов — `.env.example`. **Важно:** старые значения уже есть в истории git (коммит `71887b0`) — сама по себе эта правка их не отзывает, реальные пароли на серверах БД/Redis нужно ротировать отдельно.
|
||||||
|
|
||||||
@@ -615,3 +612,11 @@ ALTER TABLE radar_results ADD COLUMN IF NOT EXISTS image_path VARCHAR(512);
|
|||||||
**Проблема:** `Dockerfile.api` ставил зависимости из `requirements.txt`, а не из `pyproject.toml`/`uv.lock` — версии успели разойтись (`redis==5.0.0` vs `>=7.1.0`, `sqlalchemy==2.0.32` vs `>=2.0.47`).
|
**Проблема:** `Dockerfile.api` ставил зависимости из `requirements.txt`, а не из `pyproject.toml`/`uv.lock` — версии успели разойтись (`redis==5.0.0` vs `>=7.1.0`, `sqlalchemy==2.0.32` vs `>=2.0.47`).
|
||||||
|
|
||||||
**Решение:** `Dockerfile.api` теперь ставит зависимости через `uv sync --frozen` напрямую из `pyproject.toml`/`uv.lock`. `requirements.txt` удалён — единственный источник правды. При переходе обнаружилась ещё одна расхождение: `python-multipart` (нужен FastAPI для `UploadFile`/`Form`, используется в `organizations_crud.py` при импорте .docx) был в `requirements.txt`, но отсутствовал в `pyproject.toml` — без него API падал при старте с `RuntimeError`. Добавлен в зависимости.
|
**Решение:** `Dockerfile.api` теперь ставит зависимости через `uv sync --frozen` напрямую из `pyproject.toml`/`uv.lock`. `requirements.txt` удалён — единственный источник правды. При переходе обнаружилась ещё одна расхождение: `python-multipart` (нужен FastAPI для `UploadFile`/`Form`, используется в `organizations_crud.py` при импорте .docx) был в `requirements.txt`, но отсутствовал в `pyproject.toml` — без него API падал при старте с `RuntimeError`. Добавлен в зависимости.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 13. Деплой требовал двух отдельных compose-файлов ✅
|
||||||
|
|
||||||
|
**Было:** `docker-compose.yml` (api + web-react + stats) и `docker-compose_db.yml` (postgres + redis) — два отдельных файла и две команды на разворачивание.
|
||||||
|
|
||||||
|
**Решение:** `postgres`/`redis` перенесены в тот же `docker-compose.yml`, за профилем `local-db` — не поднимаются командой `docker compose up -d` по умолчанию (приложение по умолчанию ходит на внешние `DB_HOST`/`REDIS_HOST` из `.env`), но доступны через `docker compose --profile local-db up -d`, когда нужна локальная БД. `docker-compose_db.yml` удалён.
|
||||||
|
|||||||
@@ -48,3 +48,45 @@ services:
|
|||||||
depends_on:
|
depends_on:
|
||||||
- api
|
- api
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
||||||
|
# ── Локальные БД (опционально) ─────────────────────────────────────────
|
||||||
|
# По умолчанию api ходит на внешние DB_HOST/REDIS_HOST из .env. Эти два
|
||||||
|
# сервиса поднимаются только явным флагом профиля:
|
||||||
|
# docker compose --profile local-db up -d
|
||||||
|
postgres:
|
||||||
|
image: postgres:latest
|
||||||
|
container_name: postgres
|
||||||
|
profiles: ["local-db"]
|
||||||
|
ports:
|
||||||
|
- "5432:5432"
|
||||||
|
environment:
|
||||||
|
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
|
||||||
|
- PGDATA=/var/lib/postgresql/data/pgdata
|
||||||
|
volumes:
|
||||||
|
- ./data/postgres:/var/lib/postgresql/data
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 10
|
||||||
|
start_period: 10s
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: redis:alpine
|
||||||
|
container_name: redis
|
||||||
|
profiles: ["local-db"]
|
||||||
|
command: >
|
||||||
|
redis-server
|
||||||
|
--requirepass ${REDIS_PASSWORD}
|
||||||
|
--appendonly yes
|
||||||
|
--appendfsync everysec
|
||||||
|
--maxmemory 256mb
|
||||||
|
--maxmemory-policy volatile-lru
|
||||||
|
--tcp-keepalive 60
|
||||||
|
--timeout 300
|
||||||
|
--loglevel notice
|
||||||
|
ports:
|
||||||
|
- 6379:6379
|
||||||
|
volumes:
|
||||||
|
- ./data/redis:/data
|
||||||
|
restart: always
|
||||||
|
|||||||
@@ -1,38 +0,0 @@
|
|||||||
services:
|
|
||||||
|
|
||||||
redis:
|
|
||||||
image: redis:alpine
|
|
||||||
container_name: redis
|
|
||||||
command: >
|
|
||||||
redis-server
|
|
||||||
--requirepass ${REDIS_PASSWORD}
|
|
||||||
--appendonly yes
|
|
||||||
--appendfsync everysec
|
|
||||||
--maxmemory 256mb
|
|
||||||
--maxmemory-policy volatile-lru
|
|
||||||
--tcp-keepalive 60
|
|
||||||
--timeout 300
|
|
||||||
--loglevel notice
|
|
||||||
ports:
|
|
||||||
- 6379:6379
|
|
||||||
volumes:
|
|
||||||
- ./data/redis:/data
|
|
||||||
restart: always
|
|
||||||
|
|
||||||
postgres:
|
|
||||||
image: postgres:latest
|
|
||||||
container_name: postgres
|
|
||||||
#restart: always
|
|
||||||
ports:
|
|
||||||
- "5432:5432"
|
|
||||||
environment:
|
|
||||||
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
|
|
||||||
- PGDATA=/var/lib/postgresql/data/pgdata
|
|
||||||
volumes:
|
|
||||||
- ./data/postgres:/var/lib/postgresql/data
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
|
||||||
interval: 5s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 10
|
|
||||||
start_period: 10s
|
|
||||||
Reference in New Issue
Block a user