stacks/fish-s2: build from docker/Dockerfile (not dockerfile.dev) — third try

Second deploy attempt failed at build time:
  failed to fetch anonymous token: ... ghcr.io/fishaudio/fish-speech ... 403 Forbidden

Root cause: dockerfile.dev is a thin two-line wrapper around
`FROM ghcr.io/fishaudio/fish-speech:${VERSION}`, which is a private
GHCR base image. Anonymous pulls 403, and we'd need GHCR auth to use
that path. The dev variant is meant for upstream's CI / fish-speech
contributors, not external consumers.

The REAL production path (from upstream's compose.base.yml) is to
build from `docker/Dockerfile` with build args BACKEND=cuda,
CUDA_VER=12.9.0, UV_EXTRA=cu129, UV_VERSION=0.8.15. That builds
everything from source — slower (15-20 min cold), but fully self-
contained.

irv-ml1's driver (595.58.03, CUDA 13.2 capable) is forward-compatible
with the 12.9 PyTorch wheels.

Took three iterations to find the right Dockerfile because:
  1. First try: dockerfile (lowercase) — doesn't exist
  2. Second try: dockerfile.dev — exists but pulls a private base
  3. Third try: docker/Dockerfile — actual production path
This commit is contained in:
2026-04-27 22:57:09 -07:00
parent 12d0863108
commit 425b1d45d6
+15 -10
View File
@@ -26,18 +26,23 @@ services:
image: local/fish-s2:${FISH_S2_TAG}
build:
context: https://github.com/fishaudio/fish-speech.git#${FISH_S2_SHA}
# Upstream ships `dockerfile.dev` (lowercase, dev/test image)
# rather than a plain Dockerfile — there is no production
# Dockerfile. Their intended path is `docker compose --profile
# server up` against their own compose.yml; we use the same
# underlying dockerfile.dev image but layer our own compose on
# top so it slots into our fleet conventions (restart, labels,
# bind mounts, healthcheck).
dockerfile: dockerfile.dev
# The REAL production Dockerfile is at docker/Dockerfile (per
# upstream's compose.base.yml). The repo also ships a
# `dockerfile.dev` at root which is a thin
# `FROM ghcr.io/fishaudio/fish-speech:${VERSION}` wrapper meant
# for dev iteration on top of a private base image — that path
# 403s on anonymous pulls. Build from source via docker/Dockerfile
# instead.
dockerfile: docker/Dockerfile
args:
# Upstream's dockerfile.dev reads BACKEND to choose CUDA vs CPU
# paths during pip install. We always want CUDA on irv-ml1.
# Build args mirror upstream compose.base.yml defaults.
# CUDA_VER 12.9 + UV_EXTRA cu129 = the CUDA 12.9 PyTorch wheels.
# irv-ml1's driver (595.58.03 / CUDA 13.2 capable) is
# backward-compatible with 12.9-built images.
BACKEND: cuda
CUDA_VER: "12.9.0"
UV_EXTRA: cu129
UV_VERSION: "0.8.15"
container_name: fish-s2
restart: unless-stopped
runtime: nvidia