docker-compose.yml
Rama main · réplica de lectura del repositorio original.
# Per-server settings live in a .env file next to this one (see .env.example),
# so tuning a host never means editing a tracked file. Every one has a default.
services:
frontend:
build:
context: .
dockerfile: frontend/Dockerfile
# Published to the LAN: this is the app, and other machines open it.
ports:
- "3051:80"
depends_on:
backend:
condition: service_healthy
# nginx's upload limit and proxy timeout are worked out from these at
# startup (frontend/nginx-limits.envsh), so they can't drift from the
# backend's.
environment:
- FM_MAX_FILE_MB=${MAX_FILE_MB:-50}
- FM_PROCESS_TIMEOUT_MIN=${PROCESS_TIMEOUT_MIN:-5}
restart: unless-stopped
mem_limit: 128m
# Safe anywhere, unlike an absolute cap above 1: every host has at least
# one core, and nginx serving static files needs a fraction of it.
cpus: 0.5
pids_limit: 128
healthcheck:
# 127.0.0.1, not localhost: that resolves to ::1 first and nginx
# listens on IPv4 only, so the check would fail against a healthy
# server and the frontend would never come up behind depends_on.
test: ["CMD", "wget", "-qO-", "http://127.0.0.1/"]
interval: 30s
timeout: 5s
retries: 3
start_period: 10s
backend:
build:
context: .
dockerfile: backend/Dockerfile
# Loopback only. nginx reaches the backend over the compose network, so the
# published port exists purely for the smoke suite and for debugging from
# the host. Published on 0.0.0.0 it would be a second front door that skips
# nginx -- and since `trust proxy` makes Express believe X-Forwarded-For,
# a direct client could set that header per request and rotate itself out
# of the rate limiter entirely.
ports:
- "127.0.0.1:4001:4000"
# NODE_ENV=production and PORT=4000 come from the image. PORT is not a real
# knob: the port map above, the healthcheck and nginx all say 4000.
environment:
- MAX_FILE_SIZE=${MAX_FILE_MB:-50}MB
# Per external command (ffmpeg, gs, libreoffice). A two-pass encode is two.
- PROCESS_TIMEOUT_MIN=${PROCESS_TIMEOUT_MIN:-5}
# Same-origin only by default: nginx serves the app and proxies /api on
# one origin, so the browser never makes a cross-origin call. Set this to
# an origin (or a comma-separated list) only if something else needs in.
- CORS_ORIGIN=
# Uploads and results. TEMP_DIR can point this at a host directory instead
# of the named volume (which lives under /var/lib/docker). It must be a
# directory of its own: the hourly sweep deletes everything in it older
# than an hour. The container runs as uid 1000, which needs write access.
volumes:
- ${TEMP_DIR:-temp_files}:/app/temp
restart: unless-stopped
# A 50MB video through two-pass ffmpeg, Ghostscript and LibreOffice is the
# heavy case. Memory is what can actually take the host down with it, so
# that is what is capped; a saturated CPU only makes things slow.
#
# Deliberately no `cpus:` here. It is not a cap that degrades -- Docker
# refuses to start the container outright when the value exceeds the
# host's core count ("range of CPUs is from 0.01 to 2.00"), so a number
# picked on one machine is a landmine on a smaller one. CI caught it on a
# two-core runner. It is also the wrong trade for this workload:
# transcoding is the job, and throttling it slows the people using the app
# to guard against something a trusted network does not have. Add one by
# hand if you want it, no higher than `nproc` on the smallest host it will
# ever run on.
#
# What it does have is a lower CPU *weight*. A weight only matters when the
# CPU is contended and can never be too large for a host, so unlike `cpus:`
# it is safe everywhere. On an idle machine an encode still gets every
# core; when another container wants CPU at the same time (a media server
# transcoding, say), this one yields. 512 is half the Docker default. The
# kernel weight it becomes depends on the container runtime: newer runc
# maps it to 59 against the default 100 (about 37% of a contended CPU),
# older ones to 20. backend/test/bench.sh prints the actual cpu.weight.
# Lower BACKEND_CPU_SHARES yields more (256 -> 34, 128 -> 20 on newer
# runc); 1024 competes equally.
cpu_shares: ${BACKEND_CPU_SHARES:-512}
mem_limit: 3g
pids_limit: 512
healthcheck:
test: ["CMD", "node", "-e", "require('http').get('http://127.0.0.1:4000/health',r=>process.exit(r.statusCode===200?0:1)).on('error',()=>process.exit(1))"]
interval: 30s
timeout: 5s
retries: 3
start_period: 20s
volumes:
temp_files: