如何每次创建最小的工作docker映像?


19

目的:每次创建最小的工作docker映像

当前

REPOSITORY          TAG       IMAGE ID            CREATED             SIZE
a-docker-image      latest    x                   42 minutes ago       1.92 GB

尝试

在Dockerfile的末尾添加一个清理步骤:

#clean
RUN apt-get purge -y wget
RUN rm -r a-build-dir
RUN apt-get purge -y a-package

缩小了图像尺寸:

REPOSITORY          TAG       IMAGE ID            CREATED             SIZE
a-docker-image      latest    y                   2 minutes ago       1.86 GB

讨论区

我建立了各种docker映像。每次尝试减小所创建图像的大小时,我总是觉得它太大。我正在寻找一个已经由github上的某个人创建的脚本,该脚本将从图像中删除所有多余的软件包,因此创建的图像的大小将尽可能小。

正如我所说的,我总是尝试减小图像的大小,但是我想应用一致的图像,以便从现在开始创建的每个图像都尽可能小。

如何每次创建最小的工作docker映像?

Answers:


1

涉及多种技术,没有一个解决方案。您可能需要执行以下几个操作:


首先,优化图像层以供重用。稍后在Dockerfile中进行频繁更改的步骤,以增加从早期构建中缓存早期层的机会。重用的层将在中显示为更多的磁盘空间docker image ls,但是如果您检查基础文件系统,则每层只有一个副本存储在磁盘上。这意味着3张图像,每张2 GB,但是在构建的最后几层中只有50 MB的差异,尽管清单表明它使用的是6 GB,但清单仅显示2.1 GB的磁盘空间。重复计算每个重用层。

层重用是为什么您看到具有不经常更改的构建依赖关系的映像的原因,因此请先安装映像,然后再复制代码。查看任何具有以下模式的python示例:

FROM python
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
# note how the code is copied only after the pip install
# since code changes but requirements.txt doesn't
COPY . .
CMD ["gunicorn", "app:app"]

选择一个最小的基本图像。这就是为什么您会看到人们ubuntu转向debian:slim(苗条的款式更小,使用的工具更少)或什至是的原因alpine。这减小了起点的大小,如果您不断拉动基础图像的新版本,这将非常有帮助。但是,如果基本映像很少更改,则层重用将消除最小化基本映像的许多优点。

您可以选择的最小基础映像是scratch,它什么也不是,没有外壳或库,仅对静态编译的二进制文件有用。否则,请选择一个包含所需工具的基础映像,而不需要大量不需要的工具。


接下来,任何更改或删除文件的步骤都应与创建该文件的先前步骤结合使用。否则,即使在更改文件权限等情况下也使用写时复制的分层文件系统将在上一层具有原始文件,并且在删除文件时图像大小不会缩小。这就是为什么您的rm命令对生成的磁盘空间没有影响的原因。相反,您可以链接命令,例如:

RUN apt-get update \
 && apt-get install -y \
      a-package \
      wget \
 && ... \
 && apt-get purge -y wget \
 && rm -r a-build-dir \
 && apt-get purge -y a-package

请注意,过度使用命令链会减慢您的构建速度,因为您需要在先决条件更改(例如,用wget提取代码)时重新安装同一工具集。请参阅下面的多阶段以获得更好的选择。


创建的文件中不需要的任何文件都应在创建该文件的步骤中删除。这包括程序包缓存,日志,手册页等。要发现每一层中正在创建什么文件,可以使用wagoodman / dive之类的工具(我没有亲自对其进行过审查,因此请谨慎使用,因为它可以完全root用户访问在您的主机上),或者您可以在不修剪中间容器的情况下构建docker映像,然后使用以下命令查看差异:

# first create and leave containers from any RUN step using options on build
docker image build --rm=false --no-cache -t image_name . 
# review which layers use an unexpectedly large amount of space
docker image history image_name
# list all containers, particularly the exited ones from above
docker container ps -a 
# examine any of those containers
docker container diff ${container_id} 
# ... repeat the diff for other build steps
# then cleanup exited containers
docker container prune

与每个中间的那些容器,该差异将显示文件被添加什么,改变,或在该步骤删除(这些与所指示的ACD之前的各文件名)。diff显示的是特定于容器的读/写文件系统,该文件系统是容器使用写时复制从映像状态更改的任何文件。


减小图像大小的最佳方法是从出厂的图像中消除任何不需要的组件,例如编译器。为此,多阶段构建使您可以在一个阶段进行编译,然后仅将生成的工件从构建阶段复制到运行时映像,该映像仅具有运行应用程序所需的最低要求。这避免了优化任何构建步骤的需要,因为它们不随结果映像一起提供。

FROM debian:9 as build
# still chain update with install to prevent stale cache issues
RUN apt-get update \
 && apt-get install -y \
      a-package \
      wget \
