简体   繁体   English

如何减少针对Python应用程序的此多阶段Docker构建的大小

[英]How to decrease the size of this multistage docker build for a python app

How do I avoid using /root/.cache here? 如何避免在这里使用/root/.cache? Not sure I understand how multistage builds work. 不知道我了解多阶段构建如何工作。

# ---- 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

Perhaps I should use a virtualenv? 也许我应该使用virtualenv?

Docker multi-stage builds work by creating multiple stages, with the aim that the final image will have the least required components Docker多阶段构建通过创建多个阶段来进行工作,目的是使最终映像具有最少所需的组件

In your case, you're re-using the initial build stage as the final image 就您而言,您将重新使用初始构建阶段作为最终映像

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

However, you are also removing the unwanted packages that were installed in the dependencies stage, negating the advantages of multi-stage image and hence you're not seeing any visible changes in size. 但是,您还将删除在依赖项阶段安装的不需要的软件包,从而消除了多阶段映像的优势,因此看不到任何可见的大小变化。

To give a demonstration, since you haven't posted your requirements.txt file, I'm going assume that it will install flask 为了进行演示,由于您尚未发布requirements.txt文件,因此我假设它将安装flask

λ cat requirements.txt
flask==1.0.2

Consider your Dockerfile, however, removing the commands that remove the packages 考虑您的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

Building the images: 构建图像:

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

Examine the size of the image: 检查图像的大小:

docker images

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

Let's modify the Dockerfile so that it uses the 'base' as the final image, but copies over the cached pip wheels from dependencies 让我们修改Dockerfile,使其使用“基本”作为最终映像,但从依赖项复制缓存的pip wheel

# ---- 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

Build the image 建立形象

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

With this, we get the image size as 60.5MB 这样,我们得到的图像大小为60.5MB

docker images 码头工人图像

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

However, we have only copied the cache files on the final image, we still need to install it and then the /root/.cache can be removed. 但是,我们仅将缓存文件复制到了最终映像上,我们仍然需要安装它,然后可以删除/root/.cache The Dockerfile will now look like: 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

Building the image: 建立图像:

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

Leading to a final image of 70MB 最终图像为70MB

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

Hope that makes things clear 希望事情说清楚

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM