refactor(docker): Adopt multi-stage build for optimized image size and security

- Implement base/builder/runtime three-stage build architecture
  - Introduce Python virtual environment for dependency isolation
  - Separate build and runtime environments to reduce final image size
  - Optimize Nuitka module compilation and cleanup process
  - Dockerfile-cn: Improve China mirror source compatibility
This commit is contained in:
luojiyin 2025-11-12 16:41:28 +08:00
parent fe324c14ea
commit 8a40cc56ac
No known key found for this signature in database
GPG Key ID: 9F5399380CCFD0B3
2 changed files with 175 additions and 131 deletions

View File

@ -1,45 +1,93 @@
# 使用Python 3.11作为基础镜像
FROM python:3.11-slim-bookworm
# syntax=docker/dockerfile:1
# 设置标签信息
LABEL maintainer="zhinianboke"
LABEL version="2.2.0"
LABEL description="闲鱼自动回复系统 - 企业级多用户版本,支持自动发货和免拼发货"
LABEL repository="https://github.com/zhinianboke/xianyu-auto-reply"
LABEL license="仅供学习使用,禁止商业用途"
LABEL author="zhinianboke"
LABEL build-date=""
LABEL vcs-ref=""
# Base stage with shared environment configuration
FROM python:3.11-slim-bookworm AS base
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
TZ=Asia/Shanghai \
DOCKER_ENV=true \
PLAYWRIGHT_BROWSERS_PATH=/ms-playwright
# 设置工作目录
WORKDIR /app
# 设置环境变量
ENV PYTHONUNBUFFERED=1
ENV PYTHONDONTWRITEBYTECODE=1
ENV TZ=Asia/Shanghai
ENV DOCKER_ENV=true
ENV PLAYWRIGHT_BROWSERS_PATH=/ms-playwright
# Nuitka编译优化
ENV CC=gcc
ENV CXX=g++
ENV NUITKA_CACHE_DIR=/tmp/nuitka-cache
# Builder stage: install build tooling, Python deps and optional binary modules
FROM base AS builder
ENV CC=gcc \
CXX=g++ \
NUITKA_CACHE_DIR=/tmp/nuitka-cache
# 安装系统依赖包括Playwright浏览器依赖
RUN apt-get update && \
apt-get install -y --no-install-recommends \
# 基础工具
nodejs \
npm \
tzdata \
curl \
ca-certificates \
# 编译工具Nuitka需要
build-essential \
gcc \
g++ \
ccache \
patchelf \
curl \
ca-certificates \
&& apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
RUN python -m venv /opt/venv && \
/opt/venv/bin/pip install --no-cache-dir --upgrade pip
ENV VIRTUAL_ENV=/opt/venv
ENV PATH="$VIRTUAL_ENV/bin:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin"
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
RUN if [ -f "utils/xianyu_slider_stealth.py" ]; then \
echo "===================================="; \
echo "检测到 xianyu_slider_stealth.py"; \
echo "开始编译为二进制模块..."; \
echo "===================================="; \
pip install --no-cache-dir nuitka ordered-set zstandard && \
python build_binary_module.py; \
BUILD_RESULT=$?; \
if [ $BUILD_RESULT -eq 0 ]; then \
echo "===================================="; \
echo "✓ 二进制模块编译成功"; \
echo "===================================="; \
ls -lh utils/xianyu_slider_stealth.* 2>/dev/null || true; \
else \
echo "===================================="; \
echo "✗ 二进制模块编译失败 (错误码: $BUILD_RESULT)"; \
echo "将继续使用 Python 源代码版本"; \
echo "===================================="; \
fi; \
pip uninstall -y nuitka ordered-set zstandard >/dev/null 2>&1 || true; \
rm -rf /tmp/nuitka-cache utils/xianyu_slider_stealth.build utils/xianyu_slider_stealth.dist; \
else \
echo "===================================="; \
echo "未检测到 xianyu_slider_stealth.py"; \
echo "跳过二进制编译"; \
echo "===================================="; \
fi
# Runtime stage: only keep what is needed to run the app
FROM base AS runtime
LABEL maintainer="zhinianboke" \
version="2.2.0" \
description="闲鱼自动回复系统 - 企业级多用户版本,支持自动发货和免拼发货" \
repository="https://github.com/zhinianboke/xianyu-auto-reply" \
license="仅供学习使用,禁止商业用途" \
author="zhinianboke" \
build-date="" \
vcs-ref=""
ENV NODE_PATH=/usr/lib/node_modules
RUN apt-get update && \
apt-get install -y --no-install-recommends \
nodejs \
npm \
tzdata \
curl \
ca-certificates \
# 图像处理依赖
libjpeg-dev \
libpng-dev \
@ -77,78 +125,30 @@ RUN apt-get update && \
# OpenCV运行时依赖
libgl1 \
libglib2.0-0 \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* \
&& rm -rf /tmp/* \
&& rm -rf /var/tmp/*
&& apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# 设置时区
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 验证Node.js安装并设置环境变量
RUN node --version && npm --version
ENV NODE_PATH=/usr/lib/node_modules
# 复制requirements.txt并安装Python依赖
COPY requirements.txt .
RUN pip install --no-cache-dir --upgrade pip && \
pip install --no-cache-dir -r requirements.txt
COPY --from=builder /opt/venv /opt/venv
COPY --from=builder /app /app
ENV VIRTUAL_ENV=/opt/venv
ENV PATH="$VIRTUAL_ENV/bin:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin"
# 复制项目文件
COPY . .
# 条件执行:如果 xianyu_slider_stealth.py 存在,则编译为二进制模块
RUN if [ -f "utils/xianyu_slider_stealth.py" ]; then \
echo "===================================="; \
echo "检测到 xianyu_slider_stealth.py"; \
echo "开始编译为二进制模块..."; \
echo "===================================="; \
pip install --no-cache-dir nuitka ordered-set zstandard && \
python build_binary_module.py; \
BUILD_RESULT=$?; \
if [ $BUILD_RESULT -eq 0 ]; then \
echo "===================================="; \
echo "✓ 二进制模块编译成功"; \
echo "===================================="; \
ls -lh utils/xianyu_slider_stealth.* 2>/dev/null || true; \
else \
echo "===================================="; \
echo "✗ 二进制模块编译失败 (错误码: $BUILD_RESULT)"; \
echo "将继续使用 Python 源代码版本"; \
echo "===================================="; \
fi; \
rm -rf /tmp/nuitka-cache utils/xianyu_slider_stealth.build utils/xianyu_slider_stealth.dist; \
else \
echo "===================================="; \
echo "未检测到 xianyu_slider_stealth.py"; \
echo "跳过二进制编译"; \
echo "===================================="; \
fi
# 安装Playwright浏览器必须在复制项目文件之后
RUN playwright install chromium && \
playwright install-deps chromium
# 创建必要的目录并设置权限
RUN mkdir -p /app/logs /app/data /app/backups /app/static/uploads/images && \
chmod 777 /app/logs /app/data /app/backups /app/static/uploads /app/static/uploads/images
# 配置系统限制防止core文件生成
RUN echo "ulimit -c 0" >> /etc/profile
# 注意: 为了简化权限问题使用root用户运行
# 在生产环境中,建议配置适当的用户映射
# 暴露端口
EXPOSE 8080
# 健康检查
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8080/health || exit 1
# 复制启动脚本
COPY entrypoint.sh /app/entrypoint.sh
RUN chmod +x /app/entrypoint.sh
# 启动命令
CMD ["/app/entrypoint.sh"]
CMD ["/app/entrypoint.sh"]

View File

@ -1,33 +1,97 @@
# 使用Python 3.11作为基础镜像
FROM python:3.11-slim-bookworm
# syntax=docker/dockerfile:1
# 设置标签信息
LABEL maintainer="zhinianboke"
LABEL version="2.1.0"
LABEL description="闲鱼自动回复系统 - 企业级多用户版本,支持自动发货和免拼发货"
LABEL repository="https://github.com/zhinianboke/xianyu-auto-reply"
LABEL license="仅供学习使用,禁止商业用途"
LABEL author="zhinianboke"
LABEL build-date=""
LABEL vcs-ref=""
# Base stage with shared env config and mirror switch
FROM python:3.11-slim-bookworm AS base
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
TZ=Asia/Shanghai \
DOCKER_ENV=true \
PLAYWRIGHT_BROWSERS_PATH=/ms-playwright
# 设置工作目录
WORKDIR /app
# 设置环境变量
ENV PYTHONUNBUFFERED=1
ENV PYTHONDONTWRITEBYTECODE=1
ENV TZ=Asia/Shanghai
ENV DOCKER_ENV=true
ENV PLAYWRIGHT_BROWSERS_PATH=/ms-playwright
# 更换中科大源(兼容不同基础镜像)
RUN if [ -f /etc/apt/sources.list.d/debian.sources ]; then \
sed -i 's/deb.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list.d/debian.sources; \
fi && \
if [ -f /etc/apt/sources.list ]; then \
sed -i 's/deb.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list; \
fi
#更换中科大源
RUN sed -i 's/deb.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list.d/debian.sources
# Builder stage
FROM base AS builder
ENV CC=gcc \
CXX=g++ \
NUITKA_CACHE_DIR=/tmp/nuitka-cache \
PIP_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple
RUN apt-get update && \
apt-get install -y --no-install-recommends \
build-essential \
gcc \
g++ \
ccache \
patchelf \
curl \
ca-certificates \
&& apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
RUN python -m venv /opt/venv && \
/opt/venv/bin/pip install --no-cache-dir --upgrade pip
ENV VIRTUAL_ENV=/opt/venv
ENV PATH="$VIRTUAL_ENV/bin:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin"
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
RUN if [ -f "utils/xianyu_slider_stealth.py" ]; then \
echo "===================================="; \
echo "检测到 xianyu_slider_stealth.py"; \
echo "开始编译为二进制模块..."; \
echo "===================================="; \
pip install --no-cache-dir nuitka ordered-set zstandard && \
python build_binary_module.py; \
BUILD_RESULT=$?; \
if [ $BUILD_RESULT -eq 0 ]; then \
echo "===================================="; \
echo "✓ 二进制模块编译成功"; \
echo "===================================="; \
ls -lh utils/xianyu_slider_stealth.* 2>/dev/null || true; \
else \
echo "===================================="; \
echo "✗ 二进制模块编译失败 (错误码: $BUILD_RESULT)"; \
echo "将继续使用 Python 源代码版本"; \
echo "===================================="; \
fi; \
pip uninstall -y nuitka ordered-set zstandard >/dev/null 2>&1 || true; \
rm -rf /tmp/nuitka-cache utils/xianyu_slider_stealth.build utils/xianyu_slider_stealth.dist; \
else \
echo "===================================="; \
echo "未检测到 xianyu_slider_stealth.py"; \
echo "跳过二进制编译"; \
echo "===================================="; \
fi
# Runtime stage
FROM base AS runtime
LABEL maintainer="zhinianboke" \
version="2.1.0" \
description="闲鱼自动回复系统 - 企业级多用户版本,支持自动发货和免拼发货" \
repository="https://github.com/zhinianboke/xianyu-auto-reply" \
license="仅供学习使用,禁止商业用途" \
author="zhinianboke" \
build-date="" \
vcs-ref=""
ENV NODE_PATH=/usr/lib/node_modules
# 安装系统依赖包括Playwright浏览器依赖
RUN apt-get update && \
apt-get install -y --no-install-recommends \
# 基础工具
nodejs \
npm \
tzdata \
@ -70,50 +134,30 @@ RUN apt-get update && \
# OpenCV运行时依赖
libgl1 \
libglib2.0-0 \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* \
&& rm -rf /tmp/* \
&& rm -rf /var/tmp/*
&& apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# 设置时区
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 验证Node.js安装并设置环境变量
RUN node --version && npm --version
ENV NODE_PATH=/usr/lib/node_modules
# 复制requirements.txt并安装Python依赖
COPY requirements.txt .
RUN pip install --no-cache-dir --upgrade pip -i https://pypi.tuna.tsinghua.edu.cn/simple&& \
pip install --no-cache-dir -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
COPY --from=builder /opt/venv /opt/venv
COPY --from=builder /app /app
ENV VIRTUAL_ENV=/opt/venv
ENV PATH="$VIRTUAL_ENV/bin:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin"
# 复制项目文件
COPY . .
# 安装Playwright浏览器必须在复制项目文件之后
RUN playwright install chromium && \
playwright install-deps chromium
# 创建必要的目录并设置权限
RUN mkdir -p /app/logs /app/data /app/backups /app/static/uploads/images && \
chmod 777 /app/logs /app/data /app/backups /app/static/uploads /app/static/uploads/images
# 配置系统限制防止core文件生成
RUN echo "ulimit -c 0" >> /etc/profile
# 注意: 为了简化权限问题使用root用户运行
# 在生产环境中,建议配置适当的用户映射
# 暴露端口
EXPOSE 8080
# 健康检查
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8080/health || exit 1
# 复制启动脚本
COPY entrypoint.sh /app/entrypoint.sh
RUN chmod +x /app/entrypoint.sh
# 启动命令
CMD ["/app/entrypoint.sh"]