mirror of
https://github.com/tiennm99/litellm.git
synced 2026-07-08 13:12:16 +00:00
1fd8ab4c5f
* fix(docker): copy only runtime artifacts into the final image The runtime stage previously copied the builder's entire /app workspace, shipping the full source tree and dependency manifests (uv.lock, the dashboard package-lock.json, ui/) in the published images. Tools that read manifests found in an image attribute every pin in them to the image, including packages that are never installed, which produces recurring false reports against the official images. The runtime stage now copies an explicit allowlist: the venv (where the application is installed), the entrypoint scripts, schema.prisma, prisma_migration.py (invoked by source path from entrypoint.sh), and the prisma binary caches. npm and its globally installed helper packages are dropped from the runtime stage; node stays for the prisma CLI. The database image's /root/.cache copy is narrowed to the prisma subdirs, matching the main Dockerfile, which removes the uv build cache from that image (-1.1GB). Verified on locally built images for all three variants against a contract suite that passes 100% on the v1.88.1 baselines: byte-identical venv vs old-Dockerfile builds from the same commit, DB-less and Postgres-backed boots, migration entrypoint, real completion and streaming calls, admin UI, key generation, non-root UID behavior. Image sizes: main 1.71GB -> 1.53GB, database 2.68GB -> 1.53GB * fix(docker): restore enterprise source dir required by runtime imports litellm/proxy/hooks/__init__.py, callback_utils.py and customer_endpoints.py import enterprise.* by source path, resolved via the cwd entry proxy_cli appends to sys.path, with silent ImportError fallbacks. Dropping /app/enterprise from the runtime image emptied ENTERPRISE_PROXY_HOOKS and broke managed files (e2e_openai_endpoints caught it). Restore the directory in all three runtime stages
149 lines
5.9 KiB
Docker
149 lines
5.9 KiB
Docker
# Base images
|
|
ARG LITELLM_BUILD_IMAGE=cgr.dev/chainguard/wolfi-base@sha256:3258be472764337fd13095bcbb3182da170243b5819fd67ad4c0754590588b31
|
|
ARG LITELLM_RUNTIME_IMAGE=cgr.dev/chainguard/wolfi-base@sha256:3258be472764337fd13095bcbb3182da170243b5819fd67ad4c0754590588b31
|
|
ARG PROXY_EXTRAS_SOURCE=published
|
|
ARG UV_IMAGE=ghcr.io/astral-sh/uv:0.11.7@sha256:240fb85ab0f263ef12f492d8476aa3a2e4e1e333f7d67fbdd923d00a506a516a
|
|
|
|
FROM $UV_IMAGE AS uvbin
|
|
|
|
FROM $LITELLM_BUILD_IMAGE AS builder
|
|
ARG PROXY_EXTRAS_SOURCE
|
|
WORKDIR /app
|
|
USER root
|
|
|
|
COPY --from=uvbin /uv /usr/local/bin/uv
|
|
COPY --from=uvbin /uvx /usr/local/bin/uvx
|
|
|
|
RUN for i in 1 2 3; do \
|
|
apk add --no-cache \
|
|
python3 \
|
|
python3-dev \
|
|
gcc \
|
|
bash \
|
|
coreutils \
|
|
curl \
|
|
openssl \
|
|
libsndfile \
|
|
nodejs \
|
|
npm && break || sleep 5; \
|
|
done
|
|
|
|
ENV UV_PROJECT_ENVIRONMENT=/app/.venv \
|
|
UV_LINK_MODE=copy \
|
|
PATH="/app/.venv/bin:${PATH}" \
|
|
LITELLM_NON_ROOT=true \
|
|
PRISMA_BINARY_CACHE_DIR=/app/.cache/prisma-python/binaries \
|
|
XDG_CACHE_HOME=/app/.cache
|
|
|
|
# Copy dependency metadata first for layer caching
|
|
COPY pyproject.toml uv.lock ./
|
|
COPY enterprise/pyproject.toml enterprise/
|
|
COPY litellm-proxy-extras/pyproject.toml litellm-proxy-extras/
|
|
|
|
# Install third-party dependencies (cached unless pyproject.toml/uv.lock change)
|
|
RUN --mount=type=cache,target=/app/.cache/uv,id=litellm-uv-cache \
|
|
uv sync --frozen --no-install-project --no-install-workspace --no-default-groups --no-editable \
|
|
--extra proxy \
|
|
--extra proxy-runtime \
|
|
--extra extra_proxy \
|
|
--extra semantic-router \
|
|
--python python3
|
|
|
|
# Copy full source tree
|
|
COPY . .
|
|
|
|
# Set non-root flag for build time consistency
|
|
ENV LITELLM_NON_ROOT=true
|
|
|
|
RUN mkdir -p /var/lib/litellm/ui /var/lib/litellm/assets && \
|
|
cp -r /app/litellm/proxy/_experimental/out/. /var/lib/litellm/ui/ && \
|
|
cp /app/litellm/proxy/logo.jpg /var/lib/litellm/assets/logo.jpg && \
|
|
touch /var/lib/litellm/ui/.litellm_ui_ready
|
|
|
|
RUN --mount=type=cache,target=/app/.cache/uv,id=litellm-uv-cache \
|
|
if [ "$PROXY_EXTRAS_SOURCE" = "published" ]; then \
|
|
uv sync --frozen --no-default-groups --no-editable \
|
|
--extra proxy \
|
|
--extra proxy-runtime \
|
|
--extra extra_proxy \
|
|
--extra semantic-router \
|
|
--python python3 \
|
|
--no-sources-package litellm-proxy-extras; \
|
|
else \
|
|
uv sync --frozen --no-default-groups --no-editable \
|
|
--extra proxy \
|
|
--extra proxy-runtime \
|
|
--extra extra_proxy \
|
|
--extra semantic-router \
|
|
--python python3; \
|
|
fi
|
|
|
|
RUN prisma generate --schema=./schema.prisma
|
|
|
|
RUN sed -i 's/\r$//' docker/entrypoint.sh && chmod +x docker/entrypoint.sh && \
|
|
sed -i 's/\r$//' docker/prod_entrypoint.sh && chmod +x docker/prod_entrypoint.sh
|
|
|
|
FROM $LITELLM_RUNTIME_IMAGE AS runtime
|
|
ARG PROXY_EXTRAS_SOURCE
|
|
WORKDIR /app
|
|
USER root
|
|
|
|
RUN for i in 1 2 3; do \
|
|
apk upgrade --no-cache && break || sleep 5; \
|
|
done && \
|
|
for i in 1 2 3; do \
|
|
apk add --no-cache python3 bash openssl tzdata libsndfile nodejs && break || sleep 5; \
|
|
done
|
|
|
|
# Copy only what runtime needs. The application is installed inside the venv;
|
|
# the rest of the builder's /app is source and build metadata that must not
|
|
# ship (manifest-scanning tools attribute everything in it to this image).
|
|
# entrypoint.sh invokes litellm/proxy/prisma_migration.py by source path.
|
|
# Prisma caches live under /app/.cache here (XDG_CACHE_HOME /
|
|
# PRISMA_BINARY_CACHE_DIR) so the runtime prisma generate finds them.
|
|
COPY --from=builder /app/.venv /app/.venv
|
|
COPY --from=builder /app/docker /app/docker
|
|
COPY --from=builder /app/schema.prisma /app/schema.prisma
|
|
COPY --from=builder /app/litellm/proxy/prisma_migration.py /app/litellm/proxy/prisma_migration.py
|
|
# enterprise/ is imported by source path at runtime (proxy_cli puts the
|
|
# working directory on sys.path; litellm/proxy/hooks resolves
|
|
# enterprise.enterprise_hooks from it)
|
|
COPY --from=builder /app/enterprise /app/enterprise
|
|
COPY --from=builder /app/.cache /app/.cache
|
|
COPY --from=builder /var/lib/litellm/ui /var/lib/litellm/ui
|
|
COPY --from=builder /var/lib/litellm/assets /var/lib/litellm/assets
|
|
|
|
ENV PATH="/app/.venv/bin:${PATH}" \
|
|
PRISMA_BINARY_CACHE_DIR=/app/.cache/prisma-python/binaries \
|
|
HOME=/app \
|
|
LITELLM_NON_ROOT=true \
|
|
XDG_CACHE_HOME=/app/.cache \
|
|
PRISMA_SKIP_POSTINSTALL_GENERATE=1 \
|
|
PRISMA_HIDE_UPDATE_MESSAGE=1 \
|
|
PRISMA_ENGINES_CHECKSUM_IGNORE_MISSING=1 \
|
|
PRISMA_OFFLINE_MODE=true
|
|
|
|
RUN mkdir -p /nonexistent /var/lib/litellm/assets /var/lib/litellm/ui && \
|
|
chown -R nobody:nogroup /app /var/lib/litellm/ui /var/lib/litellm/assets /nonexistent && \
|
|
PRISMA_PATH=$(python -c "import os, prisma; print(os.path.dirname(prisma.__file__))") && \
|
|
chown -R nobody:nogroup "$PRISMA_PATH" && \
|
|
LITELLM_PKG_MIGRATIONS_PATH="$(python -c 'import os, litellm_proxy_extras; print(os.path.dirname(litellm_proxy_extras.__file__))' 2>/dev/null || echo '')/migrations" && \
|
|
[ -n "$LITELLM_PKG_MIGRATIONS_PATH" ] && chown -R nobody:nogroup "$LITELLM_PKG_MIGRATIONS_PATH" || true && \
|
|
LITELLM_PROXY_EXTRAS_PATH=$(python -c "import os, litellm_proxy_extras; print(os.path.dirname(litellm_proxy_extras.__file__))" 2>/dev/null || echo "") && \
|
|
chgrp -R 0 "$PRISMA_PATH" /var/lib/litellm/ui /var/lib/litellm/assets && \
|
|
[ -n "$LITELLM_PROXY_EXTRAS_PATH" ] && chgrp -R 0 "$LITELLM_PROXY_EXTRAS_PATH" || true && \
|
|
chmod -R g=u "$PRISMA_PATH" /var/lib/litellm/ui /var/lib/litellm/assets && \
|
|
[ -n "$LITELLM_PROXY_EXTRAS_PATH" ] && chmod -R g=u "$LITELLM_PROXY_EXTRAS_PATH" || true && \
|
|
chmod -R g+w "$PRISMA_PATH" /var/lib/litellm/ui /var/lib/litellm/assets && \
|
|
[ -n "$LITELLM_PROXY_EXTRAS_PATH" ] && chmod -R g+w "$LITELLM_PROXY_EXTRAS_PATH" || true && \
|
|
chmod -R g+rX "$PRISMA_PATH" /var/lib/litellm/ui /var/lib/litellm/assets /app/.cache
|
|
|
|
USER 65534
|
|
|
|
RUN prisma generate --schema=./schema.prisma
|
|
|
|
EXPOSE 4000/tcp
|
|
|
|
ENTRYPOINT ["/app/docker/prod_entrypoint.sh"]
|
|
CMD ["--port", "4000"]
|