如何使用单个Dockerfile适配Python项目开发与生产环境
单Dockerfile适配开发/生产多环境构建方案
完全不需要维护两份重复的Dockerfile,用Docker原生能力就能实现单文件按目标环境安装对应依赖,下面给两个可直接落地的方案,优先推荐第一个多阶段构建的方案。
方案一:多阶段构建(推荐)
这个方案是Docker官方推荐的多环境构建实践,生产镜像不会带入任何开发依赖,镜像体积、安全性和之前单独维护生产Dockerfile的效果完全一致,公共配置只需要写一次,不会出现配置不同步的问题。
改写后的完整Dockerfile如下:
# 所有环境共用的基础层,公共配置统一在这里维护 FROM python:3.9.11-slim AS base ENV PYTHONUNBUFFERED=1 RUN set -ex \ && RUN_DEPS=" \ libpcre3 \ mime-support \ " \ && seq 1 8 | xargs -I{} mkdir -p /usr/share/man/man{} \ && apt-get update && apt-get install -y --no-install-recommends $RUN_DEPS \ && python -m pip install --upgrade pip \ && rm -rf /var/lib/apt/lists/* WORKDIR /app/ # 生产环境依赖安装层 FROM base AS prod-deps COPY requirements.txt ./ RUN set -ex \ && BUILD_DEPS=" \ build-essential \ libpcre3-dev \ libpq-dev \ " \ && apt-get update && apt-get install -y --no-install-recommends $BUILD_DEPS \ && pip install --user -r requirements.txt \ && apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false $BUILD_DEPS \ && rm -rf /var/lib/apt/lists/* # 开发环境依赖安装层 FROM base AS dev-deps COPY requirements.txt requirements.dev.txt ./ RUN set -ex \ && BUILD_DEPS=" \ build-essential \ libpcre3-dev \ libpq-dev \ " \ && apt-get update && apt-get install -y --no-install-recommends $BUILD_DEPS \ && pip install --user -r requirements.dev.txt \ && apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false $BUILD_DEPS \ && rm -rf /var/lib/apt/lists/* # 最终生产镜像 FROM base AS prod COPY --from=prod-deps /root/.local /root/.local COPY ./src /app/ EXPOSE 8000 ENTRYPOINT ["/scripts/docker/entrypoint.sh"] # 最终开发镜像 FROM base AS dev COPY --from=dev-deps /root/.local /root/.local COPY ./src /app/ EXPOSE 8000 ENTRYPOINT ["/scripts/docker/entrypoint.sh"]
使用方式:
- 构建生产镜像:执行
docker build --target prod -t 你的镜像名:prod . - 构建开发镜像:执行
docker build --target dev -t 你的镜像名:dev .
如果后续开发环境需要额外装调试工具、命令行工具,直接在dev-deps或者dev阶段加安装逻辑即可,完全不会污染生产镜像。
方案二:ARG传参条件判断(改动量最小)
如果你不想调整原有单阶段Dockerfile的结构,只需要加几行代码,通过构建参数判断要安装的依赖即可,改造成本极低。
改写后的核心Dockerfile内容:
FROM python:3.9.11-slim ENV PYTHONUNBUFFERED=1 # 定义构建参数,默认构建生产环境 ARG APP_ENV=prod RUN set -ex \ && RUN_DEPS=" \ libpcre3 \ mime-support \ " \ && seq 1 8 | xargs -I{} mkdir -p /usr/share/man/man{} \ && apt-get update && apt-get install -y --no-install-recommends $RUN_DEPS \ && python -m pip install --upgrade pip \ && rm -rf /var/lib/apt/lists/* # 提前把两个依赖文件都拷贝进去,文件体积极小几乎不影响构建速度和镜像体积 COPY requirements.txt requirements.dev.txt ./ RUN set -ex \ && BUILD_DEPS=" \ build-essential \ libpcre3-dev \ libpq-dev \ " \ && apt-get update && apt-get install -y --no-install-recommends $BUILD_DEPS \ # 根据传入的环境参数选择依赖文件安装 && if [ "$APP_ENV" = "dev" ]; then pip install -r requirements.dev.txt; else pip install -r requirements.txt; fi \ && apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false $BUILD_DEPS \ && rm -rf /var/lib/apt/lists/* COPY ./src /app/ WORKDIR /app/ EXPOSE 8000 ENTRYPOINT ["/scripts/docker/entrypoint.sh"]
使用方式:
- 构建生产镜像:直接执行
docker build -t 你的镜像名:prod .,不需要额外传参 - 构建开发镜像:执行
docker build --build-arg APP_ENV=dev -t 你的镜像名:dev .
注意这个方案因为是单阶段构建,构建生产镜像时必须确保不传APP_ENV=dev参数,避免把开发依赖打包进生产镜像。
两个方案都能彻底解决双Dockerfile维护的问题,后续调整基础配置、启动命令、端口映射等公共逻辑,只需要改一次即可,不会再出现两边配置不一致的情况。
内容的提问来源于stack exchange,提问作者Anuj TBE
相关产品推荐
相关产品推荐

