探索Docker,第4部分:减小映像大小并加速其组装

在Docker系列翻译的这一部分中,我们将讨论如何优化图像大小并加快组装速度。 在过去的材料中,我们将Docker图像与比萨饼进行了比较,术语与甜甜圈进行了比较,并将Dockerfile指令与百吉饼进行了比较。 今天不会烘烤。 是时候节食了。

第1部分:基础知识
第2部分:术语和概念
第3部分:Dockerfile文件
第4部分:缩小图像尺寸并加快其组装速度
第5部分:团队
第6部分:处理数据


为了理解我们在这里要谈论的内容,对您重新记忆本系列第三部分中讨论的内容将很有用。 即,我们在那里谈论了Dockerfile文件指令。 了解这些说明以及我们今天讨论的Docker功能,将帮助您优化Docker映像文件。

快取


Docker的优势之一就是缓存。 由于这种机制,图像的组装得以加速。

组装Docker映像时,它遵循Dockerfile的说明,并按顺序进行。 在分析指令的过程中,Docker检查其自身的缓存中是否有图像,这是我们在组装其他图像的中间阶段所得到的。 如果可以找到此类图像,则系统可以使用它们而不会浪费时间重新创建它们。

如果缓存无效,则会执行发生缓存的指令,从而在不使用缓存的情况下创建新层。 执行其后的指令时,也会发生相同的情况。

结果,如果在执行来自Dockerfile的指令期间发现基本映像在缓存中,则使用该缓存中的映像。 这称为缓存命中。 如果基本映像不在缓存中,则将在不使用缓存的情况下进行映像组装的整个过程。

然后,将以下指令与来自缓存的所有图像进行比较,这些图像基于已在缓存中找到的相同基本图像。 检查每个缓存的中间映像,以查看其是否包含由同一指令创建的映像。 如果找不到匹配项,则称为“缓存未命中”,并且认为缓存无效。 在处理完整个Dockerfile之前,都会发生同样的事情。

大多数新指令都只是与中间映像中已有的指令进行了比较。 如果系统设法找到匹配项,则程序集将使用缓存中已存在的内容。

使用缓存可以加快图像的组装速度,但是存在一个问题。 例如,如果在Dockerfile中找到RUN pip install -r requirements.txt指令,则Docker在其中间映像的本地缓存中搜索相同的指令。 但是,未比较requirements.txt文件的旧版本和新版本的内容。

如果将有关新软件包的信息添加到requirements.txt ,则可能导致问题,此后,在构建更新的映像时,为了安装一组新软件包,您需要再次运行RUN pip install语句。 很快我们将讨论如何处理这个问题。

与其他Docker指令不同,在执行ADDCOPY指令时,Docker需要检查一个或多个文件的内容,以确定在创建映像时是否可以使用缓存。 即,将这些指令中提到的文件的校验和与已经在缓存中的中间映像中的文件的校验和进行比较。 如果文件的内容或其元数据已更改,则缓存无效。

以下是利用Docker缓存的一些技巧:

  • 可以通过将--no-cache=True开关传递给docker build来禁用--no-cache=True
  • 如果您打算对Dockerfile指令进行更改,那么由更改后的指令创建的每一层都将很频繁地重新组装,而无需使用缓存。 要利用缓存,请将可能发生更改的指令尽可能靠近Dockerfile的末尾放置。
  • RUN apt-get update命令RUN apt-get updateapt-get install链式组合在一起,以避免与缓存使用不当相关的问题。
  • 如果您将包管理器(如pip )与pip文件一起使用,则请遵循以下方案,以从缓存中排除使用过时的中间映像,该映像包含旧版本的requirements.txt文件中列出的一组包。 看起来是这样的:

     COPY requirements.txt /tmp/ RUN pip install -r /tmp/requirements.txt COPY . /tmp/ 

如果您知道其他解决“ requirements.txt问题”的方法,则可以在注释中说明。

缩小图像尺寸


▍仔细选择基本图像


Docker映像可能很大。 这与创建它们的人的根基化的要求相矛盾,即使它们尽可能紧凑,这将有利于它们从远程存储库中下载,并将对加载它们的计算机上的可用空间量产生有益的影响。 让我们谈谈如何减小它们的大小。


现在,我们将吃蔬菜而不是百吉饼和甜甜圈

减小图像尺寸的一种方法是仔细选择基本图像及其后续调整。

例如,基本的Alpine映像是类似Linux的OS的完整发行版,其中包含最少的其他软件包。 它的大小约为5兆字节。 但是,基于Alpine构建自己的映像将需要大量时间来为其配备必要的一切,以确保特定应用程序的运行。

也有基本Alpine图片的专用版本。 例如,包装了print("hello world")脚本的python存储库中的相应图像重约78.5 MB。 这是用于构建此类映像的Dockerfile:

 FROM python:3.7.2-alpine3.8 COPY . /app ENTRYPOINT ["python", "./app/my_script.py", "my_var"] 

同时,Docker Hub表示该基本映像的大小为29 MB。 通过下载和安装Python,可以增加基于该基本映像的映像大小。

除了使用基于Alpine的基本图像之外,您还可以通过使用多阶段装配技术来减小图像的大小。

▍多阶段图像组装


