如何构建更小的容器

使用容器工作是很多用户和开发者的日常任务。容器开发者经常需要频繁地(重新)构建容器镜像。如果你开发容器,你。

使用容器工作是很多用户和开发者的日常任务。容器开发者经常需要频繁地(重新)构建容器镜像。如果你开发容器,你有想过减小镜像的大小吗?较小的镜像有一些好处。在下载的时候所需要的带宽更少,而且在云环境中运行的时候也可以节省开销。而且在 Fedora CoreOS、IoT 以及Silverblue 上使用较小的容器镜像可以提升整体系统性能,因为这些操作系统严重依赖于容器工作流。这篇文章将会提供一些减小容器镜像大小的技巧。

工具

以下例子所用到的主机操作系统是 Fedora Linux 33。例子使用 Podman 3.1.0 和Buildah 1.2.0。Podman 和 Buildah 已经预装在大多数 Fedora Linux 变种中。如果你没有安装 Podman 和 Buildah,可以用下边的命令安装:

$sudodnfinstall-ypodmanbuildah 任务

从一个基础的例子开始。构建一个满足以下需求的 web 容器:

容器必须基于 Fedora Linux 使用 Apache httpd web 服务器 包含一个定制的网站 容器应该比较小

下边的步骤也适用于比较复杂的镜像。

设置

首先,创建一个工程目录。这个目录将会包含你的网站和容器文件:

$mkdirsmallerContainer$cdsmallerContainer$mkdirfiles$touchfiles/index.html

制作一个简单的登录页面。对于这个演示,你可以将下面的 HTML 复制到 index.html 文件中。

<!doctypehtml>ContainerPage

ContainerPage

Fedora

  • FedoraProject
  • FedoraDocumentation
  • FedoraMagazine
  • FedoraCommunityBlog

Podman

  • Podman
  • PodmanDocumentation
  • PodmanCode
  • PodmanBlog

Buildah

  • Buildah
  • BuildahCode
  • BuildahBlog

Skopeo

  • skopeoCode

CRI-O

  • CRI-O
  • CRI-OCode
  • CRI-OBlog

此时你可以选择在浏览器中测试上面的 index.html 文件:

$firefoxfiles/index.html

最后,创建一个容器文件。这个文件可以命名为 Dockerfile 或者 Containerfile:

$touchContainerfile

现在你应该有了一个工程目录,并且该目录中的文件系统布局如下:

smallerContainer/|-files/||-index.html||-Containerfile 构建

现在构建镜像。下边的每个阶段都会添加一层改进来帮助减小镜像的大小。你最终会得到一系列镜像,但只有一个 Containerfile。

阶段 0:一个基本的容器镜像

你的新镜像将会非常简单,它只包含强制性步骤。在 Containerfile 中添加以下内容:

#使用Fedora33作为基镜像FROMregistry.fedoraproject.org/fedora:33#安装httpdRUNdnfinstall-yhttpd#复制这个网站COPYfiles/*/var/www/html/#设置端口为80/tcpEXPOSE80#启动httpd

在上边的文件中有一些注释来解释每一行内容都是在做什么。更详细的步骤:

在 FROM registry.fedoraproject.org/fedora:33 的基础上创建一个构建容器 运行命令: dnf install -y httpd 将与 Containerfile 有关的文件拷贝到容器中 设置 EXPOSE 80 来说明哪个端口是可以自动设置的 设置一个 CMD 指令来说明如果从这个镜像创建一个容器应该运行什么

运行下边的命令从工程目录创建一个新的镜像:

$podmanimagebuild-fContainerfile-tlocalhost/web-base

使用一下命令来查看你的镜像的属性。注意你的镜像的大小(467 MB)。

$podmanimagelsREPOSITORYTAGIMAGEIDCREATEDSIZElocalhost/web-baselatestac8c5ed73bb55minutesago467MBregistry.fedoraproject.org/fedora339f2a560376433monthsago182MB

以上这个例子中展示的镜像在现在占用了467 MB的空间。剩下的阶段将会显著地减小镜像的大小。但是首先要验证镜像是否能够按照预期工作。

输入以下命令来启动容器:

$podmancontainerrun-d–nameweb-base-Plocalhost/web-base

输入以下命令可以列出你的容器:

$podmancontainerlsCONTAINERIDIMAGECOMMANDCREATEDSTATUSPORTSNAMESd24063487f9flocalhost/web-basehttpd-DFOREGROUN…2secondsagoUp3secondsago0.0.0.0:46191->80/tcpweb-base

以上展示的容器正在运行,它正在监听的端口是 46191 。从运行在主机操作系统上的 web 浏览器转到 localhost:46191 应该呈现你的 web 页面:

$firefoxlocalhost:46191 阶段 1:清除缓存并将残余的内容从容器中删除

为了优化容器镜像的大小,第一步应该总是执行“清理”。这将保证安装和打包所残余的内容都被删掉。这个过程到底需要什么取决于你的容器。对于以上的例子,只需要编辑 Containerfile 让它包含以下几行。

[…]#InstallhttpdRUNdnfinstall-yhttpd&&dnfcleanall-y[…]

构建修改后的 Containerfile 来显著地减小镜像(这个例子中是 237 MB)。

$podmanimagebuild-fContainerfile-tlocalhost/web-clean$podmanimagelsREPOSITORYTAGIMAGEIDCREATEDSIZElocalhost/web-cleanlatestf0f62aece0286secondsago237MB 阶段 2:删除文档和不需要的依赖包

