在本文中,你将了解如何加快 Docker 构建周期并创建轻量级镜像。还是用比喻来说吧,给 Docker 镜像瘦身就跟我们减肥一样,减肥时期我们吃沙拉,拒绝披萨、甜甜圈和百吉饼。
这是备忘单。
FROM:指定基础(父)镜像。
标签:提供元数据。这里是包含维护者信息的好地方。
ENV:设置一个持久环境变量。
RUN:运行一个命令并创建一个图像层。用于将包安装到容器中。
COPY:将文件和目录复制到容器中。
ADD:将文件和目录复制到容器中。可以上传本地.tar 文件中。
CMD:为正在执行的容器提供命令和参数。可以覆盖参数。只能有一个 CMD。
WORKDIR:为下面的指令设置工作目录。
ARG:在构建时传递给 Docker 的变量。
ENTRYPOINT:为正在执行的容器提供命令和参数。关于这件事的争论一直在持续。
EXPOSE:公开端口。
VOLUME:创建一个目录挂载点来访问和存储持久数据。
现在让我们看看如何设计 dockerfile,以便在开发镜像和提取容器时节省时间。
缓存
Docker 的优点之一是提供缓存,帮助你更快地迭代镜像构建。
在构建映像时,Docker 按步骤遍历 Dockerfile 中的指令,按顺序执行每个指令。在检查每个指令时,Docker 会在其缓存中寻找一个可以重用的现有中间镜像,而不是创建一个新的(重复的)中间映像。
如果缓存无效,让无效的指令和所有后续 Dockerfile 指令生成新的中间镜像。一旦缓存失效,Dockerfile 中其余的指令也就失效了。
因此,从 Dockerfile 的顶部开始,如果基础镜像已经在缓存中,那么它将被重用。这将是高效命中。否则,缓存无效。
也是一击
然后将下一条指令与从该基础镜像派生的缓存中的所有子镜像进行比较。比较每个缓存的中间镜像,看指令是否在缓存命中。如果缓存失败,则缓存无效。重复相同的过程,直到到达 Dockerfile 的末尾。
大多数新指令只是简单地与中间镜像中的指令进行比较。如果匹配,则使用缓存的副本。
例如,当在 Dockerfile 中找到RUN pip install -r requiremtes .txt
指令时,Docker 会在本地缓存的中间镜像中搜索相同的指令。不比较新旧 requirements.txt 文件的内容。
如果使用新包来更新 requirements.txt 文件,并使用RUN pip install
并希望使用新包名称重新运行包安装,则此行为可能会出现问题。我一会儿会展示一些解决方案。
与其他 Docker 指令不同,ADD 和 COPY 指令确实需要 Docker 查看文件的内容,以确定是否存在缓存命中。将引用文件的校验和与现有中间镜像中的校验和进行比较。如果文件内容或元数据发生了更改,则缓存无效。
下面是一些有效使用缓存的技巧。
可以通过传递
--no-cache=True
给docker build
关闭缓存。如果你要对指令进行更改,那么接下来的每一层都将频繁地重新构建。要利用缓存,请在 Dockerfile 中尽可能低地放置可能更改的指令。
链接
RUN apt-get update
和apt-get install
命令,以避免缓存丢失问题。如果你正在使用带有 requirements.txt 文件的包安装程序(如 pip),那么请遵循如下模型,以确保你不会收到带有 requirements.txt 中列出的旧包的陈旧的中间镜像。
这些是有效使用 Docker 构建缓存的建议。
减小尺寸
Docker 镜像可能会变得很大。你想让它们尺寸变小,这样它们就可以快速拉起,使用很少的资源。让我们给你的镜像瘦身!
吃顿沙拉而不是百吉饼
Alpine base 镜像是一个完整的 Linux 发行版,没有太多其他东西。下载通常小于 5mb,但是它需要更多的时间为构建应用程序所需的依赖项编写代码。
Alpine 源自阿尔卑斯山脉
如果你的容器中需要 Python, Python Alpine 构建是一个不错的折衷方案。它包含 Linux 和 Python,你可以提供大多数其他东西。
我用最新的 Python Alpine 构建的带有打印脚本(“hello world”)的镜像大小为 78.5 MB。下面是 Dockerfile:
在 Docker Hub 上,基础镜像的大小为 29MB,当构建子镜像时,需要下载并安装 Python,尺寸就变得很大。
除了使用 Alpine 基础镜像,另一种减小镜像大小的方法是使用多级构建。这种技术还会增加 Dockerfile 的复杂性。
多级构建
一个舞台+另一个舞台=多级舞台
多阶段构建使用多个 FROM 指令。你可以有选择地将文件(称为构建工件)从一个阶段复制到另一个阶段。你可以在最终的镜像中扔掉任何你不想要的东西。这种方法可以减少整体镜像的大小。
每个 FROM 指令
开始构建的新阶段
去掉在之前阶段留下的任何状态
可以用不同的基础镜像
下面是Docker文档中经过修改的多级构建示例:
注意,我们通过给 FROM 指令增加一个名字来命名第一阶段。然后,被命名的阶段会通过COPY --from=
指令引用到 Dockerfile 中。
在制造大量容器的情况下,多级构建是有意义的。多级构建可以帮助你从镜像大小中挤出每一寸空间。然而,有时多阶段构建会增加复杂性,使镜像更难维护,因此你可能不会在大多数构建中使用它们。参见此处对折衷和高级模式的进一步讨论。
相反,每个人都应该使用.dockerignore 文件来帮助保持 Docker 镜像的简洁。
.dockerignore
如果你对 Docker 了解得足够多,那么*.dockerignore*就是一些你应该知道的东西。
.dockerignore 类似于.gitignore。它是一个包含 Docker 模式列表的文件,Docker 在生成镜像时需要匹配文件名并排除这些模式。
来.dockerignore 一下
将.dockerignore 文件与 Dockerfile 和构建上下文的其余部分放在同一个文件夹中。
运行 docker build 创建镜像时,docker 检查.dockerignore 文件。如果找到一个,则逐行检查文件并使用 Go 的filepath。匹配规则——以及Docker自己的一些规则——以匹配文件名以进行排除。想想 unix 风格的 glob 模式,而不是正则表达式。
因此*.jpg
将排除扩展名为.jpg 的文件。并且视频
将排除视频文件夹及其内容。
您可以使用以#
开头的注释来解释您在.dockerignore 中所做的事情。
使用.dockerignore 从 Docker 镜像中排除不需要的文件是个好主意。
帮助你保守秘密。没有人想在镜像中使用密码。
减少镜像大小。更少的文件意味着更小、更快的镜像。
减少构建缓存失效。如果日志或其他文件正在发生变化,而你的镜像缓存因此而失效,则会减慢构建周期。
这就是使用.dockerignore 文件的原因。
尺寸检查
让我们看看如何从命令行找到 Docker 镜像和容器的大小。
要查看正在运行的容器的大致大小,可以使用
docker container ls -s
命令。运行
docker image ls
显示镜像的大小。要查看组成镜像的中间镜像大小,请使用
docker image history my_image:my_tag
。运行
Docker image inspect my_image:tag
:该标签将显示跟镜像有关的信息,包括每个层的大小。图层与构成镜像略有不同。但是你可以把它们看成是一样的。安装和使用dive可以很容易地看到你的层内容。
现在,让我们来看看一些最佳实践来给镜像瘦身。
减少镜像大小和构建时间的八个最佳实践
尽可能使用正式的基础镜像。官方镜像定期更新,比非官方镜像更安全。
在可能的情况下使用不同的 Alpine 镜像,以保持你的镜像轻量级。
3.如果使用 apt,请在同一指令中将 RUN apt-get update 与 apt-get install 结合使用。然后在该指令中链接多个包。用\字符在多行上按字母顺序列出包。例如:
这种方法减少了要构建的层的数量,并保持简洁。
在运行指令的末尾包含
&& rm -rf /var/lib/apt/lists/*
,以清理 apt 缓存,使其不存储在层中。聪明地使用缓存,将可能发生更改的指令放在 Dockerfile 中。
使用.dockerignore 文件将不需要的和不必要的文件从镜像中删除。
查看dive——它的一个非常酷的工具,可以检查你的 Docker 镜像层,并帮助你削减多余的部分。
不要安装你不需要的软件包。唉!但这种现象很常见。
总结
现在你知道了如何使 Docker 镜像快速构建、快速下载,并且不占用太多空间。和健康饮食一样,知道是成功的一半。享受你的蔬菜。
健康和美味
查看英文原文链接:https://towardsdatascience.com/slimming-down-your-docker-images-275f0ca9337e
评论 5 条评论