Spaces:
Sleeping
Sleeping
| # syntax=docker/dockerfile:1.7 | |
| # ---------- Stage 1: official llama.cpp server image ---------- | |
| # Use the upstream prebuilt server-only image (~71 MB) instead of compiling | |
| # from source. This dropped Space build time from ~30 min (compiling all of | |
| # mtmd/clip/vision-models on a 2-vCPU runner) to ~30 sec, and the upstream | |
| # image is built/tested by the llama.cpp maintainers for every release. | |
| # Pin to a tag (overridable) for reproducibility; defaults to :server. | |
| ARG LLAMA_CPP_IMAGE=ghcr.io/ggml-org/llama.cpp:server | |
| FROM ${LLAMA_CPP_IMAGE} AS llama | |
| # ---------- Stage 2: download model ---------- | |
| FROM ubuntu:24.04 AS modelfetch | |
| ARG MODEL_REPO=unsloth/gemma-4-E2B-it-GGUF | |
| ARG MODEL_FILE=gemma-4-E2B-it-UD-Q4_K_XL.gguf | |
| ENV DEBIAN_FRONTEND=noninteractive | |
| RUN apt-get update && apt-get install -y --no-install-recommends \ | |
| ca-certificates \ | |
| curl \ | |
| && rm -rf /var/lib/apt/lists/* | |
| WORKDIR /model | |
| # Download GGUF from Hugging Face. URL is constructed only from build-args | |
| # (not from any user-controlled runtime input), so this does not violate | |
| # the rule against using user input in network/file paths at runtime. | |
| RUN set -eux; \ | |
| url="https://huggingface.co/${MODEL_REPO}/resolve/main/${MODEL_FILE}?download=true"; \ | |
| echo "Downloading ${url}"; \ | |
| curl -fL --retry 5 --retry-delay 5 --retry-all-errors \ | |
| -o "/model/${MODEL_FILE}" \ | |
| "${url}"; \ | |
| ls -lh "/model/${MODEL_FILE}" | |
| # ---------- Stage 3: runtime ---------- | |
| # Must match the upstream :server image's glibc/libstdc++ ABI. Upstream is | |
| # built on ubuntu:24.04 (glibc 2.39, libstdc++ from gcc-14); debian bookworm | |
| # only has glibc 2.36 / older libstdc++ and the binary fails to load with | |
| # "GLIBC_2.38 not found" / "GLIBCXX_3.4.32 not found". | |
| FROM ubuntu:24.04 AS runtime | |
| ENV DEBIAN_FRONTEND=noninteractive | |
| # Slim runtime: only what llama-server actually links against (libgomp for | |
| # OpenMP) plus curl for HEALTHCHECK and tini for PID 1. The upstream :server | |
| # image is built without OpenBLAS, so no libopenblas0 needed; libcurl4 is | |
| # pulled in because the upstream image has LLAMA_CURL=ON, but we never use | |
| # the --hf-repo path at runtime — it's a small (~6 MB) cost we accept to | |
| # avoid maintaining our own build. | |
| RUN apt-get update && apt-get install -y --no-install-recommends \ | |
| ca-certificates \ | |
| curl \ | |
| libcurl4 \ | |
| libgomp1 \ | |
| tini \ | |
| && apt-get autoremove -y \ | |
| && apt-get clean \ | |
| && rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/* | |
| ARG MODEL_FILE=gemma-4-E2B-it-UD-Q4_K_XL.gguf | |
| # Hugging Face Spaces requires a non-root user with UID 1000 and a writable | |
| # /home/user directory. ubuntu:24.04 ships with a default `ubuntu` user | |
| # already at UID 1000, so we rename that user/group/home to `user` instead | |
| # of creating a new one (which would fail with "UID 1000 is not unique"). | |
| RUN userdel -r ubuntu 2>/dev/null || true \ | |
| && groupadd -g 1000 user \ | |
| && useradd -m -u 1000 -g 1000 -s /bin/bash user | |
| # Upstream :server image is built with GGML_BACKEND_DL=ON, meaning the CPU | |
| # backend (libggml-cpu-*.so) is a runtime plugin that llama-server dlopens | |
| # from its own directory. Keep the binary and ALL its *.so* siblings together | |
| # in /app and add /app to the dynamic linker path so both PUBLIC libs and | |
| # DL-plugin backends resolve correctly. Splitting them across /usr/local/bin | |
| # vs /usr/local/lib breaks plugin discovery ("no backends are loaded"). | |
| COPY --from=llama /app/ /app/ | |
| RUN echo "/app" > /etc/ld.so.conf.d/llama.conf && ldconfig \ | |
| && ln -sf /app/llama-server /usr/local/bin/llama-server | |
| COPY --from=modelfetch /model/${MODEL_FILE} /models/${MODEL_FILE} | |
| RUN chown -R user:user /models | |
| COPY --chown=user:user entrypoint.sh /usr/local/bin/entrypoint.sh | |
| RUN chmod +x /usr/local/bin/entrypoint.sh | |
| USER user | |
| WORKDIR /home/user | |
| ENV MODEL_PATH=/models/${MODEL_FILE} \ | |
| PORT=7860 \ | |
| HOST=0.0.0.0 \ | |
| CTX_SIZE=4096 \ | |
| THREADS=2 \ | |
| THREADS_BATCH=4 \ | |
| PARALLEL=1 \ | |
| N_PREDICT=-1 \ | |
| OMP_WAIT_POLICY=active \ | |
| LLAMA_API_KEY="" | |
| EXPOSE 7860 | |
| HEALTHCHECK --interval=30s --timeout=10s --start-period=120s --retries=3 \ | |
| CMD curl -fsS "http://127.0.0.1:${PORT}/health" || exit 1 | |
| ENTRYPOINT ["/usr/bin/tini", "--", "/usr/local/bin/entrypoint.sh"] | |