电子游艺平台

首页 > 正文

你确定你会写 Dockerfile 吗?

www.agituss.com2019-07-20
塞班岛电子游艺网站

数以千计的Dockerfiles已经包含在GitHub存储库中,但并非所有Dockerfiles都是高效的。本文将以五种方式介绍Dockerfile的最佳实践,以帮助您编写更优雅的Dockerfiles。如果您是Docker的初学者,恭喜,本文适合您。后一系列将更加深入,敬请关注!

本文以基于Maven的Java项目为例,然后不断改进Dockerfile的编写风格,直到编写最优雅的Dockerfile为止。中间的所有步骤都是为了说明最佳实践的某些方面。

1.减少构建时间

开发周期包括构建Docker镜像,更改代码,然后重建Docker镜像。在构建映像的过程中,如果可以利用缓存,则可以减少不必要的重复构建步骤。

构建顺序会影响缓存的利用率

2b9d8525abc1494080b792384998f124

构建图像的顺序很重要。将文件添加到Dockerfile或修改其中一行时,缓存的一部分将失效,缓存的后续步骤将被中断,需要重建。因此,优化缓存的最佳方法是将不需要频繁更改的行和最常更改的行放到最后。

仅复制防止缓冲区溢出所需的文件

5403aa48912c4fafad44fac59ed8a822

将文件复制到映像时,请尝试仅复制所需的文件。切勿使用COPY命令复制整个目录。如果复制文件的内容已更改,则将销毁缓存。在上面的示例中,只需要在映像中构建构建的jar包,因此您只需要复制文件,这样即使更改了其他不相关的文件,更改也不会受到影响。

最小化可缓存的执行层

3ed8d226751749a094d0dbe4b9cd76fb

每个RUN指令都被视为可缓存的执行单元。太多的RUN指令会增加镜像中的层数并增加镜像卷。将所有命令放入相同的RUN指令将破坏缓存并延迟开发周期。使用软件包管理器安装软件时,软件索引信息通常在安装软件之前更新。建议将更新索引和安装软件放在相同的RUN指令中,以便可以形成可缓存的执行单元,否则可以安装旧的包。

2.减少镜像音量

图像的大小很重要,因为镜像越小,部署越快,攻击范围越小。

删除不必要的依赖

7c12401b84404102a3f87db5be721826

删除不必要的依赖项,不要安装调试工具。如果您确实需要调试工具,可以在容器运行后安装它。除了用户指定的包之外,一些包管理工具(例如apt)将安装推荐的包,这将无缘无故地增加图像的大小。 Apt可以通过添加参数-no-install-recommended确保不安装不需要的依赖项。如果您确实需要某些依赖项,请稍后手动添加它们。

删除包管理工具的缓存

279dfb524d5741a4b23bb923686c7271

包管理工具维护自己的缓存,该缓存保存在映像文件中。建议的方法是在每个RUN指令结束时删除缓存。如果在下一条指令中删除缓存,则不会减小图像的大小。

当然,还有其他更先进的方法可用于减少图像体积,如下面的多阶段构建中所述。接下来,我们将探讨如何优化Dockerfiles的可维护性,安全性和可重复性。

3.可维护性

尝试使用官方图片

8673f3f2dd5f48f2acb239f2ed927323

使用官方图像可以节省大量维护时间,因为官方图像的所有安装步骤都使用最佳实践。如果您有多个项目,则可以共享这些镜像层,因为它们都使用相同的基本图像。

使用更具体的标签

9377765524ad458bb7ee9d13b654c165

基本映像应尽量不使用最新的标记。虽然这很方便,但最新镜像可能会随着时间的推移发生显着变化因此,最好在Dockerfile中指定基本映像的特定标签。我们使用openjdk作为示例并指定标签8.请检查官方仓库以获取更多标签。

使用最小的基本图像

36d4333a1e314133b15c402b083a2a58

基本图像具有不同的标签样式,镜像体积将不同。细长风格的图像基于Debian发行版,而阿尔卑斯风格的图像基于较小的Alpine Linux发行版。一个明显的区别是Debian使用GNU项目实现的C语言标准库,而Alpine使用Musl C标准库,旨在取代嵌入式操作系统和移动设备的GNU C标准库(glibc)替代品。因此,在某些情况下使用Alpine会导致兼容性问题。以openjdk为例,jre风格的图像只包含Java运行时,不包含SDK。这也可以大大减小图像尺寸。

4.重复使用

到目前为止,我们一直假设您的jar包是在主机上构建的,这不是一个理想的解决方案,因为容器提供的一致性环境没有得到充分利用。例如,如果Java应用程序依赖于特定操作系统的库,则可能会出现问题,因为环境不一致(取决于构建jar包的机器)。

在一致的环境中从源代码构建

源代码是构建Docker镜像的最终源代码,Dockerfile中只提供构建步骤。

c994f0a8e5424d679eda9a30ea5c6d53

首先,您应该确定构建应用程序所需的所有依赖项。本文中的示例Java应用程序非常简单,只需要Maven和JDK,因此基本映像应该选择官方最小的maven映像,其中还包含JDK。如果需要安装更多依赖项,可以在RUN指令中添加它们。需要将pom.xml文件和src文件夹复制到映像中,因为mvn package命令最后执行(-e参数用于显示错误,-B参数用于在非交互式中运行)批处理模式)。使用这些依赖项文件。

虽然我们现在已经解决了环境不一致的问题,但还有另一个问题:在每次代码更改后,重新获取pom.xml中描述的所有依赖项。让我们在下面解决这个问题。

通过单独的步骤获取依赖关系

abf437d031de44a893b0c70f366dd1c5

结合上面提到的缓存机制,只要pom.xml文件的内容没有改变,无论代码如何更改,它都不会破坏缓存,我们可以将依赖关系转换为可缓存单元。这一层。上图中两条COPY指令中间的RUN指令用于告诉Maven仅获取依赖关系。

现在我遇到了一个新问题:与之前的jar包的直接副本相比,图像大小变得更大,因为它包含许多运行应用程序所不需要的构建依赖项。

使用多阶段构建来删除构建时依赖性

8cdf1e8448df472dbcd1d0d3e1662c8c

可以通过多个FROM指令来标识多阶段构建,每个FROM指令代表一个新的构建阶段,并且可以使用AS参数指定阶段名称。在此示例中,第一个阶段的名称被指定为构建器,可以由第二个阶段直接引用。两阶段环境是一致的,第一阶段包含所有构建依赖项。

第二阶段是构建最终图像的最后阶段,其中包括应用程序运行时的所有必要条件,在这种情况下基于Alpine的最小JRE图像。虽然在之前的构建阶段会有很多缓存,但它不会出现在第二阶段。要将构建的jar包添加到最终图像,可以使用COPY --from=STAGE_NAME指令,其中STAGE_NAME是先前构建阶段的名称。

c51baec72c7b4d73b6ac643fc9393c67

多阶段构建是删除构建依赖关系的首选方法。

本文首先介绍在非一致环境中构建较大图像的优化,优化在连贯环境中构建最小镜像,同时利用缓存机制。下一篇文章将介绍多阶段构建的更多其他用法。

原始链接:

热门浏览
热门排行榜
热门标签
日期归档