描述映像的多阶段组装的Dockerfile使用了一些FROM指令。 此类映像的创建者可以设置称为构建工件的文件从一个构建级别到另一构建级别的选择性复制。 同时,有可能摆脱完成图像中不需要的所有内容。 由于采用了这种方法,您可以减小完成图像的尺寸。

以下是每个FROM语句的工作方式:

  • 她开始新的构建步骤。
  • 它不取决于上一个构建步骤中创建的内容。
  • 她可以使用与上一步使用的基本图像不同的基本图像。

这是Docker 文档中 Dockerfile的修改示例,描述了多阶段构建。

 FROM golang:1.7.3 AS build 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=build /go/src/github.com/alexellis/href-counter/app . CMD ["./app"] 

请注意,我们给出了程序集第一阶段的名称,在FROM语句之后指定了该名称。 我们在Dockerfile中的COPY --from= --from COPY --from=中引用了命名的构建阶段。

在某些情况下,必须为生产环境创建多个容器时,使用多阶段图像组装过程才有意义。 多级装配使您可以最小化最终图像的尺寸。 但是有时这种方法会使图像的支持复杂化。 因此,在没有图像的情况下,您可能不会使用图像的多阶段组装。 您可以在这里这里阅读有关此技术的功能。

如您所见,多阶段装配是一项有趣的技术,但它并不适合所有情况。 绝对会推荐给我们,下面将讨论减少图像大小的相同方法。

▍.dockerignore文件


绝对每个想要学习Docker的人都需要了解.dockerignore文件。 这些文件类似于.gitignore文件。 它们包含文件和文件夹的列表,形式为Docker在映像组装期间应忽略的名称或模板。

该文件放置在Dockerfile所在的位置,以及映像程序集上下文中包含的所有其他内容。

当您运行docker build以启动映像的组装时,Docker会检查文件夹中是否存在.dockerignore文件。 如果可以找到这样的文件,则将对此文件进行解析,并使用文件filepath Go包Match()函数的规则以及它自己的某些Docker 规则来确定要忽略的文件列表。

因此,例如,如果在.dockerignore文件中找到了*.jpg格式的模板,则在创建映像时,将忽略具有任何名称和扩展名.jpg文件。 如果字符串videos在文件中,则系统将忽略videos文件夹及其所有内容。

编译.dockerignore文件时,可以使用#符号对其进行注释。

这是.dockerignore文件提供给创建Docker映像的任何人的内容:

  • 这使您可以从图像文件中排除包含敏感信息(例如登录名和密码)的文件。
  • 这样可以减小图像的尺寸。 图像中的文件越小,其大小将越小,并且可以更快地使用它。
  • 这使得可以减少在组装相似图像时使高速缓存无效的原因的数量。 例如,如果在映像的重组期间项目的某些服务文件(例如日志文件)发生更改,因此,实际上由于不合理地使缓存中存储的数据无效,则这会减慢映像的组装速度。

.dockerignore可以在Docker 文档中阅读有关.dockerignore文件的更多信息。

图像尺寸研究


让我们谈谈如何使用命令行工具找出Docker映像和容器的大小。

  • 为了找出正在运行的容器的大致大小,可以使用docker container ls -s形式的命令。
  • docker image ls显示docker image ls大小。
  • 您可以使用docker image history my_image:my_tag查找从中组合特定映像的中间映像的大小。
  • docker image inspect my_image:tag可让您查找有关图像的详细信息,包括其每个层的大小。 图层与构成最终图像的中间图像略有不同,但是在大多数情况下,它们可以被视为相同的实体。 这是有关Docker映像内部结构细节的一些很好的材料。
  • 为了检查容器中的物品 ,您可以安装潜水包。

既然我们已经讨论了减小图像尺寸的可能性,我提请您注意有关减小图像尺寸和加快组装速度的八项建议。

有关减少图像大小并加快组装过程的建议


  1. 尽可能将官方图像用作基本图像。 官方图片会定期更新,比非正式图片更安全。
  2. 为了尽可能收集紧凑的映像,请使用基于Alpine Linux的基本映像。
  3. 如果使用apt ,则将apt-get updateapt-get install命令合并在一个RUN语句中。 此外,将软件包安装命令合并为一条指令。 用多行字母顺序列出软件包,用\分隔列表。 例如,它可能看起来像这样:

     RUN apt-get update && apt-get install -y \   package-one \   package-two \   package-three && rm -rf /var/lib/apt/lists/* 

    此方法减少了应添加到图像的层数,并有助于将文件代码保持得体。
  4. 在用于安装软件包的RUN语句的末尾包含类似&& rm -rf /var/lib/apt/lists/*的结构。 这将清除apt缓存,并导致它不会保存在RUN命令形成的层中。 有关详细信息,请参见文档
  5. 通过在Dockerfile中放置很可能会在文件末尾更改的命令来明智地使用缓存功能。
  6. 使用.dockerignore文件。
  7. 看一下dive ,这是探索Docker映像的一个好工具,可帮助减小它们的大小。
  8. 不要安装可以免除的软件包。

总结


现在您知道了如何使Docker映像快速组装,从存储库快速加载并且不占用过多的计算机空间。 下次我们将讨论Docker团队。

亲爱的读者们! 在构建Docker映像时是否遇到缓存机制问题?

Source: https://habr.com/ru/post/zh-CN440658/


All Articles