networks: musehub-internal: driver: bridge services: musehub: build: context: .. dockerfile: musehub/Dockerfile image: musehub/musehub container_name: musehub ports: - "127.0.0.1:1337:1337" env_file: .env environment: DATABASE_URL: "postgresql+asyncpg://musehub:${DB_PASSWORD:-musehub}@postgres:5432/musehub" volumes: - musehub_data:/data # /tmp writable for uvicorn temp files; root filesystem is read-only. - type: tmpfs target: /tmp # TLS cert for local HTTPS — enables HTTP/2 without a reverse proxy. # Certs live outside the repo at ~/.config/musehub/local-tls/ so they # survive repo cleans, checkouts, and directory recreations. # First-time setup: mkcert localhost 127.0.0.1 ::1 (run in that dir). - ${HOME}/.config/musehub/local-tls:/tls:ro depends_on: postgres: condition: service_healthy networks: - musehub-internal restart: unless-stopped # Read-only root filesystem — prevents code injection and log-file exfiltration. # Explicit writable mounts: /data (object store, named volume) and /tmp (tmpfs). read_only: true deploy: resources: limits: # 1 vCPU cap prevents a runaway request from starving nginx/postgres. cpus: "1.0" # 2 GiB covers large mpack unpack operations (1000+ commits, 10k+ blobs). memory: 2048M reservations: cpus: "0.25" memory: 256M worker: build: context: .. dockerfile: musehub/Dockerfile image: musehub/musehub container_name: musehub_worker command: ["python", "-m", "musehub.worker"] env_file: .env environment: DATABASE_URL: "postgresql+asyncpg://musehub:${DB_PASSWORD:-musehub}@postgres:5432/musehub" WORKER_POLL_INTERVAL: "1.0" volumes: - musehub_data:/data - type: tmpfs target: /tmp depends_on: postgres: condition: service_healthy healthcheck: test: ["CMD-SHELL", "kill -0 1 2>/dev/null || exit 1"] interval: 30s timeout: 5s start_period: 15s retries: 3 networks: - musehub-internal restart: unless-stopped read_only: true deploy: resources: limits: # Worker may use more memory than the web process — symbol indexing # loads commit graphs into memory. 2 GiB covers the largest repos. cpus: "1.0" memory: 2048M reservations: cpus: "0.1" memory: 128M postgres: image: postgres:16-alpine container_name: musehub_postgres environment: POSTGRES_DB: musehub POSTGRES_USER: musehub POSTGRES_PASSWORD: "${DB_PASSWORD:-musehub}" volumes: - postgres_data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U musehub -d musehub"] interval: 5s timeout: 5s retries: 10 networks: - musehub-internal restart: unless-stopped # Expose on 5434 (not 5432/5433) to avoid colliding with a locally-installed # Postgres or another project's container (e.g. agentception uses 5433). # This lets the local test suite and Alembic CLI reach the DB directly: # DATABASE_URL=postgresql+asyncpg://musehub:musehub@localhost:5434/musehub # make test (the Makefile sets this automatically) # alembic upgrade head ports: - "127.0.0.1:5434:5432" deploy: resources: limits: cpus: "0.5" memory: 256M reservations: cpus: "0.1" memory: 64M musehub-runner: image: docker:24-dind container_name: musehub_runner privileged: true env_file: .env environment: RUNNER_TOKEN: "${RUNNER_TOKEN:-}" MUSEHUB_URL: "http://musehub:1337" volumes: - type: tmpfs target: /tmp depends_on: - musehub networks: - musehub-internal restart: unless-stopped deploy: resources: limits: cpus: "2.0" memory: 1024M reservations: cpus: "0.25" memory: 256M volumes: musehub_data: postgres_data: