-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdocker-compose.yml
More file actions
134 lines (128 loc) · 5.44 KB
/
Copy pathdocker-compose.yml
File metadata and controls
134 lines (128 loc) · 5.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# SubtitleExtractor — base stack (control plane).
# Phase 1: api + postgres + minio. The macOS worker runs NATIVELY on the host
# (see worker/run-macos.sh) and is NOT part of this compose file, because Docker
# on macOS cannot reach the Apple GPU.
# Phase 2: the NVIDIA worker is added via docker-compose.nvidia.yml (overlay).
#
# PRODUCTION NOTES
# ----------------
# * Datastore/API ports (postgres 5432, minio 9000/9001, api 8080) are published
# on 127.0.0.1 only — reachable from the host, NOT the public network. Do not
# change these to a broad bind unless you front them with a firewall/proxy.
# * `web` is the intended entrypoint and is the only broadly-published service.
# In production, put a TLS-terminating reverse proxy (nginx/Caddy/Traefik) in
# front of `web` — this compose file serves plain HTTP.
# * Resource limits below (deploy.resources.limits) are conservative defaults;
# tune mem/cpus to your host. The OCR worker runs OUTSIDE compose (native
# macOS host, or the NVIDIA overlay) and is sized separately.
services:
postgres:
# Pinned to the 16.x line on purpose: bumping the Postgres MAJOR version
# requires a data migration (pg_upgrade / dump+restore) of the pgdata
# volume, so do NOT change this to 17/18 without one.
image: postgres:16-alpine
restart: unless-stopped
environment:
# No fallbacks: a missing .env must abort rather than boot with known creds.
POSTGRES_USER: ${POSTGRES_USER:?set POSTGRES_USER in .env}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env}
POSTGRES_DB: ${POSTGRES_DB:?set POSTGRES_DB in .env}
volumes:
- pgdata:/var/lib/postgresql/data
ports:
# Loopback-only: the DB must not be reachable on the public network.
# Host port 5433 (not 5432) so it never clashes with a Postgres already
# running natively on the host. Containers still talk over the internal
# network on 5432 (see api DATABASE_URL), so this only affects host tools.
- "127.0.0.1:5433:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
interval: 5s
timeout: 5s
retries: 10
minio:
# Pinned off :latest for reproducible deploys (current stable release tag).
image: minio/minio:RELEASE.2025-09-07T16-13-09Z
restart: unless-stopped
command: server /data --console-address ":9001"
environment:
# No fallbacks: a missing .env must abort rather than boot with known creds.
MINIO_ROOT_USER: ${MINIO_ROOT_USER:?set MINIO_ROOT_USER in .env}
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:?set MINIO_ROOT_PASSWORD in .env}
volumes:
- miniodata:/data
ports:
# Loopback-only: object store + admin console are not public-facing.
- "127.0.0.1:9000:9000" # S3 API
- "127.0.0.1:9001:9001" # web console
healthcheck:
# The minio binary serves a liveness endpoint; curl is bundled in the image.
test: ["CMD-SHELL", "curl -fsS http://localhost:9000/minio/health/live || exit 1"]
interval: 5s
timeout: 5s
retries: 20
# One-shot: create the bucket on first boot so the S3 backend works out of the box.
createbuckets:
# Pinned off :latest for reproducible deploys (current stable release tag).
image: minio/mc:RELEASE.2025-08-13T08-35-41Z
depends_on:
minio:
condition: service_healthy
entrypoint: >
/bin/sh -c "
mc alias set local http://minio:9000 ${MINIO_ROOT_USER:?set MINIO_ROOT_USER in .env} ${MINIO_ROOT_PASSWORD:?set MINIO_ROOT_PASSWORD in .env};
mc mb --ignore-existing local/${STORAGE_S3_BUCKET:-subext};
exit 0;
"
api:
# Prebuilt image from GHCR. `docker compose pull` fetches it; `up --build`
# rebuilds locally and tags it with this same name. Override the tag with
# IMAGE_TAG (e.g. IMAGE_TAG=0.1.0) in .env or the environment.
image: ghcr.io/dim145/subtitleextractor-api:${IMAGE_TAG:-latest}
build:
context: ./api
restart: unless-stopped
env_file: .env
environment:
# Override host-specific values so the container reaches sibling services.
DATABASE_URL: postgres://${POSTGRES_USER:?set POSTGRES_USER in .env}:${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env}@postgres:5432/${POSTGRES_DB:?set POSTGRES_DB in .env}?sslmode=disable
depends_on:
postgres:
condition: service_healthy
ports:
# Loopback-only: the API is reached through `web`'s /api proxy, not
# directly from the public network.
- "127.0.0.1:8080:8080"
volumes:
# Used only when STORAGE_BACKEND=local; harmless otherwise.
- blobs:/data/blobs
deploy:
resources:
limits:
# Conservative defaults — tune to your host. The API is I/O-bound
# (DB + object store), not compute-heavy.
cpus: "1.0"
memory: 512M
web:
image: ghcr.io/dim145/subtitleextractor-web:${IMAGE_TAG:-latest}
build:
context: ./web
restart: unless-stopped
depends_on:
api:
condition: service_healthy
ports:
# Intended entrypoint: kept broadly published. In production, front this
# with a TLS-terminating reverse proxy (see PRODUCTION NOTES at top).
- "3000:80"
deploy:
resources:
limits:
# Conservative defaults — tune to your host. nginx serving a static
# SPA + proxying /api has a small footprint.
cpus: "0.5"
memory: 256M
volumes:
pgdata:
miniodata:
blobs: