009 add docker compose
This commit is contained in:
+16
@@ -0,0 +1,16 @@
|
|||||||
|
FROM python:3.14-slim
|
||||||
|
|
||||||
|
ENV PYTHONUNBUFFERED=1
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
RUN pip install --no-cache-dir poetry
|
||||||
|
|
||||||
|
COPY pyproject.toml poetry.lock ./
|
||||||
|
RUN poetry config virtualenvs.create false \
|
||||||
|
&& poetry install --no-interaction --no-root
|
||||||
|
|
||||||
|
COPY app ./app
|
||||||
|
COPY config.yaml ./config.yaml
|
||||||
|
|
||||||
|
CMD ["poetry", "run", "uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
|
||||||
+25
-1
@@ -1,6 +1,25 @@
|
|||||||
services:
|
services:
|
||||||
|
app:
|
||||||
|
image: yusupal1ev/g2s-aggregator:0.0.0
|
||||||
|
environment:
|
||||||
|
G2S_CONFIG_FILE: /app/config.yaml
|
||||||
|
G2S_REPOSITORY__REDIS_DSN: redis://redis:6379/0
|
||||||
|
G2S_OBSERVABILITY__OTLP_ENDPOINT: http://signoz:4317
|
||||||
|
PYTHONUNBUFFERED: "1"
|
||||||
|
ports:
|
||||||
|
- "8000:8000"
|
||||||
|
depends_on:
|
||||||
|
- redis
|
||||||
|
- signoz
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: redis:7-alpine
|
||||||
|
command: ["redis-server", "--save", "", "--appendonly", "no"]
|
||||||
|
ports:
|
||||||
|
- "6379:6379"
|
||||||
|
|
||||||
signoz:
|
signoz:
|
||||||
image: signoz/signoz:0.82.0
|
image: signoz/signoz:latest
|
||||||
container_name: signoz
|
container_name: signoz
|
||||||
environment:
|
environment:
|
||||||
G2S_ALERTS__TELEGRAM_BOT_TOKEN: ${G2S_ALERTS__TELEGRAM_BOT_TOKEN:-}
|
G2S_ALERTS__TELEGRAM_BOT_TOKEN: ${G2S_ALERTS__TELEGRAM_BOT_TOKEN:-}
|
||||||
@@ -9,5 +28,10 @@ services:
|
|||||||
SIGNOZ_ALERTS_RULES_FILE: /etc/signoz/alerts/signoz_alert_rules.yaml
|
SIGNOZ_ALERTS_RULES_FILE: /etc/signoz/alerts/signoz_alert_rules.yaml
|
||||||
ports:
|
ports:
|
||||||
- "3301:3301"
|
- "3301:3301"
|
||||||
|
- "4317:4317"
|
||||||
volumes:
|
volumes:
|
||||||
|
- signoz_data:/var/lib/signoz
|
||||||
- ./infra/alerts:/etc/signoz/alerts:ro
|
- ./infra/alerts:/etc/signoz/alerts:ro
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
signoz_data:
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
# Local Infrastructure Stack
|
||||||
|
|
||||||
|
## Services
|
||||||
|
|
||||||
|
- `app`: FastAPI service (`uvicorn app.main:app`) built from root `Dockerfile`
|
||||||
|
- `redis`: price cache backend
|
||||||
|
- `signoz`: observability backend (UI + OTLP receiver)
|
||||||
|
|
||||||
|
## Environment wiring
|
||||||
|
|
||||||
|
### `app` service
|
||||||
|
|
||||||
|
- `G2S_CONFIG_FILE=/app/config.yaml`
|
||||||
|
- `G2S_REPOSITORY__REDIS_DSN=redis://redis:6379/0`
|
||||||
|
- `G2S_OBSERVABILITY__OTLP_ENDPOINT=http://signoz:4317`
|
||||||
|
- `PYTHONUNBUFFERED=1`
|
||||||
|
|
||||||
|
### `signoz` service
|
||||||
|
|
||||||
|
- `G2S_ALERTS__TELEGRAM_BOT_TOKEN` (optional for Telegram alerts)
|
||||||
|
- `G2S_ALERTS__TELEGRAM_CHAT_ID` (optional for Telegram alerts)
|
||||||
|
|
||||||
|
## Startup instructions
|
||||||
|
|
||||||
|
1. Validate compose syntax:
|
||||||
|
- `docker compose config`
|
||||||
|
2. Start dependencies:
|
||||||
|
- `docker compose up -d redis signoz`
|
||||||
|
3. Verify running containers:
|
||||||
|
- `docker compose ps`
|
||||||
|
4. Start application:
|
||||||
|
- `docker compose up -d app`
|
||||||
|
5. Stop local stack:
|
||||||
|
- `docker compose down`
|
||||||
|
|
||||||
|
## Smoke command sequence
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose config
|
||||||
|
docker compose up -d redis signoz
|
||||||
|
docker compose ps
|
||||||
|
```
|
||||||
+5
-4
@@ -1,7 +1,7 @@
|
|||||||
# Spec Tasks Index
|
# Spec Tasks Index
|
||||||
|
|
||||||
> ⚠️ This file is generated. Do not edit manually.
|
> ⚠️ This file is generated. Do not edit manually.
|
||||||
> Generated at (UTC): `2026-03-08T09:04:29+00:00`
|
> Generated at (UTC): `2026-03-08T12:18:20+00:00`
|
||||||
|
|
||||||
## Tasks
|
## Tasks
|
||||||
|
|
||||||
@@ -16,10 +16,11 @@
|
|||||||
| 006 | DONE | 2026-03-07 | Add delivery price controller endpoint | `spec/tasks/006_add_delivery_price_controller.md` |
|
| 006 | DONE | 2026-03-07 | Add delivery price controller endpoint | `spec/tasks/006_add_delivery_price_controller.md` |
|
||||||
| 007 | DONE | 2026-03-07 | Add observability correlation and telemetry | `spec/tasks/007_add_observability_correlation.md` |
|
| 007 | DONE | 2026-03-07 | Add observability correlation and telemetry | `spec/tasks/007_add_observability_correlation.md` |
|
||||||
| 008 | DONE | 2026-03-07 | Add SigNoz to Telegram alerting configuration | `spec/tasks/008_add_signoz_telegram_alerting.md` |
|
| 008 | DONE | 2026-03-07 | Add SigNoz to Telegram alerting configuration | `spec/tasks/008_add_signoz_telegram_alerting.md` |
|
||||||
| 009 | TODO | 2026-03-07 | Add local infrastructure stack | `spec/tasks/009_add_local_infra_stack.md` |
|
| 009 | DONE | 2026-03-07 | Add local infrastructure stack | `spec/tasks/009_add_local_infra_stack.md` |
|
||||||
|
| 010 | TODO | 2026-03-08 | Migrate to YAML-only configuration loading | `spec/tasks/010_migrate_to_yaml_only_configuration.md` |
|
||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
- Total: **10**
|
- Total: **11**
|
||||||
- TODO: **1**
|
- TODO: **1**
|
||||||
- DONE: **9**
|
- DONE: **10**
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
id: 009
|
id: 009
|
||||||
title: Add local infrastructure stack
|
title: Add local infrastructure stack
|
||||||
status: TODO
|
status: DONE
|
||||||
created: 2026-03-07
|
created: 2026-03-07
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
---
|
||||||
|
id: 010
|
||||||
|
title: Migrate to YAML-only configuration loading
|
||||||
|
status: TODO
|
||||||
|
created: 2026-03-08
|
||||||
|
---
|
||||||
|
|
||||||
|
## Context
|
||||||
|
В проекте используется смешанный подход конфигурации с переменными окружения. Требуется унифицировать источник конфигурации и оставить только `config.yaml`.
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
Убрать использование переменных окружения из runtime-конфигурации приложения и перевести загрузку всех параметров на чтение из `config.yaml`.
|
||||||
|
|
||||||
|
## Constraints
|
||||||
|
- Соблюдать layered architecture из `AGENTS.md`.
|
||||||
|
- Scope задачи: только механизм загрузки конфигурации и места её потребления.
|
||||||
|
- Запрещено менять бизнес-правила и поведение use-case, не связанное с конфигурацией.
|
||||||
|
- Не изменять файлы в `spec/`.
|
||||||
|
|
||||||
|
## Acceptance criteria
|
||||||
|
- Runtime-конфигурация приложения загружается только из `config.yaml`.
|
||||||
|
- Переменные окружения не используются для чтения параметров Controller, Service, Business Logic, Repository, Adapter, Observability и Alerts.
|
||||||
|
- При отсутствии обязательных полей в `config.yaml` приложение завершает запуск с детерминированной ошибкой валидации конфигурации.
|
||||||
|
- Тесты конфигурации больше не опираются на `monkeypatch` переменных окружения и проверяют чтение из YAML.
|
||||||
|
|
||||||
|
## Definition of Done
|
||||||
|
- [ ] Удалено чтение переменных окружения из конфигурационного слоя.
|
||||||
|
- [ ] Все компонентные секции конфигурации продолжают читаться из `config.yaml`.
|
||||||
|
- [ ] Обновлены тесты конфигурации под YAML-only поведение.
|
||||||
|
- [ ] Smoke test старта приложения проходит с валидным `config.yaml`.
|
||||||
|
|
||||||
|
## Tests
|
||||||
|
- Обновить `tests/config/test_config_sections.py` под проверку YAML-only загрузки.
|
||||||
|
- Добавить/обновить негативные тесты отсутствующих обязательных YAML-полей.
|
||||||
|
- Проверить app startup smoke test с валидным `config.yaml`.
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
- `poetry run pytest tests/config/test_config_sections.py -q`
|
||||||
|
- `poetry run pytest tests/smoke/test_app_import.py -q`
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
|
||||||
|
PROJECT_ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
COMPOSE_FILE = PROJECT_ROOT / "docker-compose.yml"
|
||||||
|
INFRA_README = PROJECT_ROOT / "infra" / "README.md"
|
||||||
|
|
||||||
|
|
||||||
|
def _load_compose() -> dict:
|
||||||
|
content = yaml.safe_load(COMPOSE_FILE.read_text(encoding="utf-8"))
|
||||||
|
assert isinstance(content, dict)
|
||||||
|
return content
|
||||||
|
|
||||||
|
|
||||||
|
def test_compose_defines_required_services() -> None:
|
||||||
|
compose = _load_compose()
|
||||||
|
services = compose.get("services")
|
||||||
|
assert isinstance(services, dict)
|
||||||
|
assert {"app", "redis", "signoz"}.issubset(services.keys())
|
||||||
|
|
||||||
|
|
||||||
|
def test_app_service_contains_cache_and_observability_wiring() -> None:
|
||||||
|
compose = _load_compose()
|
||||||
|
app_service = compose["services"]["app"]
|
||||||
|
|
||||||
|
build_config = app_service.get("build")
|
||||||
|
assert isinstance(build_config, dict)
|
||||||
|
assert build_config["context"] == "."
|
||||||
|
assert build_config["dockerfile"] == "Dockerfile"
|
||||||
|
|
||||||
|
environment = app_service.get("environment")
|
||||||
|
assert isinstance(environment, dict)
|
||||||
|
assert environment["G2S_REPOSITORY__REDIS_DSN"] == "redis://redis:6379/0"
|
||||||
|
assert environment["G2S_OBSERVABILITY__OTLP_ENDPOINT"] == "http://signoz:4317"
|
||||||
|
assert environment["G2S_CONFIG_FILE"] == "/app/config.yaml"
|
||||||
|
|
||||||
|
depends_on = app_service.get("depends_on")
|
||||||
|
assert isinstance(depends_on, list)
|
||||||
|
assert "redis" in depends_on
|
||||||
|
assert "signoz" in depends_on
|
||||||
|
|
||||||
|
|
||||||
|
def test_smoke_command_sequence_is_documented() -> None:
|
||||||
|
readme = INFRA_README.read_text(encoding="utf-8")
|
||||||
|
|
||||||
|
assert "docker compose config" in readme
|
||||||
|
assert "docker compose up -d redis signoz" in readme
|
||||||
|
assert "docker compose ps" in readme
|
||||||
Reference in New Issue
Block a user