File size: 4,403 Bytes
7c447a5
 
 
 
 
 
 
 
e8997ce
7c447a5
 
 
e8997ce
7c447a5
e8997ce
 
 
 
 
 
 
7c447a5
e8997ce
7c447a5
d02be95
e8997ce
7c447a5
 
e8997ce
7c447a5
 
e8997ce
 
 
7c447a5
 
 
 
e8997ce
17c5c69
18362b0
e8cf564
 
 
 
 
 
 
97a31eb
7c447a5
e8997ce
cf579a5
7c447a5
e8997ce
 
 
 
e8cf564
 
 
 
 
 
18362b0
cf579a5
17c5c69
 
 
cf579a5
7c447a5
e8997ce
cf579a5
e8997ce
7c447a5
 
cf579a5
7c447a5
 
18362b0
 
 
cf579a5
 
 
 
 
8b951c1
17c5c69
 
 
 
 
 
cf579a5
 
 
17c5c69
cf579a5
7c447a5
 
 
 
 
 
 
 
 
 
 
8b951c1
17c5c69
 
 
7c447a5
 
 
cf579a5
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# ---------- Frontend build ----------
FROM node:20-bullseye AS fe
WORKDIR /app/frontend
COPY frontend/package*.json ./
RUN npm ci
COPY frontend/ ./
RUN npm run build

# ---------- Backend build (build venv only) ----------
FROM python:3.11-slim AS be
ENV PIP_NO_CACHE_DIR=1 PYTHONUNBUFFERED=1 PIP_PREFER_BINARY=1
WORKDIR /app

RUN apt-get update && apt-get install -y --no-install-recommends \
    build-essential gcc g++ gfortran make pkg-config \
    libopenblas-dev liblapack-dev git \
 && rm -rf /var/lib/apt/lists/*

RUN python -m venv /opt/venv
ENV PATH="/opt/venv/bin:${PATH}"

RUN python -m pip install --upgrade pip setuptools wheel

RUN pip install --index-url https://download.pytorch.org/whl/cpu "torch==2.3.1"
RUN pip install --no-cache-dir safetensors accelerate

COPY backend/requirements.txt ./backend/requirements.txt
RUN sed -i 's/^[Tt]orch[[:space:]=<>!].*/# torch pinned separately (CPU)/' backend/requirements.txt || true

RUN pip install --only-binary=:all: blis || echo "Precompiled blis not available"
RUN pip install -r backend/requirements.txt || pip install -r backend/requirements.txt --no-deps

RUN pip install --no-cache-dir gunicorn

COPY backend/ ./backend/

# ---------- Runtime ----------
FROM python:3.11-slim AS runtime
ENV PYTHONUNBUFFERED=1 PIP_NO_CACHE_DIR=1 PORT=7860 \
    PATH="/opt/venv/bin:${PATH}" \
    MPLCONFIGDIR=/tmp 
ENV HOME=/tmp \
    XDG_CACHE_HOME=/tmp/.cache \
    HF_HOME=/tmp/.cache/huggingface \
    HF_HUB_CACHE=/tmp/.cache/huggingface/hub \
    HF_DATASETS_CACHE=/tmp/.cache/huggingface/datasets \
    TRANSFORMERS_CACHE=/tmp/.cache/huggingface/transformers \
    MPLCONFIGDIR=/tmp
RUN mkdir -p /tmp/huggingface /tmp/transformers /tmp/hub /tmp/datasets
WORKDIR /app

# 依賴
RUN apt-get update && apt-get install -y --no-install-recommends \
    nginx supervisor ca-certificates \
    libgomp1 libopenblas0 \
 && rm -rf /var/lib/apt/lists/*

RUN install -d -m 0777 \
    /tmp/.cache \
    /tmp/.cache/huggingface/hub \
    /tmp/.cache/huggingface/datasets \
    /tmp/.cache/huggingface/transformers \
    /tmp/nginx/client_body /tmp/nginx/proxy /tmp/nginx/fastcgi /tmp/nginx/uwsgi /tmp/nginx/scgi

# 建立可寫暫存
RUN mkdir -p /tmp/nginx/client_body /tmp/nginx/proxy /tmp/nginx/fastcgi /tmp/nginx/uwsgi /tmp/nginx/scgi \
    /tmp/matplotlib

# 前端
COPY --from=fe /app/frontend/dist /usr/share/nginx/html

# venv + 後端
COPY --from=be /opt/venv /opt/venv
COPY --from=be /app/backend /app/backend

# nginx 主設定
COPY nginx.conf.template /etc/nginx/nginx.conf

RUN printf "access_log /dev/stdout;\nerror_log /dev/stderr info;\n" \
  > /etc/nginx/conf.d/log_to_stdout.conf

# 放一個 http 級別的 drop-in,避免高風險 sed
RUN printf "client_max_body_size 100M;\nclient_body_temp_path /tmp/nginx/client_body;\nproxy_temp_path /tmp/nginx/proxy;\nfastcgi_temp_path /tmp/nginx/fastcgi;\nuwsgi_temp_path /tmp/nginx/uwsgi;\nscgi_temp_path /tmp/nginx/scgi;\n" \
    > /etc/nginx/conf.d/temp_paths.conf

# 調整 nginx.conf:移除 user;設定 pid;在 http{} 內包含 conf.d
RUN set -eux; \
  sed -ri 's/^\s*user\s+[^;]+;//g' /etc/nginx/nginx.conf || true; \
  if grep -qE '^\s*pid\s+' /etc/nginx/nginx.conf; then \
    sed -ri 's|^\s*pid\s+[^;]+;|pid /tmp/nginx.pid;|' /etc/nginx/nginx.conf; \
  else \
    sed -ri '1i pid /tmp/nginx.pid;' /etc/nginx/nginx.conf; \
  fi; \
  if ! grep -q 'include /etc/nginx/conf.d/\*.conf;' /etc/nginx/nginx.conf; then \
    sed -ri 's|(^\s*include\s+/etc/nginx/mime\.types;)|\1\n    include /etc/nginx/conf.d/*.conf;|' /etc/nginx/nginx.conf; \
  fi

# supervisor 設定:pidfile 放 /tmp;不要 user=
RUN mkdir -p /etc/supervisor/conf.d && \
printf "[program:api]\n\
command=gunicorn --workers 2 --threads 8 --timeout 0 --chdir /app/backend -b 0.0.0.0:5001 server:app\n\
priority=10\nautostart=true\nautorestart=true\n\
stdout_logfile=/dev/stdout\nstderr_logfile=/dev/stderr\n\
stdout_logfile_maxbytes=0\nstderr_logfile_maxbytes=0\n\n\
[program:nginx]\n\
command=nginx -g \"daemon off;\"\n\
priority=20\nautostart=true\nautorestart=true\n\
stdout_logfile=/dev/stdout\nstderr_logfile=/dev/stderr\n\
stdout_logfile_maxbytes=0\nstderr_logfile_maxbytes=0\n\n\
[supervisord]\n\
logfile=/dev/stdout\nlogfile_maxbytes=0\n\
pidfile=/tmp/supervisord.pid\n\
nodaemon=true\n" \
> /etc/supervisor/conf.d/app.conf

EXPOSE 7860
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/app.conf"]