Skip to main content
 首页 » 编程设计

python之如何减小 python 应用程序的多阶段 docker 构建的大小

2025年05月04日35傻小

如何避免在此处使用/root/.cache?不确定我是否了解多阶段构建的工作原理。

# ---- Base python ---- 
FROM python:2.7-alpine3.7 AS base 
# Create app directory 
WORKDIR /app 
 
# ---- Dependencies ---- 
FROM base AS dependencies 
COPY requirements.txt ./ 
RUN apk add --no-cache libgcc git build-base  && \ 
    pip install -r requirements.txt && \ 
    apk del git build-base binutils-libs binutils gmp isl libgomp libatomic pkgconf libgcc && \ 
    apk del mpfr3 mpc1 libstdc++ gcc musl-dev libc-dev g++ make fortify-headers ca-certificates libssh2 && \ 
    apk del libcurl expat pcre2 git && \ 
    pip uninstall -y mock PyMySQL coverage pytest pytest-cov pytest-xdist wheel setuptools && \ 
    rm -rf /usr/share/locale/* && \ 
    rm -rf /var/cache/debconf/*-old && \ 
    rm -rf /var/lib/apt/lists/* /var/lib/dpkg   && \ 
    rm -rf /usr/share/doc/* && \ 
    rm -rf /usr/share/man/?? && \ 
    rm -rf /usr/share/man/??_* 
 
# ---- Copy Files/Build ---- 
FROM dependencies AS build 
WORKDIR /app 
COPY . /app 
COPY --from=dependencies /root/.cache /root/.cache 
WORKDIR /app 

也许我应该使用 virtualenv?

请您参考如下方法:

Docker 多阶段构建通过创建多个阶段来工作,目标是最终镜像将具有最少的必需组件

在您的情况下,您将重新使用初始构建阶段作为最终图像

FROM python:2.7-alpine3.7 AS base 
.. 
FROM base AS dependencies 
.. 
FROM dependencies AS build 

但是,您也删除了在依赖阶段安装的不需要的包,否定了多阶段镜像的优势,因此您看不到任何可见的大小变化。

为了演示,由于您还没有发布您的 requirements.txt 文件,我假设它将安装 flask

λ cat requirements.txt 
flask==1.0.2 

然而,请考虑您的 Dockerfile,删除删除包的命令

# ---- Base python ---- 
FROM python:2.7-alpine3.7 AS base 
# Create app directory 
WORKDIR /app 
 
# ---- Dependencies ---- 
FROM base AS dependencies 
COPY requirements.txt ./ 
RUN apk add --no-cache libgcc git build-base  && \ 
    pip install -r requirements.txt 
 
# ---- Copy Files/Build ---- 
FROM dependencies AS build 
WORKDIR /app 
COPY . /app 
COPY --from=dependencies /root/.cache /root/.cache 
WORKDIR /app 

构建图像:

docker build -t so:51678830 . 
Sending build context to Docker daemon  3.072kB 
Step 1/10 : FROM python:2.7-alpine3.7 AS base 
 ---> b1d3c201a89a 
Step 2/10 : WORKDIR /app 
 ---> Using cache 
 ---> 675f27f73cf9 
Step 3/10 : FROM base AS dependencies 
 ---> 675f27f73cf9 
Step 4/10 : COPY requirements.txt ./ 
 ---> Using cache 
 ---> 288a87ba0ecf 
Step 5/10 : RUN apk add --no-cache libgcc git build-base  &&         pip install -r requirements.txt 
 ---> Running in 6520cfe93603 
fetch http://dl-cdn.alpinelinux.org/alpine/v3.7/main/x86_64/APKINDEX.tar.gz 
fetch http://dl-cdn.alpinelinux.org/alpine/v3.7/community/x86_64/APKINDEX.tar.gz 
(1/23) Installing binutils-libs (2.30-r1) 
(2/23) Installing binutils (2.30-r1) 
(3/23) Installing gmp (6.1.2-r1) 
(4/23) Installing isl (0.18-r0) 
(5/23) Installing libgomp (6.4.0-r5) 
(6/23) Installing libatomic (6.4.0-r5) 
(7/23) Installing pkgconf (1.3.10-r0) 
(8/23) Installing libgcc (6.4.0-r5) 
(9/23) Installing mpfr3 (3.1.5-r1) 
(10/23) Installing mpc1 (1.0.3-r1) 
(11/23) Installing libstdc++ (6.4.0-r5) 
(12/23) Installing gcc (6.4.0-r5) 
(13/23) Installing musl-dev (1.1.18-r3) 
(14/23) Installing libc-dev (0.7.1-r0) 
(15/23) Installing g++ (6.4.0-r5) 
(16/23) Installing make (4.2.1-r0) 
(17/23) Installing fortify-headers (0.9-r0) 
(18/23) Installing build-base (0.5-r0) 
(19/23) Installing libssh2 (1.8.0-r2) 
(20/23) Installing libcurl (7.61.0-r0) 
(21/23) Installing expat (2.2.5-r0) 
(22/23) Installing pcre2 (10.30-r0) 
(23/23) Installing git (2.15.2-r0) 
Executing busybox-1.27.2-r11.trigger 
OK: 186 MiB in 53 packages 
Collecting flask==1.0.2 (from -r requirements.txt (line 1)) 
  Downloading https://files.pythonhosted.org/packages/7f/e7/08578774ed4536d3242b14dacb4696386634607af824ea997202cd0edb4b/Flask-1.0.2-py2.py3-none-any.whl (91kB) 
Collecting Werkzeug>=0.14 (from flask==1.0.2->-r requirements.txt (line 1)) 
  Downloading https://files.pythonhosted.org/packages/20/c4/12e3e56473e52375aa29c4764e70d1b8f3efa6682bef8d0aae04fe335243/Werkzeug-0.14.1-py2.py3-none-any.whl (322kB) 
Collecting click>=5.1 (from flask==1.0.2->-r requirements.txt (line 1)) 
  Downloading https://files.pythonhosted.org/packages/34/c1/8806f99713ddb993c5366c362b2f908f18269f8d792aff1abfd700775a77/click-6.7-py2.py3-none-any.whl (71kB) 
Collecting itsdangerous>=0.24 (from flask==1.0.2->-r requirements.txt (line 1)) 
  Downloading https://files.pythonhosted.org/packages/dc/b4/a60bcdba945c00f6d608d8975131ab3f25b22f2bcfe1dab221165194b2d4/itsdangerous-0.24.tar.gz (46kB) 
Collecting Jinja2>=2.10 (from flask==1.0.2->-r requirements.txt (line 1)) 
  Downloading https://files.pythonhosted.org/packages/7f/ff/ae64bacdfc95f27a016a7bed8e8686763ba4d277a78ca76f32659220a731/Jinja2-2.10-py2.py3-none-any.whl (126kB) 
Collecting MarkupSafe>=0.23 (from Jinja2>=2.10->flask==1.0.2->-r requirements.txt (line 1)) 
  Downloading https://files.pythonhosted.org/packages/4d/de/32d741db316d8fdb7680822dd37001ef7a448255de9699ab4bfcbdf4172b/MarkupSafe-1.0.tar.gz 
Building wheels for collected packages: itsdangerous, MarkupSafe 
  Running setup.py bdist_wheel for itsdangerous: started 
  Running setup.py bdist_wheel for itsdangerous: finished with status 'done' 
  Stored in directory: /root/.cache/pip/wheels/2c/4a/61/5599631c1554768c6290b08c02c72d7317910374ca602ff1e5 
  Running setup.py bdist_wheel for MarkupSafe: started 
  Running setup.py bdist_wheel for MarkupSafe: finished with status 'done' 
  Stored in directory: /root/.cache/pip/wheels/33/56/20/ebe49a5c612fffe1c5a632146b16596f9e64676768661e4e46 
Successfully built itsdangerous MarkupSafe 
Installing collected packages: Werkzeug, click, itsdangerous, MarkupSafe, Jinja2, flask 
Successfully installed Jinja2-2.10 MarkupSafe-1.0 Werkzeug-0.14.1 click-6.7 flask-1.0.2 itsdangerous-0.24 
Removing intermediate container 6520cfe93603 
 ---> 6d73b486a703 
Step 6/10 : FROM dependencies AS build 
 ---> 6d73b486a703 
Step 7/10 : WORKDIR /app 
 ---> Running in 0ed8fa7f13e7 
Removing intermediate container 0ed8fa7f13e7 
 ---> e61cf72b31ae 
Step 8/10 : COPY . /app 
 ---> f6c7a4d3d8df 
Step 9/10 : COPY --from=dependencies /root/.cache /root/.cache 
 ---> 2c15e7080c91 
Step 10/10 : WORKDIR /app 
 ---> Running in 717bd7cf7b1d 
Removing intermediate container 717bd7cf7b1d 
 ---> cfe7ee0c5880 
Successfully built cfe7ee0c5880 
Successfully tagged so:51678830 

检查图像的大小:

docker images 
 
| REPOSITORY                    TAG                 IMAGE ID            CREATED              SIZE  | 
|--------------------------------------------------------------------------------------------------| 
| so                            51678830            4477dac77289        About a minute ago   234MB | 

让我们修改 Dockerfile,使其使用“基础”作为最终图像,但从依赖项中复制缓存的 pip wheels

# ---- Base python ---- 
FROM python:2.7-alpine3.7 AS base 
# Create app directory 
WORKDIR /app 
 
# ---- Dependencies ---- 
FROM base AS dependencies 
COPY requirements.txt ./ 
RUN apk add --no-cache libgcc git build-base  && \ 
    pip install -r requirements.txt 
 
# ---- Copy Files/Build ---- 
FROM base 
WORKDIR /app 
COPY . /app 
COPY --from=dependencies /root/.cache /root/.cache 
WORKDIR /app 

构建图像

docker build -t so:51678830 . 
Sending build context to Docker daemon  3.072kB 
Step 1/10 : FROM python:2.7-alpine3.7 AS base 
 ---> b1d3c201a89a 
Step 2/10 : WORKDIR /app 
 ---> Running in aca871ed01e3 
Removing intermediate container aca871ed01e3 
 ---> 89d357832427 
Step 3/10 : FROM base AS dependencies 
 ---> 89d357832427 
Step 4/10 : COPY requirements.txt ./ 
 ---> 6ecbfe862e27 
Step 5/10 : RUN apk add --no-cache libgcc git build-base  &&         pip install -r requirements.txt 
 ---> Running in 465256e75563 
fetch http://dl-cdn.alpinelinux.org/alpine/v3.7/main/x86_64/APKINDEX.tar.gz 
fetch http://dl-cdn.alpinelinux.org/alpine/v3.7/community/x86_64/APKINDEX.tar.gz 
(1/23) Installing binutils-libs (2.30-r1) 
(2/23) Installing binutils (2.30-r1) 
(3/23) Installing gmp (6.1.2-r1) 
(4/23) Installing isl (0.18-r0) 
(5/23) Installing libgomp (6.4.0-r5) 
(6/23) Installing libatomic (6.4.0-r5) 
(7/23) Installing pkgconf (1.3.10-r0) 
(8/23) Installing libgcc (6.4.0-r5) 
(9/23) Installing mpfr3 (3.1.5-r1) 
(10/23) Installing mpc1 (1.0.3-r1) 
(11/23) Installing libstdc++ (6.4.0-r5) 
(12/23) Installing gcc (6.4.0-r5) 
(13/23) Installing musl-dev (1.1.18-r3) 
(14/23) Installing libc-dev (0.7.1-r0) 
(15/23) Installing g++ (6.4.0-r5) 
(16/23) Installing make (4.2.1-r0) 
(17/23) Installing fortify-headers (0.9-r0) 
(18/23) Installing build-base (0.5-r0) 
(19/23) Installing libssh2 (1.8.0-r2) 
(20/23) Installing libcurl (7.61.0-r0) 
(21/23) Installing expat (2.2.5-r0) 
(22/23) Installing pcre2 (10.30-r0) 
(23/23) Installing git (2.15.2-r0) 
Executing busybox-1.27.2-r11.trigger 
OK: 186 MiB in 53 packages 
Collecting flask==1.0.2 (from -r requirements.txt (line 1)) 
  Downloading https://files.pythonhosted.org/packages/7f/e7/08578774ed4536d3242b14dacb4696386634607af824ea997202cd0edb4b/Flask-1.0.2-py2.py3-none-any.whl (91kB) 
Collecting Werkzeug>=0.14 (from flask==1.0.2->-r requirements.txt (line 1)) 
  Downloading https://files.pythonhosted.org/packages/20/c4/12e3e56473e52375aa29c4764e70d1b8f3efa6682bef8d0aae04fe335243/Werkzeug-0.14.1-py2.py3-none-any.whl (322kB) 
Collecting click>=5.1 (from flask==1.0.2->-r requirements.txt (line 1)) 
  Downloading https://files.pythonhosted.org/packages/34/c1/8806f99713ddb993c5366c362b2f908f18269f8d792aff1abfd700775a77/click-6.7-py2.py3-none-any.whl (71kB) 
Collecting itsdangerous>=0.24 (from flask==1.0.2->-r requirements.txt (line 1)) 
  Downloading https://files.pythonhosted.org/packages/dc/b4/a60bcdba945c00f6d608d8975131ab3f25b22f2bcfe1dab221165194b2d4/itsdangerous-0.24.tar.gz (46kB) 
Collecting Jinja2>=2.10 (from flask==1.0.2->-r requirements.txt (line 1)) 
  Downloading https://files.pythonhosted.org/packages/7f/ff/ae64bacdfc95f27a016a7bed8e8686763ba4d277a78ca76f32659220a731/Jinja2-2.10-py2.py3-none-any.whl (126kB) 
Collecting MarkupSafe>=0.23 (from Jinja2>=2.10->flask==1.0.2->-r requirements.txt (line 1)) 
  Downloading https://files.pythonhosted.org/packages/4d/de/32d741db316d8fdb7680822dd37001ef7a448255de9699ab4bfcbdf4172b/MarkupSafe-1.0.tar.gz 
Building wheels for collected packages: itsdangerous, MarkupSafe 
  Running setup.py bdist_wheel for itsdangerous: started 
  Running setup.py bdist_wheel for itsdangerous: finished with status 'done' 
  Stored in directory: /root/.cache/pip/wheels/2c/4a/61/5599631c1554768c6290b08c02c72d7317910374ca602ff1e5 
  Running setup.py bdist_wheel for MarkupSafe: started 
  Running setup.py bdist_wheel for MarkupSafe: finished with status 'done' 
  Stored in directory: /root/.cache/pip/wheels/33/56/20/ebe49a5c612fffe1c5a632146b16596f9e64676768661e4e46 
Successfully built itsdangerous MarkupSafe 
Installing collected packages: Werkzeug, click, itsdangerous, MarkupSafe, Jinja2, flask 
Successfully installed Jinja2-2.10 MarkupSafe-1.0 Werkzeug-0.14.1 click-6.7 flask-1.0.2 itsdangerous-0.24 
Removing intermediate container 465256e75563 
 ---> d9a23965de75 
Step 6/10 : FROM base 
 ---> 89d357832427 
Step 7/10 : WORKDIR /app 
 ---> Running in bb975f43890d 
Removing intermediate container bb975f43890d 
 ---> ba0d78774039 
Step 8/10 : COPY . /app 
 ---> 3510860b3538 
Step 9/10 : COPY --from=dependencies /root/.cache /root/.cache 
 ---> 812c65bd156b 
Step 10/10 : WORKDIR /app 
 ---> Running in 4191ef84468e 
Removing intermediate container 4191ef84468e 
 ---> 236d8ee0bea4 
Successfully built 236d8ee0bea4 
Successfully tagged so:51678830 

有了这个,我们得到的图像大小为 60.5MB

docker 图片

| REPOSITORY                    TAG                 IMAGE ID            CREATED              SIZE   | 
|---------------------------------------------------------------------------------------------------| 
| so                            51678830            e53282dc4fc7        2 seconds ago        60.5MB | 

但是,我们只是复制了最终图像上的缓存文件,我们仍然需要安装它,然后才能删除 /root/.cache。 Dockerfile 现在看起来像:

# ---- Base python ---- 
FROM python:2.7-alpine3.7 AS base 
# Create app directory 
WORKDIR /app 
 
# ---- Dependencies ---- 
FROM base AS dependencies 
COPY requirements.txt ./ 
RUN apk add --no-cache libgcc git build-base  && \ 
    pip install -r requirements.txt 
 
# ---- Copy Files/Build ---- 
FROM base 
WORKDIR /app 
COPY . /app 
COPY --from=dependencies /root/.cache /root/.cache 
COPY requirements.txt ./ 
RUN pip install -r requirements.txt && rm -rf /root/.cache 

构建图像:

docker build -t so:51678830 . 
 
 
Sending build context to Docker daemon  3.584kB 
Step 1/11 : FROM python:2.7-alpine3.7 AS base 
 ---> b1d3c201a89a 
Step 2/11 : WORKDIR /app 
 ---> Running in 8471e5fe8fac 
Removing intermediate container 8471e5fe8fac 
 ---> 646de3787bbc 
Step 3/11 : FROM base AS dependencies 
 ---> 646de3787bbc 
Step 4/11 : COPY requirements.txt ./ 
 ---> 4b6c6690ddf7 
Step 5/11 : RUN apk add --no-cache libgcc git build-base  &&         pip install -r requirements.txt 
 ---> Running in aaa83a183ead 
fetch http://dl-cdn.alpinelinux.org/alpine/v3.7/main/x86_64/APKINDEX.tar.gz 
fetch http://dl-cdn.alpinelinux.org/alpine/v3.7/community/x86_64/APKINDEX.tar.gz 
(1/23) Installing binutils-libs (2.30-r1) 
(2/23) Installing binutils (2.30-r1) 
(3/23) Installing gmp (6.1.2-r1) 
(4/23) Installing isl (0.18-r0) 
(5/23) Installing libgomp (6.4.0-r5) 
(6/23) Installing libatomic (6.4.0-r5) 
(7/23) Installing pkgconf (1.3.10-r0) 
(8/23) Installing libgcc (6.4.0-r5) 
(9/23) Installing mpfr3 (3.1.5-r1) 
(10/23) Installing mpc1 (1.0.3-r1) 
(11/23) Installing libstdc++ (6.4.0-r5) 
(12/23) Installing gcc (6.4.0-r5) 
(13/23) Installing musl-dev (1.1.18-r3) 
(14/23) Installing libc-dev (0.7.1-r0) 
(15/23) Installing g++ (6.4.0-r5) 
(16/23) Installing make (4.2.1-r0) 
(17/23) Installing fortify-headers (0.9-r0) 
(18/23) Installing build-base (0.5-r0) 
(19/23) Installing libssh2 (1.8.0-r2) 
(20/23) Installing libcurl (7.61.0-r0) 
(21/23) Installing expat (2.2.5-r0) 
(22/23) Installing pcre2 (10.30-r0) 
(23/23) Installing git (2.15.2-r0) 
Executing busybox-1.27.2-r11.trigger 
OK: 186 MiB in 53 packages 
Collecting flask==1.0.2 (from -r requirements.txt (line 1)) 
  Downloading https://files.pythonhosted.org/packages/7f/e7/08578774ed4536d3242b14dacb4696386634607af824ea997202cd0edb4b/Flask-1.0.2-py2.py3-none-any.whl (91kB) 
Collecting Werkzeug>=0.14 (from flask==1.0.2->-r requirements.txt (line 1)) 
  Downloading https://files.pythonhosted.org/packages/20/c4/12e3e56473e52375aa29c4764e70d1b8f3efa6682bef8d0aae04fe335243/Werkzeug-0.14.1-py2.py3-none-any.whl (322kB) 
Collecting click>=5.1 (from flask==1.0.2->-r requirements.txt (line 1)) 
  Downloading https://files.pythonhosted.org/packages/34/c1/8806f99713ddb993c5366c362b2f908f18269f8d792aff1abfd700775a77/click-6.7-py2.py3-none-any.whl (71kB) 
Collecting itsdangerous>=0.24 (from flask==1.0.2->-r requirements.txt (line 1)) 
  Downloading https://files.pythonhosted.org/packages/dc/b4/a60bcdba945c00f6d608d8975131ab3f25b22f2bcfe1dab221165194b2d4/itsdangerous-0.24.tar.gz (46kB) 
Collecting Jinja2>=2.10 (from flask==1.0.2->-r requirements.txt (line 1)) 
  Downloading https://files.pythonhosted.org/packages/7f/ff/ae64bacdfc95f27a016a7bed8e8686763ba4d277a78ca76f32659220a731/Jinja2-2.10-py2.py3-none-any.whl (126kB) 
Collecting MarkupSafe>=0.23 (from Jinja2>=2.10->flask==1.0.2->-r requirements.txt (line 1)) 
  Downloading https://files.pythonhosted.org/packages/4d/de/32d741db316d8fdb7680822dd37001ef7a448255de9699ab4bfcbdf4172b/MarkupSafe-1.0.tar.gz 
Building wheels for collected packages: itsdangerous, MarkupSafe 
  Running setup.py bdist_wheel for itsdangerous: started 
  Running setup.py bdist_wheel for itsdangerous: finished with status 'done' 
  Stored in directory: /root/.cache/pip/wheels/2c/4a/61/5599631c1554768c6290b08c02c72d7317910374ca602ff1e5 
  Running setup.py bdist_wheel for MarkupSafe: started 
  Running setup.py bdist_wheel for MarkupSafe: finished with status 'done' 
  Stored in directory: /root/.cache/pip/wheels/33/56/20/ebe49a5c612fffe1c5a632146b16596f9e64676768661e4e46 
Successfully built itsdangerous MarkupSafe 
Installing collected packages: Werkzeug, click, itsdangerous, MarkupSafe, Jinja2, flask 
Successfully installed Jinja2-2.10 MarkupSafe-1.0 Werkzeug-0.14.1 click-6.7 flask-1.0.2 itsdangerous-0.24 
Removing intermediate container aaa83a183ead 
 ---> eca67b911ca4 
Step 6/11 : FROM base 
 ---> 646de3787bbc 
Step 7/11 : WORKDIR /app 
 ---> Running in 0b81da90cc35 
Removing intermediate container 0b81da90cc35 
 ---> 17489d37a114 
Step 8/11 : COPY . /app 
 ---> 1f12ed2b9456 
Step 9/11 : COPY --from=dependencies /root/.cache /root/.cache 
 ---> 850bd5d693e3 
Step 10/11 : COPY requirements.txt ./ 
 ---> b508d7762e8e 
Step 11/11 : RUN pip install -r requirements.txt && rm -rf /root/.cache 
 ---> Running in 125afe6f16b0 
Collecting flask==1.0.2 (from -r requirements.txt (line 1)) 
  Using cached https://files.pythonhosted.org/packages/7f/e7/08578774ed4536d3242b14dacb4696386634607af824ea997202cd0edb4b/Flask-1.0.2-py2.py3-none-any.whl 
Collecting Werkzeug>=0.14 (from flask==1.0.2->-r requirements.txt (line 1)) 
  Using cached https://files.pythonhosted.org/packages/20/c4/12e3e56473e52375aa29c4764e70d1b8f3efa6682bef8d0aae04fe335243/Werkzeug-0.14.1-py2.py3-none-any.whl 
Collecting click>=5.1 (from flask==1.0.2->-r requirements.txt (line 1)) 
  Using cached https://files.pythonhosted.org/packages/34/c1/8806f99713ddb993c5366c362b2f908f18269f8d792aff1abfd700775a77/click-6.7-py2.py3-none-any.whl 
Collecting itsdangerous>=0.24 (from flask==1.0.2->-r requirements.txt (line 1)) 
Collecting Jinja2>=2.10 (from flask==1.0.2->-r requirements.txt (line 1)) 
  Using cached https://files.pythonhosted.org/packages/7f/ff/ae64bacdfc95f27a016a7bed8e8686763ba4d277a78ca76f32659220a731/Jinja2-2.10-py2.py3-none-any.whl 
Collecting MarkupSafe>=0.23 (from Jinja2>=2.10->flask==1.0.2->-r requirements.txt (line 1)) 
Installing collected packages: Werkzeug, click, itsdangerous, MarkupSafe, Jinja2, flask 
Successfully installed Jinja2-2.10 MarkupSafe-1.0 Werkzeug-0.14.1 click-6.7 flask-1.0.2 itsdangerous-0.24 
Removing intermediate container 125afe6f16b0 
 ---> d122f42fcb72 
Successfully built d122f42fcb72 
Successfully tagged so:51678830 

导致最终图像为 70MB

| REPOSITORY                    TAG                 IMAGE ID            CREATED             SIZE   | 
|--------------------------------------------------------------------------------------------------| 
| so                            51678830            d122f42fcb72        4 seconds ago       69.6MB | 

希望能把事情说清楚