-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathDockerfile
More file actions
142 lines (124 loc) · 5.82 KB
/
Copy pathDockerfile
File metadata and controls
142 lines (124 loc) · 5.82 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
135
136
137
138
139
140
141
142
# ============================================================
# feedBack Demucs Server — Docker Image
# ============================================================
# Build:
# docker build -t feedback-demucs-server .
#
# Run (CPU):
# docker run -p 7865:7865 feedback-demucs-server
#
# Run (GPU — requires nvidia-container-toolkit):
# docker run --gpus all -p 7865:7865 feedback-demucs-server
# ============================================================
# ---- Base: Python slim ----
FROM python:3.11-slim AS base
LABEL org.opencontainers.image.title="feedBack Demucs Server"
LABEL org.opencontainers.image.description="AI source separation, lyrics alignment, and pitch extraction service for feedBack"
# image.source is what links the published package to this repo on GHCR - it must
# point at the repo that actually builds it, or the package is orphaned.
LABEL org.opencontainers.image.source="https://github.com/got-feedBack/feedBack-demucs-server"
LABEL org.opencontainers.image.licenses="AGPL-3.0-only"
# Prevent Python from writing .pyc files & buffer stdout
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=1
# ---- System dependencies ----
RUN apt-get update && apt-get install -y --no-install-recommends \
ffmpeg \
git \
libgomp1 \
&& rm -rf /var/lib/apt/lists/*
# ---- Application directory ----
WORKDIR /app
# ---- COPY requirements first (leverage Docker layer cache) ----
COPY requirements.txt .
# ---- Install main Python dependencies ----
# whisperx pins torch~=2.8.0 + torchaudio~=2.8.0 — this satisfies torchcrepe too.
# requirements.txt deliberately does NOT list audio-separator or demucs; both are
# installed --no-deps below. See the ⚠️ note at the top of that file.
RUN pip install --no-cache-dir -r requirements.txt
# ---- Install audio-separator SEPARATELY, with --no-deps ----
# Its metadata requires `diffq` on non-Windows, a C-extension whose newest wheels
# stop at cp310. On this python:3.11 base pip finds no wheel, falls back to the
# sdist and tries to compile it — and this image has no gcc (deliberately: adding a
# toolchain to ship one optional quantizer is the wrong trade). That compile is what
# broke every image build. Its real deps are in requirements.txt instead.
RUN pip install --no-cache-dir --no-deps "audio-separator>=0.44.0"
# ---- Install demucs SEPARATELY to avoid torchaudio version conflict ----
# demucs 4.0.1 (latest PyPI) requires torchaudio<2.1 which conflicts with
# whisperx (torchaudio~=2.8.0). Installing with --no-deps skips the bad pin.
# Runtime deps that are compatible with modern torch are added manually.
RUN pip install --no-cache-dir \
demucs>=4.0.0 \
--no-deps \
&& pip install --no-cache-dir \
einops \
julius \
lameenc \
openunmix \
pyyaml \
tqdm \
dora-search \
sphn
# ---- diffq: BINARY-ONLY, and optional ----
# Needed only to load QUANTIZED demucs checkpoints. `demucs` guards its import and
# audio-separator only reaches for it from its bundled demucs architecture — neither
# is on the bs_roformer_sw path, which is what the app splits with.
#
# --only-binary=:all: is the point: it makes pip FAIL rather than silently fall back
# to the sdist, so a missing wheel can never reintroduce a source build here. On this
# base (glibc >= 2.28, cp311) `diffq-fixed` has a manylinux_2_28 wheel; it installs
# under the module name `diffq`, so it satisfies the import just like the original.
#
# The tolerated failure is gated on the SPECIFIC "no wheel exists" signature. A bare
# `|| true` would also swallow a transient network/index error and quietly ship an image
# without diffq while CI stayed green — a silent downgrade is worse than a failed build.
RUN out="$(pip install --no-cache-dir --no-deps --only-binary=:all: 'diffq-fixed>=0.2' 2>&1)"; rc=$?; \
echo "$out"; \
if [ "$rc" -ne 0 ]; then \
case "$out" in \
*"No matching distribution found"*|*"Could not find a version that satisfies"*) \
echo "WARNING: no diffq wheel for this interpreter - quantized demucs checkpoints will not load (bs_roformer_sw is unaffected)" ;; \
*) \
echo "ERROR: diffq install failed for a reason OTHER than a missing wheel (network? index?). Failing the build rather than silently shipping without it." >&2; \
exit "$rc" ;; \
esac; \
fi
# ---- COPY application code ----
COPY . .
# ---- Least privilege runtime user ----
#
# /app/cache MUST exist in the image, owned by appuser, BEFORE the VOLUME below.
#
# Docker initializes a fresh named volume from whatever sits at that mountpoint in the
# image — ownership included. With nothing there, it creates the directory as root:root.
# The container runs as appuser (uid 10001), so the server dies on its first write:
#
# PermissionError: [Errno 13] Permission denied: '/app/cache/_roformer-models'
#
# ...and `restart: unless-stopped` turns that into a crash-loop. Not theoretical: it is
# what the freshly published image did on its very first run, and it breaks the documented
# `docker compose up -d` path exactly as hard as anything else.
RUN useradd --create-home --uid 10001 appuser \
&& mkdir -p /app/cache \
&& chown -R appuser:appuser /app
# ---- Server port ----
EXPOSE 7865
# ---- Default environment ----
ENV PORT=7865 \
HOST=0.0.0.0 \
AUTO_UPDATE=false \
UPDATE_TIME=04:00 \
UPDATE_CHECK_INTERVAL=3600 \
SLOPSMITH_DEMUCS_CACHE=/app/cache \
CACHE_TTL=24h \
# Redirect HuggingFace and PyTorch caches to the persistent volume
HF_HOME=/app/cache/huggingface \
TORCH_HOME=/app/cache/torch \
HUGGINGFACE_HUB_CACHE=/app/cache/huggingface/hub \
MPLLOCALEDIR=/app/cache/locale
USER appuser
# ---- Volume for model cache (persist across restarts) ----
VOLUME /app/cache
# ---- Entrypoint ----
ENTRYPOINT ["./docker-entrypoint.sh"]