文章插图
Photo by William Warby on Unsplash
您是否曾经想过为什么您的单应用程序Docker容器会增长到400 MB? 或者 , 也许为什么一个只有几十MB的应用程序二进制文件会生成一个MB的Docker映像?
在本文中 , 我们将回顾一些导致容器变胖的主要因素 , 以及为您的项目提供超薄Docker容器的最佳实践和技巧 。
Docker镜像层Docker容器镜像本质上是堆积的文件 , 稍后将被实例化为正在运行的容器 。Docker利用联合文件系统(UnionFS)设计 , 其中文件按层分组在一起 。每一层可能包含一个或多个文件 , 并且每一层都位于上一层的顶部 。作为最终用户 , 我们体验了作为统一文件系统的所有层的所有内容的虚拟运行时合并:
文章插图
A simplified view of UnionFS (Image by the author)
UnionFS的底层实现向我们提供的最终文件系统视图(Docker通过可插拔存储驱动程序支持许多不同的视图)具有其所构成的所有层的总大小 。Docker为图像创建容器时 , 它将以只读格式使用镜像的所有层 , 并在它们之上添加一个薄的读写层 。这个薄的读写层使我们能够实际修改正在运行的Docker容器中的文件:
文章插图
A running container adds a read-write layer on top of an image's read-only layers.
如果在上述第4层中删除了文件 , 会发生什么情况? 尽管已删除的文件不会再出现在观察到的文件系统中 , 但是由于该文件包含在较低的只读层中 , 因此它最初占用的大小仍将是容器占用空间的一部分 。
从一个小的应用程序二进制文件开始到以一个胖容器镜像结束是相对容易的 。在以下各节中 , 我们将探索不同的方法来使镜像的尺寸尽可能地薄 。
提防构建路径我们构建Docker镜像的最常见方式是什么?
docker build .上面的命令告诉Docker我们将当前的工作文件夹视为构建过程的根文件系统路径 。
为了更好地理解发出上述命令时实际发生的情况 , 我们应该记住 , Docker构建是一个客户端-服务器进程 。我们从中执行docker build命令的Docker CLI(客户端)使用基础Docker引擎(服务器)来构建容器镜像 。为了限制对客户端基础文件系统的访问 , 构建过程需要知道虚拟文件系统的根目录是什么 。正是在此确切路径下 , Dockerifle中的任何命令都试图查找可能最终在正在生成的镜像中结束的文件资源 。
让我们考虑一下我们通常放置Dockerfile的位置 。在项目的根源中 , 也许吧? 好吧 , 将项目根目录中的Dockerfile与Docker构建相结合 , 我们已经有效地添加了完整的项目文件夹作为构建的潜在文件资源 。这可能会导致在构建上下文中不必要地添加多个MB和数千个文件 。如果我们不小心在Dockerfile中定义了ADD / COPY命令 , 则所有这些文件都可以成为最终镜像的一部分 。在大多数情况下 , 这不是我们所需要的 , 因为最终容器镜像中仅应包含一些选定的项目人工制品 。
始终检查是否为Docker构建提供了适当的构建路径 , 并且Dockerfile没有向镜像添加不必要的文件 。如果出于任何原因确实需要将项目的根目录定义为构建上下文 , 则可以通过.dockerignore有选择地包括/排除文件 。
挤压图像命令合并的另一种方法是使用Docker的squash命令构建镜像 , 尤其是在使用您不希望或无法修改的其他Dockerfile时 。
除非您使用的是非常老的Docker版本(<1.13) , 否则Docker允许我们将所有层压缩为一个层 , 从而有效地删除所有虚幻资源 。我们仍然可以将原始的 , 未更改的Dockerfile与许多单独的命令一起使用 , 但是这次我们通过--sqash选项执行构建:
docker build --squash .再次对生成的镜像进行100%优化:
文章插图
A 100% optimised image with image squash (Image by the author)
这里需要注意的有趣一点是 , 由于我们的Dockerfile创建了一个添加文件的层 , 然后创建了另一个删除该文件的层 , 所以squash足够聪明 , 以至于无需创建任何层(我们只有9ccd9…层 我们正在使用的基本图片) 。然后 , 额外的荣誉就可以南瓜了 。但是 , 请注意 , 挤压图层可能会阻止您或您的镜像用户利用先前缓存的图层 。
推荐阅读
- 快速搞定docker部署Filebeat、ELK全家桶
- Jenkins与Docker的自动化CI/CD流水线实战
- 在没有网络的环境下离线安装docker
- Docker容器网络实操教程
- EFK 日志系统收集K8s日志 之 容器标准输出日志
- 借助工具优化Dockerfile分层
- Docker命令大全
- docker下拉取tomcat镜像以及配置,亲测可用
- 云计算核心技术Docker教程:docker-compose控制服务启动和关闭顺序
- 基于SpringBoot的微服务架构与K8S容器部署实践