TranslateProject/translated/tech/20210421 Build smaller containers.md

13 KiB
Raw Blame History

构建更小的容器

build smaller containers

水獭图片节选自Dele Oluwayomi 发表在 Unsplash上的照片

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

工具

以下例子所用到的主机操作系统是Fedora Linux33。例子使用 Podman 3.1.0 和Buildah 1.2.0。在大多数Fedora Linux变体中Podman和Buildah都被预装好了。如果你没有安装Podman和Buildah可以用下边的命令安装

$ sudo dnf install -y podman buildah

任务

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

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

下边的步骤都是在比较复杂的镜像上进行的。

设置

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

$ mkdir smallerContainer
$ cd smallerContainer
$ mkdir files
$ touch files/index.html

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

<!doctype html>

<html lang="de">
<head>
  <title>Container Page</title>
</head>

<body>
  <header>
    <h1>Container Page</h1>
  </header>
  <main>
    <h2>Fedora</h2>
    <ul>
      <li><a href="https://getfedora.org">Fedora Project</a></li>
      <li><a href="https://docs.fedoraproject.org/">Fedora Documentation</a></li>
      <li><a href="https://fedoramagazine.org">Fedora Magazine</a></li>
      <li><a href="https://communityblog.fedoraproject.org/">Fedora Community Blog</a></li>
    </ul>
    <h2>Podman</h2>
    <ul>
      <li><a href="https://podman.io">Podman</a></li>
      <li><a href="https://docs.podman.io/">Podman Documentation</a></li>
      <li><a href="https://github.com/containers/podman">Podman Code</a></li>
      <li><a href="https://podman.io/blogs/">Podman Blog</a></li>
    </ul>
    <h2>Buildah</h2>
    <ul>
      <li><a href="https://buildah.io">Buildah</a></li>
      <li><a href="https://github.com/containers/buildah">Buildah Code</a></li>
      <li><a href="https://buildah.io/blogs/">Buildah Blog</a></li>
    </ul>
    <h2>Skopeo</h2>
    <ul>
      <li><a href="https://github.com/containers/skopeo">skopeo Code</a></li>
    </ul>
    <h2>CRI-O</h2>
    <ul>
      <li><a href="https://cri-o.io/">CRI-O</a></li>
      <li><a href="https://github.com/cri-o/cri-o">CRI-O Code</a></li>
      <li><a href="https://medium.com/cri-o">CRI-O Blog</a></li>
    </ul>
  </main>
</body>

</html>

此时你可以选择在浏览器中测试上面的 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
CMD ["httpd", "-DFOREGROUND"]

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

  1. 在FROM registry.fedoraproject.org/fedora:33 的基础上创建一个构建容器
  2. 运行命令: dnf install -y httpd
  3. 将与 Containerfile 有关的文件拷贝到容器中
  4. 设置EXPOSE 80来说明哪个端口是可以自动设置的
  5. 设置一个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 让它包含以下几行。

[...]
# Install httpd
RUN dnf install -y httpd && \
    dnf clean all -y
[...]

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

$ podman image build -f Containerfile -t localhost/web-clean
$ podman image ls
REPOSITORY            TAG     IMAGE ID      CREATED        SIZE
localhost/web-clean   latest  f0f62aece028  6 seconds ago  237 MB

阶段2删除文档和不需要的依赖包

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

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

[...]
# Install httpd
RUN dnf install -y httpd --nodocs --setopt install_weak_deps=False && \
    dnf clean all -y
[...]

构建经过以上修改后的 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 镜像如下所示。

$ podman image search fedora-minimal
INDEX               NAME   DESCRIPTION   STARS   OFFICIAL   AUTOMATED
fedoraproject.org   registry.fedoraproject.org/fedora-minimal         0

fedora-minimal 基镜像不包含DNF而是倾向于不需要Python的较小的microDNF。当 registry.fedoraproject.org/fedora:33registry.fedoraproject.org/fedora-minimal:33 替换后,需要用 microdnf 来替换 dnf

# 使用Fedora minimal 33作为基镜像
FROM registry.fedoraproject.org/fedora-minimal:33

# 安装 httpd
RUN microdnf install -y httpd --nodocs --setopt install_weak_deps=0 && \
    microdnf clean all -y
[...]

使用 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脚本。除了运行这个脚本你也可以在终端逐条地运行脚本中的命令来更好的理解每一步都是做什么的。

#!/usr/bin/env bash
set -o errexit

# 创建一个容器
CONTAINER=$(buildah from scratch)

# 挂载容器文件系统
MOUNTPOINT=$(buildah mount $CONTAINER)

# 安装一个基本的文件系统和最小的包以及nginx
dnf install -y --installroot $MOUNTPOINT  --releasever 33 glibc-minimal-langpack httpd --nodocs --setopt install_weak_deps=False

dnf clean all -y --installroot $MOUNTPOINT --releasever 33

# 清除
buildah unmount $CONTAINER

# 复制网站
buildah copy $CONTAINER 'files/*' '/var/www/html/'

# 设置端口为 80/tcp
buildah config --port 80 $CONTAINER

# 启动httpd
buildah config --cmd "httpd -DFOREGROUND" $CONTAINER

# 将容器保存为一个镜像
buildah commit --squash $CONTAINER web-scratch

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

$ buildah unshare bash web-scratch.sh
$ podman image ls
REPOSITORY             TAG     IMAGE ID      CREATED        SIZE
localhost/web-scratch  latest  acca45fc9118  9 seconds ago  155 MB

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

结论

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

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


via: https://fedoramagazine.org/build-smaller-containers/

作者:Daniel Schier 选题:lujun9972 译者:ShuyRoy 校对:校对者ID

本文由 LCTT 原创编译,Linux中国 荣誉推出