|
1 | | -FROM python:3.11-slim |
| 1 | +############################ |
| 2 | +# Builder stage |
| 3 | +############################ |
| 4 | +FROM python:3.11-alpine AS builder |
2 | 5 |
|
3 | | -ARG GIT_COMMIT |
4 | | -ENV GIT_COMMIT=$GIT_COMMIT |
| 6 | +ENV PYTHONDONTWRITEBYTECODE=1 \ |
| 7 | + PYTHONUNBUFFERED=1 \ |
| 8 | + APP_HOME=/home/app |
5 | 9 |
|
6 | | -# This prevents Python from writing out pyc files |
7 | | -ENV PYTHONDONTWRITEBYTECODE=1 |
8 | | -# This keeps Python from buffering stdin/stdout |
9 | | -ENV PYTHONUNBUFFERED=1 |
10 | | -ENV PIP_ARGS="--progress-bar off --no-cache-dir" |
11 | | - |
12 | | -ENV APP_HOME=/home/app |
| 10 | +RUN pip install --progress-bar off --no-cache-dir poetry==2.2.1 |
13 | 11 |
|
14 | 12 | WORKDIR $APP_HOME |
15 | 13 |
|
16 | | -# Install dependencies using poetry |
17 | | -RUN pip install $PIP_ARGS "poetry==2.1.1" |
18 | | -RUN poetry self add poetry-plugin-export |
19 | | -COPY pyproject.toml . |
20 | | -COPY poetry.lock . |
21 | | -RUN poetry export -f requirements.txt --without-hashes | pip install $PIP_ARGS -r /dev/stdin |
| 14 | +# Install dependencies first to leverage Docker layer caching |
| 15 | +COPY pyproject.toml poetry.lock poetry.toml ./ |
| 16 | +RUN poetry install --no-interaction --no-ansi --no-cache --no-root \ |
| 17 | + --no-directory --only main |
22 | 18 |
|
23 | | -# Copy source code |
| 19 | +# Copy source code and install the project |
24 | 20 | COPY ./statgpt/app $APP_HOME/statgpt/app |
25 | 21 | COPY ./statgpt/common $APP_HOME/statgpt/common |
| 22 | +RUN poetry install --no-interaction --no-ansi --no-cache --no-root --only main |
| 23 | + |
| 24 | +############################ |
| 25 | +# Runtime stage |
| 26 | +############################ |
| 27 | +FROM python:3.11-alpine AS server |
| 28 | + |
| 29 | +# Security patches (consolidated into single layer) |
| 30 | +# CVE-2023-52425 (libexpat), CVE-2025-6965 (sqlite-libs), libcrypto3/libssl3 |
| 31 | +RUN apk update && apk upgrade --no-cache \ |
| 32 | + libcrypto3 libssl3 libexpat sqlite-libs \ |
| 33 | + && apk add --no-cache ca-certificates \ |
| 34 | + && update-ca-certificates \ |
| 35 | + && rm -rf /var/cache/apk/* |
| 36 | + |
| 37 | +# CVE-2026-23949 (setuptools), CVE-2026-24049 (wheel) |
| 38 | +RUN pip install --no-cache-dir setuptools==80.10.2 wheel==0.46.2 |
| 39 | + |
| 40 | +ENV PYTHONDONTWRITEBYTECODE=1 \ |
| 41 | + PYTHONUNBUFFERED=1 \ |
| 42 | + APP_HOME=/home/app \ |
| 43 | + WEB_CONCURRENCY=1 \ |
| 44 | + PYDANTIC_V2=True |
26 | 45 |
|
27 | | -# create the app user and chown workdir to the app user |
28 | | -RUN adduser -u 5678 --system --disabled-password --gecos "" app && chown -R app $APP_HOME |
29 | | -USER app |
| 46 | +WORKDIR $APP_HOME |
| 47 | + |
| 48 | +# Create non-root user and copy built application |
| 49 | +RUN adduser -u 1001 --disabled-password --gecos "" appuser |
| 50 | +COPY --chown=appuser --from=builder $APP_HOME . |
30 | 51 |
|
31 | | -ENV WEB_CONCURRENCY=1 |
32 | | -ENV PYDANTIC_V2=True |
| 52 | +COPY --chmod=755 ./docker/scripts/chat_docker_entrypoint.sh /docker_entrypoint.sh |
33 | 53 |
|
34 | 54 | EXPOSE 5000 |
35 | 55 |
|
36 | | -CMD ["uvicorn", "statgpt.app.app:app", "--host", "0.0.0.0", "--port", "5000", "--lifespan", "on"] |
| 56 | +USER appuser |
| 57 | + |
| 58 | +HEALTHCHECK --interval=10s --timeout=5s --start-period=30s --retries=6 \ |
| 59 | + CMD wget -q --spider -T 3 http://localhost:5000/health || exit 1 |
| 60 | + |
| 61 | +ARG GIT_COMMIT |
| 62 | +ENV GIT_COMMIT=$GIT_COMMIT |
| 63 | + |
| 64 | +ENTRYPOINT ["/docker_entrypoint.sh"] |
0 commit comments