# syntax=docker/dockerfile:1.4 # Multi-tenant ComfyUI image — one container per BoosAPI user. # # Lineage: based on the same Python 3.11 / CPU-only profile the legacy # bosapi-comfyui:ready image used. Differences from the singleton image: # 1. Bakes `comfy_patches/overlay` into the image (proxy-base # default + auth-header fallback, server/runtime hardening, docs) # so containers do NOT need a host bind-mount of `comfy_source/`. # 2. Bakes the BoosAPI custom nodes from `comfy/boosapi_comfy_nodes.py` # under `/workspace/ComfyUI/custom_nodes/` so workflows referencing # `BoosAPITextGen` etc. resolve without any host mount. # 3. Reads `BOOSAPI_BUILTIN_KEY`, `BOOSAPI_BASE`, `BOOSAPI_KEY` at # runtime via the entrypoint shim and forwards them as # `--comfy-api-base` and the documented env vars. # 4. No host source mounts — all ComfyUI code lives inside the image # so the container can run with `--read-only` and tmpfs `/tmp`. # # Build context MUST be the repo root (`docker build -f docker/Dockerfile.comfyui.multi-tenant .`). # # Requires BuildKit (Docker 20.10+ has it on by default; build-and-run.sh # also exports DOCKER_BUILDKIT=1 defensively). The `--mount=type=cache` # instructions below are no-ops without BuildKit. FROM python:3.11-slim WORKDIR /workspace # USTC mirror for faster apt RUN sed -i 's|deb.debian.org|mirrors.ustc.edu.cn|g' /etc/apt/sources.list.d/debian.sources 2>/dev/null || \ sed -i 's|deb.debian.org|mirrors.ustc.edu.cn|g' /etc/apt/sources.list RUN apt-get update && apt-get install -y --no-install-recommends \ git curl tini \ && rm -rf /var/lib/apt/lists/* # uv: 5-10x faster than pip on resolution + install. Installed from PyPI # via the Tsinghua mirror that's already used by the rest of the build, # instead of curling the upstream GitHub release tarball — # `github.com/astral-sh/uv/releases/...` is unreliable from mainland # networks (TLS handshake completes, then body read truncates with # `SSL_read: unexpected eof`). The PyPI wheel bundles the same self- # contained binary and drops `uv` into the system Python's scripts dir # (already on PATH). Pinned for reproducibility. RUN pip install --no-cache-dir \ --index-url https://pypi.tuna.tsinghua.edu.cn/simple \ uv==0.5.31 \ && uv --version # ── Layer-caching strategy ──────────────────────────────────────────── # Copy ONLY requirements.txt first. The heavy install layers (torch + # ComfyUI deps, ~200 MB combined) then live in their own cache lines # that only invalidate when requirements.txt actually changes. Most # rebuilds change other comfy_source/ files (workflow scripts, custom # nodes, etc.), so this swap turns a 5-10 minute reinstall into a # zero-network layer-cache hit. # # The full `COPY comfy_source` happens after the install. It overlays # the rest of ComfyUI on top of the venv directory (which lives at # /workspace/ComfyUI/venv) without disturbing it — venv/ isn't present # in the source tree, and requirements.txt is just rewritten with # identical content. COPY comfy_source/requirements.txt /workspace/ComfyUI/requirements.txt WORKDIR /workspace/ComfyUI RUN uv venv venv --python python3.11 ENV PATH="/workspace/ComfyUI/venv/bin:${PATH}" # ── PyTorch CPU wheels ──────────────────────────────────────────────── # ~200 MB combined and the single biggest network draw of the build. # Two reliability levers: # 1. Tsinghua pytorch-wheels mirror replaces upstream # `download.pytorch.org/whl/cpu`. Upstream is slow + flaky from # mainland networks (TLS handshake completes, body read truncates # with `SSL_read: unexpected eof`). Tsinghua mirrors the same # wheels and is documented as a drop-in `--extra-index-url`. # 2. BuildKit cache mount on /root/.cache/uv preserves the downloaded # wheels across rebuilds. Even if this layer is invalidated (e.g. # after a torch version bump), uv reuses cached wheels and only # fetches what changed. RUN --mount=type=cache,target=/root/.cache/uv \ UV_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple \ UV_EXTRA_INDEX_URL=https://mirrors.tuna.tsinghua.edu.cn/pytorch-wheels/cpu/ \ uv pip install --python venv/bin/python torch torchvision torchaudio # ── ComfyUI deps ────────────────────────────────────────────────────── # kornia_rs is a Rust-built wheel that compiles from source on install, # adding minutes to the build. The BoosAPI workflows we care about # don't use it, so strip it. Cache mount handles re-downloads when # requirements.txt changes (most lines stay the same → most wheels # reuse from cache). RUN --mount=type=cache,target=/root/.cache/uv \ grep -v kornia_rs requirements.txt > /tmp/requirements.txt && \ UV_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple \ uv pip install --python venv/bin/python -r /tmp/requirements.txt && \ UV_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple \ uv pip install --python venv/bin/python six && \ rm /tmp/requirements.txt # ── Full ComfyUI source ─────────────────────────────────────────────── # This overlay COPY brings in everything else under comfy_source/. The # venv at /workspace/ComfyUI/venv survives because the source tree # doesn't contain a venv/ directory; requirements.txt is overwritten # with identical bytes (no-op). COPY comfy_source /workspace/ComfyUI RUN git init # ── Bake the BoosAPI patches ────────────────────────────────────────── # Keep the image self-contained: overlay patches are tracked in the parent # repo, while comfy_source remains a vanilla ComfyUI submodule. COPY comfy_patches/overlay /workspace/ComfyUI # BoosAPI custom nodes (BoosAPITextGen, image gen, etc.). RUN mkdir -p /workspace/ComfyUI/custom_nodes/boosapi_nodes COPY comfy/boosapi_comfy_nodes.py \ /workspace/ComfyUI/custom_nodes/boosapi_nodes/__init__.py # Entrypoint shim — forwards env vars to ComfyUI's CLI flags. COPY docker/comfyui-entrypoint.sh /usr/local/bin/comfyui-entrypoint RUN chmod +x /usr/local/bin/comfyui-entrypoint EXPOSE 8188 # tini reaps any subprocesses ComfyUI spawns; the shim execs into Python. ENTRYPOINT ["/usr/bin/tini", "--", "/usr/local/bin/comfyui-entrypoint"]