From bda52291832c29290e405fddc73649e67f241fac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A1=E5=8F=A3=E6=B5=AA=E4=BA=BA?= Date: Sat, 17 Oct 2026 13:41:29 +0800 Subject: [PATCH] build: exclude packaging tools from production images [skip ci] --- .dockerignore | 3 +++ Dockerfile | 15 ++++++++++++++- deploy/Dockerfile.runtime-update | 22 +++++++++++++++++++++- 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/.dockerignore b/.dockerignore index f920761..6620404 100644 --- a/.dockerignore +++ b/.dockerignore @@ -14,3 +14,6 @@ dist .mypy_cache **/__pycache__ **/*.pyc + +# macOS metadata at any depth +**/.DS_Store diff --git a/Dockerfile b/Dockerfile index 3b9bc53..70815e2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ ARG PYTHON_BASE=python:3.14.5-slim-bookworm@sha256:ec58d916f9e24a6035cab2bdf07f6206c4cc092a16613c60597534711332d9d6 -FROM ${PYTHON_BASE} +FROM ${PYTHON_BASE} AS prepared ARG DEBIAN_MIRROR=deb.debian.org ARG DEBIAN_SECURITY_MIRROR=deb.debian.org ARG TARGETARCH @@ -37,6 +37,19 @@ RUN --mount=type=cache,id=frameflow-pip-py314-${TARGETARCH},target=/root/.cache/ else python /build-tools/install.py --locked; fi COPY pigway_frame_flow ./pigway_frame_flow COPY vendor ./vendor +# Publish only the cleaned filesystem, without retaining build-stage layers. +RUN rm -rf /usr/local/lib/python*/site-packages/pip \ + /usr/local/lib/python*/site-packages/pip-*.dist-info \ + /usr/local/lib/python*/ensurepip \ + && rm -f /usr/local/bin/pip /usr/local/bin/pip[0-9]* \ + && find / -name .DS_Store -type f -delete + +FROM scratch +COPY --from=prepared / / +ENV PATH=/usr/local/bin:/usr/local/sbin:/usr/sbin:/usr/bin:/sbin:/bin LANG=C.UTF-8 +ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1 TZ=Asia/Shanghai \ + DATA_DIR=/data CONFIG_DIR=/config +WORKDIR /app ARG BUILD_COMMIT=development ARG BUILD_TIME=unknown ENV BUILD_COMMIT=$BUILD_COMMIT BUILD_TIME=$BUILD_TIME diff --git a/deploy/Dockerfile.runtime-update b/deploy/Dockerfile.runtime-update index 8fcc218..8290ba7 100644 --- a/deploy/Dockerfile.runtime-update +++ b/deploy/Dockerfile.runtime-update @@ -1,11 +1,31 @@ # Reuse a reviewed image only when the locked Python dependencies are identical. # For a fresh installation use the repository's main Dockerfile instead. ARG BASE_IMAGE -FROM ${BASE_IMAGE} +FROM ${BASE_IMAGE} AS prepared +# Cleanup runs only in the disposable preparation stage. +USER 0 COPY requirements.lock /app/requirements.expected.lock RUN python -c "from pathlib import Path; assert Path('/app/requirements.lock').read_bytes() == Path('/app/requirements.expected.lock').read_bytes(), 'Dependency lock changed; use the full Dockerfile'" COPY pigway_frame_flow /app/pigway_frame_flow COPY vendor /app/vendor +# Publish only the cleaned filesystem, without retaining build-stage layers. +RUN rm -rf /usr/local/lib/python*/site-packages/pip \ + /usr/local/lib/python*/site-packages/pip-*.dist-info \ + /usr/local/lib/python*/ensurepip \ + && rm -f /usr/local/bin/pip /usr/local/bin/pip[0-9]* \ + && find / -name .DS_Store -type f -delete + +FROM scratch +COPY --from=prepared / / +ENV PATH=/usr/local/bin:/usr/local/sbin:/usr/sbin:/usr/bin:/sbin:/bin LANG=C.UTF-8 +ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1 TZ=Asia/Shanghai \ + DATA_DIR=/data CONFIG_DIR=/config +WORKDIR /app +USER 10333:10333 +EXPOSE 18787 +HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \ + CMD python -c "import urllib.request; urllib.request.urlopen('http://127.0.0.1:18787/health',timeout=3)" +CMD ["python", "-m", "uvicorn", "pigway_frame_flow.main:app", "--host", "0.0.0.0", "--port", "18787", "--workers", "1", "--no-access-log"] ARG BUILD_COMMIT ARG BUILD_TIME ENV BUILD_COMMIT=$BUILD_COMMIT BUILD_TIME=$BUILD_TIME