zzxworld

使用 Podman 和 Buildah 制作容器镜像

自去年发了这篇《Podman 安装和使用初体验》的文章后,我就在开发环境上开始了 Docker 到 Podman 的切换之旅。经过这几个月的实际体验,暂未发现任何不适或异常。作为使用的总结记录,今天就来分享一下使用 Podman 制作容器镜像的过程。

使用 Dockerfile

Podman 是一个高度兼容 Docker 的容器引擎和管理工具。所以使用 Podman 时同样也可以继续使用之前的 Dockerfile 镜像构建配置文件。

比如有这样一份自定义 PHP 镜像的构建配置文件:

FROM php:8.1-fpm

RUN sed -i \
    "s@http://\(deb\|security\).debian.org@https://mirrors.aliyun.com@g" \
    /etc/apt/sources.list
RUN apt update -y
RUN apt install -y libpng-dev libjpeg-dev libfreetype-dev
RUN docker-php-ext-configure gd --with-freetype --with-jpeg
RUN docker-php-ext-install gd

如果使用 Podman 来构建这份镜像配置,只需要运行以下命令:

podman build -t localhost/php .

是不是和 Docker 的 build 命令看起来别无二致?

关于 Podman 这个 build 命令的详细的参数说明和示例,可以通过查阅它的官方文档来了解更多:

podman-build — Podman documentationBuild a container image using a Containerfile.docs.podman.io

点进这个链接,会在命令描述的部分看到这样一段话:

NOTE: podman build uses code sourced from the Buildah project to build container images.This Buildah code creates Buildah containers for the RUN options in container storage. ...

由此可知,Podman 提供的 build 命令来自于一个叫 Buildah 的项目。既然如此,那就看看 Buildah 是如何构建镜像的。

使用 Buildah

作为 Podman 这个容器引擎的好搭档,Buildah 的用途非常纯粹,就是专门用来构建镜像的工具。至于 Buildah 和 Dockerfile 构建镜像的区别,下面会直接通过构建过程来展现。相信看完这个完整的过程后就会有自己的答案。

BuildahA tool that facilitates building OCI container images.buildah.io

使用之前需要先安装,在 Arch Linux 上的安装命令如下:

sudo pacman -S buildah

使用其他 Linux 系统只要把 pacman 替换为系统对应的包管理命令即可。

同样还是以构建上面的 PHP 镜像举例。首先打开命令窗口,输入以下命令定义一个基础来源镜像:

container=$(buildah from php:8.1-fpm)

按回车键执行命令,会开始拉取基础镜像。

2022-03-21-20-04-58-image

接下来修改基础镜像中的软件源镜像地址:

buildah run $container sed -i "s@http://\(deb\|security\).debian.org@https://mirrors.aliyun.com@g" /etc/apt/sources.list

注意命令中的 $container,它是一个变量,代表目前 buildah 命令操作的容器对象。这也是和使用 Dockerfile 构建镜像时最显著的区别。主要有两点:

  1. 代表这个基础镜像目前是运行状态的,它并没有因为一行命令执行结束而终止。
  2. 意味着使用 Buildah 构建镜像是交互式的,而不是像 Dockerfile 那样必须每次调整一下配置都必须从头开始构建。
  3. 再也不用担心 Dockerfile 使用构建命令时的「分层」问题。

回到未完成的构建过程上来:

buildah run $container apt update -y
buildah run $container apt install -y libpng-dev libjpeg-dev libfreetype-dev
buildah run $container docker-php-ext-configure gd --with-freetype --with-jpeg
buildah run $container docker-php-ext-install gd

上面的构建命令随时可以根据需要进行回测或重试,而不必重新从第一条命令逐条开始。这在入手不熟悉的基础镜像时,带来了极大的便捷性和自由度。所以我在首次使用 Buildah 构建完一个镜像后,就再也回不到 Dockerfile 方式了。

在最终完成镜像的所有设置和清理工作后,就可以通过下面的命令来提交镜像:

buildah commit $container php:8.1-fpm-with-gd

命令执行完成后,就可以使用 podman images 来查看并使用新构建的自定义镜像了。

使用 buildah ps 可以查看还在运行中的基础镜像。

2022-03-21-20-23-32-image

在确定构建的新镜像没有问题后,可以通过 buildah rm 命令来删除这些运行中的基础镜像。这样使用 Buildah 构建一个镜像的过程就完成了。因为是基于 Shell 命令的构建流程,所以也可以把这个过程中的命令整理到一个脚本文件中:

#!/bin/sh

set -x

container=$(buildah from php:8.1-fpm)

buildah run $container sed -i "s@http://\(deb\|security\).debian.org@https://mirrors.aliyun.com@g" /etc/apt/sources.list
buildah run $container apt update -y
buildah run $container apt install -y libpng-dev libjpeg-dev libfreetype-dev
buildah run $container docker-php-ext-configure gd --with-freetype --with-jpeg
buildah run $container docker-php-ext-install gd

buildah commit $container php:8.1-fpm-with-gd
buildah rm $container

下载再构建这个镜像时,就只需要执行一下这个 Shell 脚本。这样就跟 Dockerfile 有异曲同工之妙了。因为用的是 Shell 脚本,所以在可控制性,灵活性和自由度上,我觉得更高一筹。

另外 Buildah 不依赖于 Podman,所以即便使用的是 Docker,也可以尝试一下这个灵活的镜像构建工具。