File size: 4,370 Bytes
7b6257f
 
e1d8498
7b6257f
 
 
 
 
e1d8498
7b6257f
 
 
 
47f9aeb
 
 
f526e24
 
 
10fc7f0
47f9aeb
 
 
 
 
 
 
 
 
 
e1d8498
 
 
 
 
7b6257f
e1d8498
03267ae
e1d8498
 
 
 
 
7b6257f
e1d8498
47f9aeb
 
10fc7f0
 
e1d8498
7b6257f
 
 
 
 
e1d8498
47f9aeb
 
 
 
 
10fc7f0
f526e24
 
 
47f9aeb
f526e24
e1d8498
 
 
 
7b6257f
 
e1d8498
7b6257f
 
 
 
 
e1d8498
 
 
 
7b6257f
 
e1d8498
 
 
 
 
 
 
 
 
 
 
f526e24
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
# Dockerfile.huggingface - HF Spaces single container
# LiteLLM v1.81.14 with external PostgreSQL via DATABASE_URL
#
# Required HF Space secrets:
#   DATABASE_URL        postgresql://user:pass@host:5432/db
#   LITELLM_SALT_KEY    random string, encrypts API keys in DB (never change after first use)
#   LITELLM_MASTER_KEY  admin key
#   JWT_SECRET          session secret
#
# Bug fixes:
#   [Bug2]  build-essential for better-sqlite3 node-gyp fallback
#   [Bug3]  npm install --omit=dev (--only=production deprecated in npm v10)
#   [Bug5]  ARG LITELLM_VERSION for single-source versioning
#   [BugP]  prisma generate — LiteLLM v1.61+ 在 database_url 存在时会在 FastAPI
#           lifespan 启动阶段初始化 Prisma 客户端,需要 query-engine 二进制文件
#           预先存在。否则容器立即崩溃:
#             ModuleNotFoundError: No module named 'prisma'
#             Exception: Unable to find Prisma binaries.
#                        Please run 'prisma generate' first.
#
#           根因分析(三层):
#           1. litellm[proxy]==1.81.14 的依赖树里 **没有** prisma 包,
#              必须显式 pip install prisma。
#           2. prisma generate 产生的 query-engine 二进制默认写入
#              ~/.cache/prisma-binaries/(即 root 的 /root/.cache/),
#              但容器运行时是 uid=1000(user),查找路径是
#              /home/user/.cache/ → 完全不同的目录 → 找不到。
#           3. 修复:设 PRISMA_BINARY_CACHE_DIR=/app/.prisma(在 /app 下,
#              后续 chown -R user:user /app 会覆盖到这里),build 阶段和
#              运行时都读同一个环境变量,路径始终一致。

FROM node:20-alpine AS frontend-builder
WORKDIR /build
ARG VITE_API_BASE=/api
ARG VITE_APP_NAME="AI Gateway Hub"
ENV VITE_API_BASE=$VITE_API_BASE VITE_APP_NAME=$VITE_APP_NAME
COPY frontend/package*.json ./
RUN npm install
COPY frontend/ .
RUN npm run build

FROM python:3.11-slim

ARG LITELLM_VERSION=1.81.14

# 把 prisma 二进制缓存目录固定到 /app/.prisma,
# 使 build 阶段(root)和运行时(uid=1000)使用同一路径。
ENV PRISMA_BINARY_CACHE_DIR=/app/.prisma

RUN apt-get update && apt-get install -y --no-install-recommends \
        curl gnupg ca-certificates nginx supervisor build-essential \
    && curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
    && apt-get install -y --no-install-recommends nodejs \
    && apt-get purge -y gnupg && apt-get autoremove -y \
    && rm -rf /var/lib/apt/lists/*

# [BugP 修复]
# litellm[proxy]==1.81.14 的依赖里不含 prisma,需要单独安装。
# 安装后立即执行 prisma generate,将 query-engine 写入
# $PRISMA_BINARY_CACHE_DIR(/app/.prisma),后续 chown 会一并处理权限。
RUN pip install --no-cache-dir "litellm[proxy]==${LITELLM_VERSION}" prisma \
    && mkdir -p "${PRISMA_BINARY_CACHE_DIR}" \
    && SCHEMA_PATH=$(python3 -c \
         "import litellm, os; \
          print(os.path.join(os.path.dirname(litellm.__file__), 'proxy', 'schema.prisma'))") \
    && echo "Running: prisma generate --schema ${SCHEMA_PATH}" \
    && prisma generate --schema "${SCHEMA_PATH}"

RUN useradd -m -u 1000 -s /bin/bash user

RUN mkdir -p \
        /app/frontend/dist /app/backend/src /app/litellm \
        /app/huggingface /app/data \
        /var/log/supervisor \
        /tmp/nginx/client_body /tmp/nginx/proxy \
        /tmp/nginx/fastcgi /tmp/nginx/uwsgi /tmp/nginx/scgi \
    && chown -R user:user \
        /app /var/log/supervisor \
        /var/log/nginx /var/lib/nginx /tmp/nginx

COPY --from=frontend-builder --chown=user:user /build/dist /app/frontend/dist

COPY --chown=user:user backend/package*.json /app/backend/
RUN cd /app/backend && npm install --omit=dev \
    && chown -R user:user /app/backend/node_modules
COPY --chown=user:user backend/src/ /app/backend/src/

COPY --chown=user:user litellm/config.yaml           /app/litellm/config.yaml
COPY --chown=user:user huggingface/nginx.conf        /app/huggingface/nginx.conf
COPY --chown=user:user huggingface/supervisord.conf  /app/huggingface/supervisord.conf
COPY --chown=user:user huggingface/entrypoint.sh     /app/huggingface/entrypoint.sh
RUN chmod +x /app/huggingface/entrypoint.sh

USER user
WORKDIR /app
EXPOSE 7860
ENTRYPOINT ["/app/huggingface/entrypoint.sh"]