使用容器工作是很多用户和开发者的日常任务。容器开发者经常需要频繁地(重新)构建容器镜像。如果你开发容器,你有想过减小镜像的大小吗?较小的镜像有一些好处。在下载的时候所需要的带宽更少,而且在云环境中运行的时候也可以节省开销。而且在Fedora CoreOS、IoT以及Silverblue上使用较小的容器镜像可以提升整体系统性能,因为这些操作系统严重依赖于容器工作流。这篇文章将会提供一些减小容器镜像大小的技巧。
工具
以下例子所用到的主机操作系统是Fedora Linux 33。例子使用Podman 3.1.0和Buildah 1.2.0。Podman和Buildah已经预装在大多数Fedora Linux变种中。如果你没有安装Podman和Buildah,可以用下边的命令安装:
从一个基础的例子开始。构建一个满足以下需求的web容器:
容器必须基于Fedora Linux使用Apache httpd web服务器包含一个定制的网站容器应该比较小
下边的步骤也适用于比较复杂的镜像。
设置
首先,创建一个工程目录。这个目录将会包含你的网站和容器文件:
Mkdir SmallerContainer cd SmallerContainer Mkdir files Touch files/index.html
制作一个简单的登录页面。对于这个演示,你可以将下面的HTML复制到index.html文件中。
容器Page Fedora Project Fedora Documentation Fedora Magazine Fedora Community Blog Podman Podman Documentation Podman Code Podman Blog Buildah Buildah Code Buildah Blog Skopeo skopeo Code CRI-O CRI-O Code CRI-O Blog
此时你可以选择在浏览器中测试上面的index.html文件:
Firefox files/index.html
最后,创建一个容器文件。这个文件可以命名为Dockerfile或者Containerfile:
Touch Containerfile
现在你应该有了一个工程目录,并且该目录中的文件系统布局如下:
SmallerContainer/ |- files/ | – index.html | – Containerfile 构建
现在构建镜像。下边的每个阶段都会添加一层改进来帮助减小镜像的大小。你最终会得到一系列镜像,但只有一个Containerfile。
阶段 0:一个基本的容器镜像
你的新镜像将会非常简单,它只包含强制性步骤。在Containerfile中添加以下内容:
# 使用Fedora 33作为基镜像 FROM Registry.fedoraproject.org/fedora:33 # 安装httpd RUN dnf install -y httpd # 复制这个网站 COPY files/* /var/www/html/ # 设置端口为80/TCP EXPOSE 80 # 启动httpd
在上边的文件中有一些注释来解释每一行内容都是在做什么。更详细的步骤:
在FROM Registry.fedoraproject.org/fedora:33的基础上创建一个构建容器 运行命令:dnf install -y httpd将与Containerfile有关的文件拷贝到容器中 设置EXPOSE 80来说明哪个端口是可以自动设置的 设置一个CMD指令来说明如果从这个镜像创建一个容器应该运行什么
运行下边的命令从工程目录创建一个新的镜像:
podman image build -f Containerfile -t localhost/web-base
使用以下命令来查看你的镜像的属性。注意你的镜像的大小(467 MB)。
podman image ls REPOSITORY tag image ID CREATED SIZE localhost/web-base latest ac8c5ed73bb5 5 Minutes ago 467 MB Registry.fedoraproject.org/fedora 33 9f2a56037643 3 Months ago 182 MB
以上这个例子中展示的镜像在现在占用了467 MB的空间。剩下的阶段将会显著地减小镜像的大小。但是首先要验证镜像是否能够按照预期工作。
输入以下命令来启动容器:
podman container run -d –name web-base -P localhost/web-base
输入以下命令可以列出你的容器:
podman container ls CONTAINER ID image command CREATED STATUS PORTS NAMES d24063487f9f localhost/web-base httpd -DFOREGROUN… 2 seconds ago Up 3 seconds ago 0.0.0.0:46191->80/TCP web-base
以上展示的容器正在运行,它正在监听的端口是46191。从运行在主机操作系统上的web浏览器转到localhost:46191应该呈现你的web页面:
Firefox localhost:46191 阶段 1:清除缓存并将残余的内容从容器中删除
为了优化容器镜像的大小,第一步应该总是执行“清理”。这将保证安装和打包所残余的内容都被删掉。这个过程到底需要什么取决于你的容器。对于以上的例子,只需要编辑Containerfile让它包含以下几行。
阶段 2:删除文档和不需要的依赖包
许多包在安装时会被建议拉下来,包含一些弱依赖和文档。这些在容器中通常是不需要的,可以删除。dnf命令有选项可以表明它不需要包含弱依赖或文档。
再次编辑Containerfile,并在dnf install行中添加删除文档和弱依赖的选项:
构建经过以上修改后的Containerfile可以得到一个更小的镜像(231 MB)。
podman image build -f Containerfile -t localhost/web-docs podman image ls REPOSITORY tag image ID CREATED SIZE localhost/web-docs latest 8a76820cec2f 8 seconds ago 231 MB 阶段 3:使用更小的容器基镜像
前面的阶段结合起来,使得示例镜像的大小减少了一半。但是仍然还有一些途径来进一步减小镜像的大小。这个基镜像Registry.fedoraproject.org/fedora:33是通用的。它提供了一组软件包,许多人希望这些软件包预先安装在他们的Fedora Linux容器中。但是,通用的Fedora Linux基镜像中提供的包通常必须要的更多。Fedora项目也为那些希望只从基本包开始,然后只添加所需内容来实现较小总镜像大小的用户提供了一个fedora-minimal镜像。
使用podman image search来查找fedora-minimal镜像,如下所示:
fedora-minimal基镜像不包含DNF,而是倾向于使用不需要Python的较小的MicRoDNF。
当Registry.fedoraproject.org/fedora:33被Registry.fedoraproject.org/fedora-minimal:33替换后,需要用MicRodnf命令来替换dnf。
使用fedora-minimal重新构建后的镜像大小如下所示 (169 MB):
podman image build -f Containerfile -t localhost/web-docs podman image ls REPOSITORY tag image ID CREATED SIZE localhost/web-minimal latest e1603bbb1097 7 Minutes ago 169 MB
最开始的镜像大小是467 MB。结合以上每个阶段所提到的方法,进行重新构建之后可以得到最终大小为169 MB的镜像。最终的总镜像大小比最开始的基镜像小了182 MB!
从零开始构建容器
前边的内容使用一个容器文件和Podman来构建一个新的镜像。还有最后一个方法要展示——使用Buildah来从头构建一个容器。Podman使用与Buildah相同的库来构建容器。但是Buildah被认为是一个纯构建工具。Podman被设计来是为了代替Docker的。
使用Buildah从头构建的容器是空的——它里边什么都没有。所有的东西都需要安装或者从容器外复制。幸运地是,使用Buildah相当简单。下边是一个从头开始构建镜像的小的Bash脚本。除了运行这个脚本,你也可以在终端逐条地运行脚本中的命令,来更好的理解每一步都是做什么的。
或者,可以通过将上面的脚本传递给Buildah来构建镜像。注意不需要Root权限。
最后的镜像只有155 MB!而且攻击面也减少了。甚至在最后的镜像中都没有安装DNF(或者MicRoDNF)。
结论
构建一个比较小的容器镜像有许多优点。减少所需要的带宽、磁盘占用以及攻击面,都会得到更好的镜像。只用很少的更改来减小镜像的大小很简单。许多更改都可以在不改变结果镜像的功能下完成。
只保存所需的二进制文件和配置文件来构建非常小的镜像也是可能的。