# ========================================================================= # Maestro Platform — local infrastructure # Brings up Postgres, MongoDB, Qdrant and Redis for development. # The FastAPI backend and Next.js frontend run on the host (see README). # Ollama also runs on the host (`ollama serve`) so it can use the GPU. # # Redis is optional locally: leave REDIS_URL unset and the rate limiter keeps # its buckets in process memory, which is correct for a single dev worker. # # Every service carries a `mem_limit`, mirroring docker-compose.prod.yml. Without # one, each container sizes its caches from the whole WSL2 VM; the four of them # together starved the Next.js dev server on the host and froze the machine. # The VM itself is capped separately in %USERPROFILE%\.wslconfig. # ========================================================================= services: postgres: image: postgres:16-alpine container_name: maestro-postgres restart: unless-stopped mem_limit: 512m environment: POSTGRES_USER: maestro POSTGRES_PASSWORD: maestro POSTGRES_DB: maestro ports: # Host port 5433: a native PostgreSQL service on Windows already owns 5432. - "5433:5432" volumes: - ./.data/postgres:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U maestro -d maestro"] interval: 10s timeout: 5s retries: 5 mongo: image: mongo:7 container_name: maestro-mongo restart: unless-stopped mem_limit: 1g # WiredTiger sizes its cache from *visible* RAM, which inside WSL2 is the # whole VM — it ignores the cgroup limit and would get OOM-killed instead. command: ["mongod", "--wiredTigerCacheSizeGB", "0.5"] ports: # Host port 27018, for the same reason Postgres uses 5433: a native # MongoDB service (Homebrew's mongodb-community, Windows' MongoDB # service) already owns 27017 on plenty of dev machines. It binds # 127.0.0.1 specifically while Docker's proxy binds the wildcard, and a # loopback-specific bind wins — so `localhost:27017` silently reaches the # *native* server, not this container. Those installs default to # authorization enabled, which surfaces as an unrelated-looking # "Command update requires authentication" from the seed script. - "27018:27017" volumes: # A named volume, unlike its bind-mounted siblings. WiredTiger cannot open # an *existing* data file over Docker Desktop's VirtioFS share on macOS: # `/data/db/WiredTiger.wt: handle-open: open` returns EPERM ("Operation not # permitted") and mongod turns that into a fatal assertion, so the # container crash-loops. A fresh dbpath initialises fine, which is why the # failure only appears on the *second* start, once the files exist — and # why it looks like a connection error from the seed script rather than a # storage one. Postgres, Qdrant and Redis keep their bind mounts; none of # them touches the file in the way that trips this. This also matches # docker-compose.prod.yml, which has always used a named `mongodata`. - mongodata:/data/db healthcheck: test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"] interval: 10s timeout: 5s retries: 5 qdrant: # Pinned to the same tag as production; `latest` silently changed the storage # format between runs and mmaps the segment store on start. image: qdrant/qdrant:v1.18.2 container_name: maestro-qdrant restart: unless-stopped mem_limit: 1g ports: - "6333:6333" # REST - "6334:6334" # gRPC volumes: - ./.data/qdrant:/qdrant/storage # The image ships no curl/wget and its /bin/sh is dash, so CMD-SHELL cannot # probe anything — but bash *is* installed, and its /dev/tcp redirection # speaks enough HTTP to read Qdrant's own /readyz. That endpoint answers # without the API key, so the same probe works in docker-compose.prod.yml. healthcheck: test: - CMD - bash - -c - "exec 3<>/dev/tcp/127.0.0.1/6333 && printf 'GET /readyz HTTP/1.1\\r\\nHost: localhost\\r\\nConnection: close\\r\\n\\r\\n' >&3 && grep -q '200 OK' <&3" interval: 10s timeout: 5s retries: 5 redis: image: redis:7-alpine container_name: maestro-redis restart: unless-stopped mem_limit: 256m # Rate-limit buckets expire in 60s, so eviction under pressure costs nothing. command: ["redis-server", "--maxmemory", "192mb", "--maxmemory-policy", "allkeys-lru"] ports: - "6379:6379" volumes: - ./.data/redis:/data healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 5s retries: 5 # Only MongoDB needs one — see the comment on the mongo service. The bind-mounted # services keep their data under ./.data, which is gitignored and safe to delete. volumes: mongodata: