这是在 Docker 中使用 Python 虚拟环境很有用的地方。复制虚拟环境通常很棘手,因为它需要在完全相同的 Python 版本上具有完全相同的文件系统路径,但在 Docker 中你可以保证这一点。
(这与@mpoisot 在他们的答案中描述的基本配方相同,它也出现在其他 SO 答案中。)
假设您正在安装psycopg PostgreSQL 客户端库。它的扩展形式需要 Python C 开发库加上 PostgreSQL C 客户端库头文件;但要运行它,您只需要 PostgreSQL C 运行时库。所以在这里你可以使用多阶段构建:第一阶段使用完整的 C 工具链安装虚拟环境,最后阶段复制构建的虚拟环境,但只包含最少的所需库。
典型的 Dockerfile 可能如下所示:
# Name the single Python image we're using everywhere.
ARG python=python:3.10-slim
# Build stage:
FROM ${python} AS build
# Install a full C toolchain and C build-time dependencies for
# everything we're going to need.
RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive \
apt-get install --no-install-recommends --assume-yes \
build-essential \
libpq-dev
# Create the virtual environment.
RUN python3 -m venv /venv
ENV PATH=/venv/bin:$PATH
# Install the Python library dependencies, including those with
# C extensions. They'll get installed into the virtual environment.
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
# Final stage:
FROM ${python}
# Install the runtime-only C library dependencies we need.
RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive \
apt-get install --no-install-recommends --assume-yes \
libpq5
# Copy the virtual environment from the first stage.
COPY --from=build /venv /venv
ENV PATH=/venv/bin:$PATH
# Copy the application in.
COPY . .
CMD ["./main.py"]
如果您的应用程序使用Python 入口点脚本,那么您可以在第一阶段执行所有操作:RUN pip install .
将应用程序复制到虚拟环境中并/venv/bin
为您创建一个包装脚本。在最后阶段,您不需要COPY
再次申请。设置CMD
以在虚拟环境之外运行包装脚本,该环境已经位于$PATH
.
再次注意,这种方法之所以有效,是因为它在两个阶段都是相同的 Python 基础映像,并且因为虚拟环境位于完全相同的路径上。如果是不同的 Python 或不同的容器路径,移植的虚拟环境可能无法正常工作。