RUN ... # perform any download/compile steps

FROM debian:9-slim as release
COPY --from=build /usr/local/bin/app /usr/local/bin/app
CMD [ "/usr/local/bin/app" ]

多阶段是静态编译二进制文件的理想选择,您可以从头开始将其作为基本映像运行,也可以从JDK这样的编译环境过渡到JRE这样的运行时环境。这是在保持快速构建的同时显着减小图像大小的最简单方法。如果您具有更改或删除在先前步骤中创建的文件的步骤,则仍可以在发布阶段执行步骤的链接,但是在大多数情况下,COPY从另一个阶段将发布阶段与早期构建阶段经历的任何层膨胀隔离开来。


请注意,我不建议挤压图像,因为这会缩小一个图像的大小,但以消除图层重用为代价。这意味着以后构建同一映像将需要更多磁盘和网络流量来发送更新。回到第一个示例,压扁可能会将您的映像从2 GB减少到1 GB,但是3张映像可能不会占用3 GB而不是2.1 GB。


25

A Dockerfile为文件中的每个命令创建一个新层。由于各层都很好,因此可以彼此叠加 -您无法删除上一层添加的文件。这就是为什么在安装软件包,下载文件或在单独的命令中创建每个软件包的原因-即使在以后的层中将其删除,它们仍在映像中。

因此,如果您只是更改此设置:

RUN apt-get update -y
RUN apt-get install -y wget a-package
# ...
RUN apt-get purge -y wget
RUN rm -r a-build-dir
RUN apt-get purge -y a-package

对此:

RUN apt-get update -y \
    && apt-get install -y wget a-package \
    && mkdir a-build-dir \
    && wget http://some-site/very-big-source-code.tar.gz \
    && tar xzvf very-big-source-code.tar.gz \
    && do-some-compilation \
    && apt-get purge -y wget \
    && cd .. \
    && rm -rf a-build-dir \
    && apt-get purge -y a-package

您将获得更小的图像。


另一种选择是在构建图像后对其进行压缩问:新产品如何docker --squash运作?


另一个选择是选择苗条的基本图像。例如,以Alpine Linux为基础而不是Debian的映像仅占用10-15mb而不是180-250mb。这是在添加您自己的应用程序和数据之前。Docker Hub上的许多官方基础映像都具有高山版本。


3
2.37vs.1.47 GB
030

4

可能不完全是一个答案,但是值得给出替代方案。

考虑到这一点,就创建了Chef的栖息地,从而创建了一个具有所有必需依赖项的程序包,而没有多余的发行版/基础映像加载。

使用一个简单的nodejs应用程序从此博客文章中提取重要内容,即容器大小:

michael@ricardo-2:plans_pkg_part_2$ docker images
REPOSITORY           TAG                 IMAGE ID            CREATED             SIZE
mfdii/node-example   latest              36c6568c606b        40 minutes ago      655.9 MB
node                 latest              04c0ca2a8dad        16 hours ago        654.6 MB
mfdii/mytutorialapp  latest              534afd80d74d        2 minutes ago       182.1 MB

mdfii/node-example是来自经典dockerfile的docker映像,同时mfdii/mytutorialapp是使用栖息地生成的docker 映像。

如果规模是您的主要问题,并且您打算采用人居计划的学习曲线,那么这可能是您的解决方案。


0

一个人也可以潜水

docker run --rm -it \
    -v /var/run/docker.sock:/var/run/docker.sock \
    wagoodman/dive:latest <dive arguments...>

获取有关可以从docker映像中删除哪些垃圾以减小大小的报告。


0

如果您想拥有可重用的开发层,但是减少了磁盘的交付使用量,则可以生成一个合并的“交付层”,如下所示:

  1. 确保您有一个使用图像的容器(如果没有,请使用docker run IMAGE echoecho之类的东西,如果echo命令可用)
  2. 查找容器ID(也许使用docker container ls -l
  3. 管道docker exportdocker import创建合并的图层(类似docker export 20f192c6530a | docker import - project:merged

这将使您的开发层保持不变,但会为您提供一个较小的,可以交付的合并图像。



0

简单.. docker ps检查当前正在运行的图像..下面的简单文件示例..

来自ubuntu16

MAINTAINER sreeni(电子邮件/域)

运行apt更新

运行apt-get install -y nginx

ENTRYPOINT [“ / usr / sbin / nginx”,“-g”,“守护程序关闭;”]

展览80(港口)

简单的docker文件...

在docker命令下使用

docker run -d -p 80:80 --name Web服务器ubuntu16(图像名称)之后检查localhost或ip地址:80(打开浏览器并检查)


1
请修正答案的格式...
Pierre.Vriens
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.