如何使用多阶段构建减小 python (docker) 图像大小?
How do I reduce a python (docker) image size using a multi-stage build?
我正在寻找一种使用 python 和 Dockerfile 创建多阶段构建的方法:
例如,使用下面的图片:
第一张图片:安装所有编译时要求,并安装所有需要的python模块
第二张图片:将所有 compiled/built 包从第一张图片复制到第二张图片,没有编译器本身(gcc、postgers-dev、python -dev 等..)
最后objective是要小一点的图,运行python和我需要的python包
简而言之:我如何'wrap' 在第一个图像中创建的所有已编译模块(站点包/外部库),以及以'clean'方式复制它们,到第二张图片。
关于此的文档详细解释了如何执行此操作。
https://docs.docker.com/engine/userguide/eng-image/multistage-build/#before-multi-stage-builds
基本上你完全按照你说的去做。多阶段构建功能的神奇之处在于,您可以从一个 dockerfile 中完成所有这些工作。
即:
FROM golang:1.7.3
WORKDIR /go/src/github.com/alexellis/href-counter/
RUN go get -d -v golang.org/x/net/html
COPY app.go .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=0 /go/src/github.com/alexellis/href-counter/app .
CMD ["./app"]
这会构建一个 go 二进制文件,然后下一个图像 运行 是二进制文件。第一张图片包含所有构建工具,第二张图片只是一个基础 linux 机器,可以 运行 二进制文件。
好的,所以我的解决方案是使用 wheel,它允许我们在第一个图像上编译,为所有依赖项创建 wheel 文件并将它们安装在第二个图像中,而无需安装编译器
FROM python:2.7-alpine as base
RUN mkdir /svc
COPY . /svc
WORKDIR /svc
RUN apk add --update \
postgresql-dev \
gcc \
musl-dev \
linux-headers
RUN pip install wheel && pip wheel . --wheel-dir=/svc/wheels
FROM python:2.7-alpine
COPY --from=base /svc /svc
WORKDIR /svc
RUN pip install --no-index --find-links=/svc/wheels -r requirements.txt
您可以在以下博客中看到我对此的回答 post
https://www.blogfoobar.com/post/2018/02/10/python-and-docker-multistage-build
我推荐 this article(第 2 部分)中详述的方法。他使用 virtualenv,因此 pip install 将所有 python 代码、二进制文件等存储在一个文件夹下,而不是分散在整个文件系统中。然后很容易将那个文件夹复制到最终的 "production" 图像。总结:
编译镜像
- 在您选择的某个路径中激活 virtualenv。
- 将该路径添加到您的 docker ENV。这就是 virtualenv 需要为所有未来 docker 运行 和 CMD 操作运行的全部功能。
- 像往常一样安装系统开发包和
pip install xyz
。
生产图片
- 从编译映像复制 virtualenv 文件夹。
- 将 virtualenv 文件夹添加到 docker 的路径
这是在 Docker 中使用 Python 虚拟环境的地方。复制虚拟环境通常很棘手,因为它需要在完全相同的 Python 构建上使用完全相同的文件系统路径,但在 Docker 中你可以保证这一点。
(这与@mpoisot 在 中描述的基本配方相同,它也出现在其他 SO 答案中。)
假设您正在安装 psycopg PostgreSQL client library. The extended form of this requires the Python C development library plus the PostgreSQL C client library headers; but to run it you only need the PostgreSQL C runtime library. So here you can use a multi-stage build:第一阶段使用完整的 C 工具链安装虚拟环境,最后阶段复制构建的虚拟环境,但仅包含所需的最少库。
典型的 Docker 文件可能如下所示:
# 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 entry point script,那么您可以在第一阶段执行所有操作:RUN pip install .
会将应用程序复制到虚拟环境中,并在 /venv/bin
中为你。在最后阶段,您不需要再次 COPY
申请。设置CMD
到运行虚拟环境外的wrapper脚本,这已经是前面的$PATH
.
再次请注意,此方法之所以有效,是因为它在两个阶段都是相同的 Python 基础映像,并且虚拟环境位于完全相同的路径上。如果是不同的 Python 或不同的容器路径,移植的虚拟环境可能无法正常工作。
我正在寻找一种使用 python 和 Dockerfile 创建多阶段构建的方法:
例如,使用下面的图片:
第一张图片:安装所有编译时要求,并安装所有需要的python模块
第二张图片:将所有 compiled/built 包从第一张图片复制到第二张图片,没有编译器本身(gcc、postgers-dev、python -dev 等..)
最后objective是要小一点的图,运行python和我需要的python包
简而言之:我如何'wrap' 在第一个图像中创建的所有已编译模块(站点包/外部库),以及以'clean'方式复制它们,到第二张图片。
关于此的文档详细解释了如何执行此操作。
https://docs.docker.com/engine/userguide/eng-image/multistage-build/#before-multi-stage-builds
基本上你完全按照你说的去做。多阶段构建功能的神奇之处在于,您可以从一个 dockerfile 中完成所有这些工作。
即:
FROM golang:1.7.3
WORKDIR /go/src/github.com/alexellis/href-counter/
RUN go get -d -v golang.org/x/net/html
COPY app.go .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=0 /go/src/github.com/alexellis/href-counter/app .
CMD ["./app"]
这会构建一个 go 二进制文件,然后下一个图像 运行 是二进制文件。第一张图片包含所有构建工具,第二张图片只是一个基础 linux 机器,可以 运行 二进制文件。
好的,所以我的解决方案是使用 wheel,它允许我们在第一个图像上编译,为所有依赖项创建 wheel 文件并将它们安装在第二个图像中,而无需安装编译器
FROM python:2.7-alpine as base
RUN mkdir /svc
COPY . /svc
WORKDIR /svc
RUN apk add --update \
postgresql-dev \
gcc \
musl-dev \
linux-headers
RUN pip install wheel && pip wheel . --wheel-dir=/svc/wheels
FROM python:2.7-alpine
COPY --from=base /svc /svc
WORKDIR /svc
RUN pip install --no-index --find-links=/svc/wheels -r requirements.txt
您可以在以下博客中看到我对此的回答 post
https://www.blogfoobar.com/post/2018/02/10/python-and-docker-multistage-build
我推荐 this article(第 2 部分)中详述的方法。他使用 virtualenv,因此 pip install 将所有 python 代码、二进制文件等存储在一个文件夹下,而不是分散在整个文件系统中。然后很容易将那个文件夹复制到最终的 "production" 图像。总结:
编译镜像
- 在您选择的某个路径中激活 virtualenv。
- 将该路径添加到您的 docker ENV。这就是 virtualenv 需要为所有未来 docker 运行 和 CMD 操作运行的全部功能。
- 像往常一样安装系统开发包和
pip install xyz
。
生产图片
- 从编译映像复制 virtualenv 文件夹。
- 将 virtualenv 文件夹添加到 docker 的路径
这是在 Docker 中使用 Python 虚拟环境的地方。复制虚拟环境通常很棘手,因为它需要在完全相同的 Python 构建上使用完全相同的文件系统路径,但在 Docker 中你可以保证这一点。
(这与@mpoisot 在
假设您正在安装 psycopg PostgreSQL client library. The extended form of this requires the Python C development library plus the PostgreSQL C client library headers; but to run it you only need the PostgreSQL C runtime library. So here you can use a multi-stage build:第一阶段使用完整的 C 工具链安装虚拟环境,最后阶段复制构建的虚拟环境,但仅包含所需的最少库。
典型的 Docker 文件可能如下所示:
# 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 entry point script,那么您可以在第一阶段执行所有操作:RUN pip install .
会将应用程序复制到虚拟环境中,并在 /venv/bin
中为你。在最后阶段,您不需要再次 COPY
申请。设置CMD
到运行虚拟环境外的wrapper脚本,这已经是前面的$PATH
.
再次请注意,此方法之所以有效,是因为它在两个阶段都是相同的 Python 基础映像,并且虚拟环境位于完全相同的路径上。如果是不同的 Python 或不同的容器路径,移植的虚拟环境可能无法正常工作。