# uj-mastering-master — web UI, container deployment template. # # docker compose up --build # build and start # docker compose logs -f # watch startup # open http://localhost:8000 # # There is deliberately no audio volume. Uploaded audio lives in the browser # (Origin Private File System) and each request body is spooled to /tmp only # while that request is being decoded. Nothing about a user's masters is # persisted here — read-only storage is not just possible, it is the intent. services: ujm-web: build: context: . dockerfile: Dockerfile # Pin the build to this branch's source; override to build from a # release tag instead: # docker compose build --build-arg ... image: uj-mastering-master-web:local container_name: ujm-web # Loopback-only by default. The app binds 0.0.0.0 *inside* the container, # but publishing to 127.0.0.1 means it is only reachable from this host — # an analysis tool with no authentication should not appear on the LAN by # accident. Change to "8000:8000" (or put it behind a reverse proxy) to # expose it deliberately. ports: - "127.0.0.1:8000:8000" environment: # Analysis is CPU-bound numpy/scipy; keep BLAS from oversubscribing when # several requests overlap. Raise these if you raise `cpus` below. OMP_NUM_THREADS: "4" OPENBLAS_NUM_THREADS: "4" MKL_NUM_THREADS: "4" NUMEXPR_NUM_THREADS: "4" # Writable scratch for numba/matplotlib caches and request spools. NUMBA_CACHE_DIR: /tmp/numba-cache MPLCONFIGDIR: /tmp/matplotlib TMPDIR: /tmp # The container filesystem can be read-only: the app writes nothing it # needs to keep. /tmp is a tmpfs (memory-backed) so spooled request bodies # never touch a disk at all. read_only: true tmpfs: - /tmp:size=1g,mode=1777 # Analysis needs headroom: a long master at native sample rate is heavy in # RAM. Raise the limit for large files; the tmpfs above is also backed by # memory, so --memory must comfortably exceed it. deploy: resources: limits: cpus: "4.0" memory: 4g # Run as the image's unprivileged user (uid 10001). Nothing here needs root. security_opt: - no-new-privileges:true cap_drop: - ALL restart: unless-stopped stop_grace_period: 10s # The image ships a HEALTHCHECK; this is the same check expressed at the # orchestration layer, so `docker compose ps` shows real health. healthcheck: test: ["CMD", "python", "-c", "import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://127.0.0.1:8000/api/metrics', timeout=4).status == 200 else 1)"] interval: 30s timeout: 5s start_period: 20s retries: 3 logging: driver: json-file options: max-size: "10m" max-file: "3" # No volumes are declared, on purpose. If you want to run the API smoke test # inside the image, do it ad hoc rather than mounting a source tree: # # docker compose exec ujm-web python - <<'PY' # ... # or see `make smoke` in the README # PY