如何构建更小的容器
容器
![](/data/attachment/album/202105/12/112108han4e111a6v16act.jpg)


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


### 工具


以下例子所用到的主机操作系统是 Fedora Linux 33。例子使用 [Podman](https://podman.io/) 3.1.0 和[Buildah](https://buildah.io/) 1.2.0。Podman 和 Buildah 已经预装在大多数 Fedora Linux 变种中。如果你没有安装 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](https://github.com/rpm-software-management/dnf)，而是倾向于使用不需要 Python 的较小的 [microDNF](https://github.com/rpm-software-management/microdnf)。当 `registry.fedoraproject.org/fedora:33` 被 `registry.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**！而且 [攻击面](https://en.wikipedia.org/wiki/Attack_surface) 也减少了。甚至在最后的镜像中都没有安装 DNF（或者 microDNF）。


### 结论


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


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




---


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


作者：[Daniel Schier](https://fedoramagazine.org/author/danielwtd/) 选题：[lujun9972](https://github.com/lujun9972) 译者：[ShuyRoy](https://github.com/Shuyroy) 校对：[wxy](https://github.com/wxy)


本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


OK
Working with containers is a daily task for many users and developers. Container developers often need to (re)build container images frequently. If you develop containers, have you ever thought about reducing the image size? Smaller images have several benefits. They require less bandwidth to download and they save costs when run in cloud environments. Also, using smaller container images on Fedora [CoreOS](https://fedoramagazine.org/getting-started-with-fedora-coreos/), [IoT](https://getfedora.org/en/iot/) and [Silverblue](https://fedoramagazine.org/what-is-silverblue/) improves overall system performance because those operating systems rely heavily on container workflows. This article will provide a few tips for reducing the size of container images.

## The tools

The host operating system in the following examples is Fedora Linux 33. The examples use [Podman](https://podman.io/) 3.1.0 and [Buildah](https://buildah.io/) 1.2.0. Podman and Buildah are pre-installed in most Fedora Linux variants. If you don’t have Podman or Buildah installed, run the following command to install them.

$ sudo dnf install -y podman buildah

## The task

Begin with a basic example. Build a web container meeting the following requirements.

- The container must be based on Fedora Linux
- Use the Apache httpd web server
- Include a custom website
- The container should be relatively small

The following steps will also work on more complex images.

## The setup

First, create a project directory. This directory will include your website and container file.

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

Make a simple landing page. For this demonstration, you may copy the below HTML into the *index.html* file.

<!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>

Optionally, test the above *index.html* file in your browser.

$ firefox files/index.html

Finally, create a container file. The file can be named either *Dockerfile* or *Containerfile*.

$ touch Containerfile

You should now have a project directory with a file system layout similar to what is shown in the below diagram.

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

## The build

Now make the image. Each of the below stages will add a layer of improvements to help reduce the size of the image. You will end up with a series of images, but only one *Containerfile*.

### Stage 0: a baseline container image

Your new image will be very simple and it will only include the mandatory steps. Place the following text in *Containerfile*.

# Use Fedora 33 as base image FROM registry.fedoraproject.org/fedora:33 # Install httpd RUN dnf install -y httpd # Copy the website COPY files/* /var/www/html/ # Expose Port 80/tcp EXPOSE 80 # Start httpd CMD ["httpd", "-DFOREGROUND"]

In the above file there are some comments to indicate what is being done. More verbosely, the steps are:

- Create a build container with the base FROM registry.fedoraproject.org/fedora:33
- RUN the command:
*dnf install -y httpd* - COPY files relative to the
*Containerfile*to the container - Set EXPOSE 80 to indicate which port is auto-publishable
- Set a CMD to indicate what should be run if one creates a container from this image

Run the below command to create a new image from the project directory.

$ podman image build -f Containerfile -t localhost/web-base

Use the following command to examine your image’s attributes. Note in particular the size of your image (467 MB).

$ podman image ls REPOSITORY TAG IMAGE ID CREATED SIZE localhost/web-base latest ac8c5ed73bb5 5 minutes ago467 MBregistry.fedoraproject.org/fedora 33 9f2a56037643 3 months ago 182 MB

The example image shown above is currently occupying 467 MB of storage. The remaining stages should reduce the size of the image significantly. But first, verify that the image works as intended.

Enter the following command to start the container.

$ podman container run -d --name web-base -P localhost/web-base

Enter the following command to list your containers.

$ 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

The container shown above is running and it is listening on port *46191*. Going to *localhost:46191* from a web browser running on the host operating system should render your web page.

$ firefox localhost:46191

### Stage 1: clear caches and remove other leftovers from the container

The first step one should always perform to optimize the size of their container image is “clean up”. This will ensure that leftovers from installations and packaging are removed. What exactly this process entails will vary depending on your container. For the above example you can just edit *Containerfile* to include the following lines.

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

Build the modified *Containerfile* to reduce the size of the image significantly (237 MB in this example).

$ 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 ago237 MB

### Stage 2: remove documentation and unneeded package dependencies

Many packages will pull in recommendations, weak dependencies and documentation when they are installed. These are often not needed in a container and can be excluded. The *dnf* command has options to indicate that it should not include weak dependencies or documentation.

Edit *Containerfile* again and add the options to exclude documentation and weak dependencies on the *dnf install* line:

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

Build *Containerfile* with the above modifications to achieve an even smaller image (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 ago231 MB

### Stage 3: use a smaller container base image

The prior stages, in combination, have reduced the size of the example image by half. But there is still one more thing that can be done to reduce the size of the image. The base image *registry.fedoraproject.org/fedora:33* is meant for general purpose use. It provides a collection of packages that many people expect to be pre-installed in their Fedora Linux containers. The collection of packages provided in the general purpose Fedora Linux base image is often more extensive than needed, however. The Fedora Project also provides a *fedora-minimal* base image for those who wish to start with only the essential packages and then add only what they need to achieve a smaller total image size.

Use *podman image search* to search for the *fedora-minimal* image as shown below.

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

The *fedora-minimal* base image excludes [DNF](https://github.com/rpm-software-management/dnf) in favor of the smaller [microDNF](https://github.com/rpm-software-management/microdnf) which does not require Python. When *registry.fedoraproject.org/fedora:33* is replaced with *registry.fedoraproject.org/fedora-minimal:33*, *dnf* needs to be replaced with *microdnf*.

# Use Fedora minimal 33 as base image FROM registry.fedoraproject.org/fedora-minimal:33 # Install httpd RUN microdnf install -y httpd --nodocs --setopt install_weak_deps=0 && \ microdnf clean all -y [...]

Rebuild the image to see how much storage space has been recovered by using *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 ago169 MB

The initial image size was **467 MB**. Combining the methods detailed in each of the above stages has resulted in a final image size of **169 MB**. The final *total* image size is smaller than the original *base* image size of 182 MB!

## Building containers from scratch

The previous section used a container file and Podman to build a new image. There is one last thing to demonstrate — building a container from scratch using Buildah. Podman uses the same libraries to build containers as Buildah. But Buildah is considered a pure build tool. Podman is designed to work as a replacement for Docker.

When building from scratch using Buildah, the container is empty — there is *nothing* in it. Everything needed must be installed or copied from outside the container. Fortunately, this is quite easy with Buildah. Below, a small Bash script is provided which will build the image from scratch. Instead of running the script, you can run each of the commands from the script individually in a terminal to better understand what is being done.

#!/usr/bin/env bash set -o errexit # Create a container CONTAINER=$(buildah from scratch) # Mount the container filesystem MOUNTPOINT=$(buildah mount $CONTAINER) # Install a basic filesystem and minimal set of packages, and httpd 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 # Cleanup buildah unmount $CONTAINER # Copy the website buildah copy $CONTAINER 'files/*' '/var/www/html/' # Expose Port 80/tcp buildah config --port 80 $CONTAINER # Start httpd buildah config --cmd "httpd -DFOREGROUND" $CONTAINER # Save the container to an image buildah commit --squash $CONTAINER web-scratch

Alternatively, the image can be built by passing the above script to Buildah. Notice that root privileges are not required.

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

The final image is only **155 MB**! Also, the [attack surface](https://en.wikipedia.org/wiki/Attack_surface) has been reduced. Not even DNF (or microDNF) is installed in the final image.

## Conclusion

Building smaller container images has many advantages. Reducing the needed bandwidth, the disk footprint and attack surface will lead to better images overall. It is easy to reduce the footprint with just a few small changes. Many of the changes can be done without altering the functionality of the resulting image.

It is also possible to build very small images from scratch which will only hold the needed binaries and configuration files.

## Alexander

Thank you for the last part. “Building from scratch.”

I’m woundering about SystemD. It must be installed as well? but not started?

## Daniel Schier

systemd is installed by dependencies, but is not needed in a container. In fact, it should be even avoided if necessary. Starting a service directly in foreground should be preferred.

## Rob Verduijn

Removing the layers also reduces the overhead a bit.

podman build –layers=false

## Daniel Schier

will only avoid caching layers during the build. If you want to squash everything in one layer (which can be useful depending on your usecase), you can use

or

.

## Rene Reichenbach

And now try with a go or rust app doing the same 😉

## Phozzy

– will work well in the last scenario.

## Daniel Schier

The “from scratch” example will most likely work similar, but you can also have a look at multi-stage builds. 🙂

## rnx

useful article. thanks.

perhaps dnf should get a new subcommand specifically for installing with recommended defaults for container images and cache cleaning … would make things more cleaner and more readable.

dnf containerinstall xy or something

## Mark

I have had issues in the past with microdnf when a fedora-minimal image must have been built prior to a package update being removed from the main repository and it found a package to downgrade, microdnf will fail instead of downgrading. Infrequent but if you care about attack surfaces you should always ‘microdnf -y update’ when building a new container so it can be an issue. So some of my docker files use microdnf to install dnf and then remove that when done.

I use docker and there is a utility ‘docker-squash’ (obtained simply with ‘pip3 install docker-squash’) which has made me a bit lazy; in that you can use clarity in Dockerfile usage by not bothering to use && to stack multiple commands to minimise layers but instead happily generate as many layers as you want and even have huge ones at the start. And docker-squash will happily compress 20-30 layers down to 2 for you which shrinks the container image size a lot. I also use that on images pulled from dockerhub where some application containers can be >1Gb in size when pulled from dockerhub and many of those can be shrunk as well. docker-squash does need docker though and won’t work with podman last time I checked.

Having said that I was interested in the comment from Rob Verduijn about the ‘podman build –layers=false’ option I will have to look at to see what it does, as it is the layers that while useful for managing changes/versions take up needless space in a container image. But it’s use would be in containers personally built at build time rather than run against containers already built externally.

I also appreciate the ‘building from scratch’ section, very easy to follow with the example you used.

On layers, it should probably also be mentioned it is best to keep large layers toward the end of a Dockerfile or config file; don’t layer1 copy in a 100Mb datafile then layer2 install a package then layer3 add a user or all three layers would have that datafile. Add the user then the package then the 100Mb database and you have saved 200Mb in your final container image; order is important. Or you could docker-squash and as I am also going to do investigate the ‘podman build –layers=false’ option Rob mentioned.

## Daniel Schier

For squashing layers you can use the option

or

, which is available by default for podman build and buildah.

## Diogo Lopes

Very Good

## langdon

Minor complaint. I think you have a “typo” in the final script. You say “nginx” in the comments when I think you meant “httpd” (or apache). I was confused for a minute so others might be as well. Otherwise, nice article.

## Gregory Bartholomew

Thanks langdon. I have made the correction.

## laolux

Thanks for the article. I really like the from scratch method using buildah. Now I would like to improve on that by reusing the system’s dnf metadata cache. Any idea of how to accomplish that? Otherwise any user on my system would have to download all the metadata just for himself.

Another point: When using the btrfs backend for podman, then regular users need to execute the script with

. Then it works fine though.

## Mohamed Amin

Thanks for the article. I would think of using buildah for building containers.

I pulled apache default and alpine image from docker hub and I found this:

docker.io/library/httpd alpine a4d0bee07118 8 days ago 57 MB

docker.io/library/httpd latest 0b932df43057 13 days ago 142 MB

Why the alpine image here is so small?

## Daniel Schier

Hi, this is an easy/not so easy to answer question.

Alpine is very focused on minimalism. Therefore, it replaced and stripped important packages, which are common in other Linux systems. For example, you will not have gcc/glibc, but musl libc/gcc. But this also means, that you have to build software differently and may not be able to use certain software at all.

## xhtml

useful article. thanks. 😀

Podman tutorial – How to install XAMPP server in Podman container?

## Daniel Schier

Since XAMPP was the idea to get LAMP on Windows without knowing how to install Apache, MySQL, PHP, etc. I would suggest using each of these tools in a container is the proper way. At least I am considering XAMPP “a bunch of tools for mere testing only”. Using httpd or MariaDB in a container is a piece of cake with containers 🙂

## Shaun McFee

Could multi-stage builds be used within the Containerfile itself to achieve what the bash script of Buildah commands is doing in order to keep the Containerfile as the single source of truth for how the container was built? Is there an advantage to the bash script with Buildah approach versus multi-stage builds?

## Andrea R

I was going to ask this exactly, it’s what I do with docker and it’s clean and easy enough.

## Daniel Schier

Multi-Stage builds can be done, too. Sometimes these are very useful. If you want to use the “from scratch” method in addition to multi-stage, you can also stick to “from scratch”.

Nevertheless, this article explains the capabilities of buildah with regards to both: https://www.redhat.com/en/blog/unleash-powerful-linux-container-building-capabilities-buildah

## SergMx

I’m sorry.

Doesn’t Fedora have a similar project: https://www.redhat.com/en/blog/introducing-red-hat-universal-base-image

?

## Scott McCarty

You can use UBI on Fedora. UBI is supposed to sort of be universal, can be used on Fedora or even other Linux distros.

Also, UBI micro will come out with RHEL 8.4 and that is even smaller than the minimal image with microdnf

## Daniel Schier

Last time I used UBI on Fedora/CentOS (a year ago maybe), it requested a subscription. Is this still the case?

## Lee Whitty

Great article! I just went through this exercise using Fedora 34 images. They must have reduced the minimal image size because the podman build using the minimal image was smaller (154 MB) than the buildah build (155 MB).

## Lee Whitty

Correction: Both the minimal image size build and buildah builds were smaller under Fedora 34, with the Buildah build being the smallest. I like the trend of the container image sizes shrinking!