许多包在安装时会被建议拉下来,包含一些弱依赖和文档。这些在容器中通常是不需要的,可以删除。 dnf 命令有选项可以表明它不需要包含弱依赖或文档。

再次编辑 Containerfile ,并在 dnf install 行中添加删除文档和弱依赖的选项:

[…]#InstallhttpdRUNdnfinstall-yhttpd–nodocs–setoptinstall_weak_deps=False&&dnfcleanall-y[…]

构建经过以上修改后的 Containerfile 可以得到一个更小的镜像(231 MB)。

$podmanimagebuild-fContainerfile-tlocalhost/web-docs$podmanimagelsREPOSITORYTAGIMAGEIDCREATEDSIZElocalhost/web-docslatest8a76820cec2f8secondsago231MB 阶段 3:使用更小的容器基镜像

前面的阶段结合起来,使得示例镜像的大小减少了一半。但是仍然还有一些途径来进一步减小镜像的大小。这个基镜像 registry.fedoraproject.org/fedora:33 是通用的。它提供了一组软件包,许多人希望这些软件包预先安装在他们的 Fedora Linux 容器中。但是,通用的 Fedora Linux 基镜像中提供的包通常必须要的更多。Fedora 项目也为那些希望只从基本包开始,然后只添加所需内容来实现较小总镜像大小的用户提供了一个 fedora-minimal 镜像。

使用 podman image search 来查找 fedora-minimal 镜像,如下所示:

$podmanimagesearchfedora-minimalINDEXNAMEDESCRIPTIONSTARSOFFICIALAUTOMATEDfedoraproject.orgregistry.fedoraproject.org/fedora-minimal

fedora-minimal 基镜像不包含 DNF,而是倾向于使用不需要 Python 的较小的 microDNF。

当 registry.fedoraproject.org/fedora:33 被 registry.fedoraproject.org/fedora-minimal:33 替换后,需要用 microdnf 命令来替换 dnf。

#使用Fedoraminimal33作为基镜像FROMregistry.fedoraproject.org/fedora-minimal:33#安装httpdRUNmicrodnfinstall-yhttpd–nodocs–setoptinstall_weak_deps=0&&microdnfcleanall-y[…]

使用 fedora-minimal 重新构建后的镜像大小如下所示 (169 MB):

$podmanimagebuild-fContainerfile-tlocalhost/web-docs$podmanimagelsREPOSITORYTAGIMAGEIDCREATEDSIZElocalhost/web-minimallateste1603bbb10977minutesago169MB

最开始的镜像大小是 467 MB。结合以上每个阶段所提到的方法,进行重新构建之后可以得到最终大小为 169 MB 的镜像。最终的 总 镜像大小比最开始的 基 镜像小了 182 MB!

从零开始构建容器

前边的内容使用一个容器文件和 Podman 来构建一个新的镜像。还有最后一个方法要展示——使用 Buildah 来从头构建一个容器。Podman 使用与 Buildah 相同的库来构建容器。但是 Buildah 被认为是一个纯构建工具。Podman 被设计来是为了代替 Docker 的。

使用 Buildah 从头构建的容器是空的——它里边什么都 没有 。所有的东西都需要安装或者从容器外复制。幸运地是,使用 Buildah 相当简单。下边是一个从头开始构建镜像的小的 Bash 脚本。除了运行这个脚本,你也可以在终端逐条地运行脚本中的命令,来更好的理解每一步都是做什么的。

#!/usr/bin/envbashset-oerrexit#创建一个容器CONTAINER=$(buildahfromscratch)#挂载容器文件系统MOUNTPOINT=$(buildahmount$CONTAINER)#安装一个基本的文件系统和最小的包以及nginxdnfinstall-y–installroot$MOUNTPOINT–releasever33glibc-minimal-langpackhttpd–nodocs–setoptinstall_weak_deps=Falsednfcleanall-y–installroot$MOUNTPOINT–releasever33#清除buildahunmount$CONTAINER#复制网站buildahcopy$CONTAINER\’files/*\’\’/var/www/html/\’#设置端口为80/tcpbuildahconfig–port80$CONTAINER#启动httpdbuildahconfig–cmd\”httpd-DFOREGROUND\”$CONTAINER#将容器保存为一个镜像buildahcommit–squash$CONTAINERweb-scratch

或者,可以通过将上面的脚本传递给 Buildah 来构建镜像。注意不需要 root 权限。

$buildahunsharebashweb-scratch.sh$podmanimagelsREPOSITORYTAGIMAGEIDCREATEDSIZElocalhost/web-scratchlatestacca45fc91189secondsago155MB

最后的镜像只有 155 MB!而且 攻击面 也减少了。甚至在最后的镜像中都没有安装 DNF(或者 microDNF)。

结论

构建一个比较小的容器镜像有许多优点。减少所需要的带宽、磁盘占用以及攻击面,都会得到更好的镜像。只用很少的更改来减小镜像的大小很简单。许多更改都可以在不改变结果镜像的功能下完成。

只保存所需的二进制文件和配置文件来构建非常小的镜像也是可能的。

给TA打赏
共{{data.count}}人
人已打赏
云计算

意大利向谷歌处以超过1亿欧元的罚款

2021-5-13 16:49:43

云计算

谷歌自动驾驶汽车业务管理层再动荡:CFO和汽车合作企业发展主管离职

2021-5-13 16:49:45

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索