hasari-api / docker-compose.yml
erdoganpeker's picture
v0.3.0 — multimodal vehicle damage MVP
e327f0d
# docker-compose.yml (repo root)
# ----------------------------------------------------------------------
# Local DEV environment for arac-hasar-v2.
#
# What it brings up:
# - backend (FastAPI, hot-reload, mounts ./services/backend:/app)
# - worker (Celery, same image)
# - postgres 16
# - redis 7
# - minio + minio-init (S3-mock, bucket auto-created)
#
# What it does NOT bring up (run with pnpm dev):
# - apps/web -> cd apps/web && pnpm dev (port 3000)
# - apps/mobile -> cd apps/mobile && pnpm start
# - apps/desktop -> cd apps/desktop && pnpm tauri dev
#
# Quick start:
# docker compose up -d postgres redis minio minio-init
# docker compose up backend worker # foreground, see logs
#
# For the full GPU/CUDA compose with bundled web container,
# see services/backend/docker-compose.yml.
# ----------------------------------------------------------------------
name: arac-hasar-v2-dev
services:
backend:
build:
context: ./services/backend
dockerfile: Dockerfile
image: hasarui-api:dev
container_name: hasarui-backend
# NOTE: --reload-exclude tames watchfiles churn from ML shim copies,
# __pycache__ writes, training log spew, and visualization PNGs that
# otherwise trigger a uvicorn restart loop in dev.
command: ["sh", "-c", "uvicorn main:app --host 0.0.0.0 --port 8000 --reload --reload-dir /app --reload-exclude '*.log' --reload-exclude '*.png' --reload-exclude '*.jpg' --reload-exclude '__pycache__/*' --reload-exclude 'tests/*' --reload-exclude 'migrations/versions/*'"]
ports:
- "8000:8000"
env_file:
- ./services/backend/.env
environment:
# Override URLs to point to compose service names
DATABASE_URL: "postgresql://postgres:postgres@postgres:5432/arac_hasar"
REDIS_URL: "redis://redis:6379/0"
S3_ENDPOINT: "http://minio:9000"
S3_ACCESS_KEY: "minioadmin"
S3_SECRET_KEY: "minioadmin"
S3_BUCKET: "inspections"
S3_REGION: "us-east-1"
ML_DEVICE: "cpu"
# Entrypoint skips S3 model fetch — we mount weights as a volume.
SKIP_MODEL_FETCH: "1"
RUN_MIGRATIONS: "1"
ENVIRONMENT: "development"
# Web (3000), Tauri desktop dev (1420) + prod webview origins, Expo mobile (8081)
CORS_ORIGINS: "http://localhost:3000,http://localhost:1420,http://tauri.localhost,tauri://localhost,http://localhost:8081"
# Single-source ML modules: services/ml/ mounted read-only at /app/ml.
# PYTHONPATH includes /app/ml so `from pipeline import DamagePipeline`
# resolves to services/ml/pipeline.py without scripts/prepare-ml-shim.*
# having to copy files into services/backend/. /app still takes
# priority — backend-local override remains possible during a cutover.
PYTHONPATH: "/app:/app/ml"
volumes:
# Hot-reload: source mounted on top of image
- ./services/backend:/app
# ML single-source mount: services/ml/ read-only at /app/ml.
# Eliminates services/backend/pipeline.py drift vs services/ml/pipeline.py.
# prepare-ml-shim.{sh,ps1} is now only needed for the PRODUCTION docker
# build (CI bakes files in); dev runs straight off this mount.
# NOT: pretrained/ alt klasoru runtime'da yazilabilir (model_manager
# download bir kez .pt indirir, sonraki boot'larda cache hit). Kalan
# services/ml/ icerigi kod ve egitim verisi — dev'de read-write OK.
- ./services/ml:/app/ml
# Local model weights for dev (point at your snapshot dir or symlink).
# If this path is missing, run:
# $env:MODEL_SNAPSHOT_DIR = "<absolute path to latest snapshot>"
# or edit the path below to the latest run under services/ml/runs/bundles/.
- ${MODEL_SNAPSHOT_DIR:-./services/ml/runs/bundles/full_20260515_044630/_SNAPSHOT_FOR_BUILD}:/app/models:ro
networks:
- hasarui-net
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
minio-init:
condition: service_completed_successfully
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
# Dev guardrail. Observed peak ~1.7 GiB (uvicorn 2 workers + YOLO ensemble
# + cv2/numpy + torch CPU). Render starter (512 MB) is undersized — we
# have to deploy on standard (2 GB) or trim to a single uvicorn worker
# + lazy model load. NOT mirrored to render.yaml in this change.
deploy:
resources:
limits:
memory: 3G
cpus: "4.0"
reservations:
memory: 1G
restart: unless-stopped
worker:
build:
context: ./services/backend
dockerfile: Dockerfile
image: hasarui-api:dev
container_name: hasarui-worker
command: ["sh", "-c", "celery -A worker.celery_app worker --loglevel=info --concurrency=1"]
env_file:
- ./services/backend/.env
environment:
DATABASE_URL: "postgresql://postgres:postgres@postgres:5432/arac_hasar"
REDIS_URL: "redis://redis:6379/0"
S3_ENDPOINT: "http://minio:9000"
S3_ACCESS_KEY: "minioadmin"
S3_SECRET_KEY: "minioadmin"
S3_BUCKET: "inspections"
S3_REGION: "us-east-1"
ML_DEVICE: "cpu"
SKIP_MODEL_FETCH: "1"
RUN_MIGRATIONS: "0"
ENVIRONMENT: "development"
CORS_ORIGINS: "http://localhost:3000,http://localhost:1420,http://tauri.localhost,tauri://localhost,http://localhost:8081"
# Celery prefork spawn temizler sys.path '' entry'sini; explicit PYTHONPATH
# zorunlu — yoksa worker `from pipeline import DamagePipeline` başarısız.
# /app/ml eklendi: services/ml/ tek-kaynak modülleri (pipeline.py vb.)
PYTHONPATH: "/app:/app/ml"
volumes:
- ./services/backend:/app
# Worker da ML modüllerini aynı tek-kaynak mount'tan okur.
# NOT: pretrained/ alt klasoru runtime'da yazilabilir (model_manager
# download bir kez .pt indirir, sonraki boot'larda cache hit). Kalan
# services/ml/ icerigi kod ve egitim verisi — dev'de read-write OK.
- ./services/ml:/app/ml
- ${MODEL_SNAPSHOT_DIR:-./services/ml/runs/bundles/full_20260515_044630/_SNAPSHOT_FOR_BUILD}:/app/models:ro
networks:
- hasarui-net
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
minio-init:
condition: service_completed_successfully
backend:
condition: service_started
# Override Dockerfile's HTTP /health check — worker has no HTTP server.
# Use Celery's own broker ping (returns "pong" from each running worker).
healthcheck:
test: ["CMD-SHELL", "celery -A worker.celery_app inspect ping -d celery@$$HOSTNAME -t 5 || exit 1"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
# Worker ensemble inference 12 foto için peak ~2 GiB gözlemlendi.
# Concurrency=1 ile zaten serialize ediyoruz; 3 GiB tampon yeterli.
deploy:
resources:
limits:
memory: 3G
cpus: "4.0"
reservations:
memory: 1G
restart: unless-stopped
postgres:
image: postgres:16-alpine
container_name: hasarui-postgres
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: arac_hasar
ports:
- "5432:5432"
volumes:
- pg_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres -d arac_hasar"]
interval: 5s
timeout: 5s
retries: 10
start_period: 10s
networks:
- hasarui-net
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
restart: unless-stopped
redis:
image: redis:7-alpine
container_name: hasarui-redis
command: ["redis-server", "--appendonly", "yes", "--save", "60", "1"]
ports:
- "6379:6379"
volumes:
- redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 5
networks:
- hasarui-net
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
restart: unless-stopped
minio:
image: minio/minio:latest
container_name: hasarui-minio
command: ["server", "/data", "--console-address", ":9001"]
environment:
MINIO_ROOT_USER: minioadmin
MINIO_ROOT_PASSWORD: minioadmin
ports:
- "9000:9000" # S3 API
- "9001:9001" # Web console -> http://localhost:9001
volumes:
- minio_data:/data
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 10s
timeout: 5s
retries: 5
start_period: 10s
networks:
- hasarui-net
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
restart: unless-stopped
minio-init:
image: minio/mc:latest
container_name: hasarui-minio-init
depends_on:
minio:
condition: service_healthy
networks:
- hasarui-net
# Idempotent: --ignore-existing makes mb / anonymous safe to re-run.
entrypoint:
- /bin/sh
- -c
- |
set -e
until mc alias set local http://minio:9000 minioadmin minioadmin >/dev/null 2>&1; do
echo "minio-init: waiting for minio..."
sleep 1
done
mc mb --ignore-existing local/inspections
mc mb --ignore-existing local/models
mc anonymous set download local/inspections || true
echo "MinIO buckets ready: inspections, models"
restart: "no"
networks:
hasarui-net:
driver: bridge
volumes:
pg_data:
redis_data:
minio_data: