Podman Quadlet: Build units 详解
1. First | 序
[Build] 单元将容器镜像的构建过程(即 podman build 命令的执行)抽象为一个可被其他 systemd 服务依赖的一次性系统任务。当一个 .container 单元声明其依赖于一个由 .build 单元构建的镜像时,systemd 会自动确保在启动容器服务之前,首先执行并成功完成对应的镜像构建服务。
以下示例定义了一个构建服务和一个依赖于它的容器服务:
- my-app.build
[Unit]
Description=Build the my-app container image
[Build]
ImageTag=localhost/my-app:latest
File=Containerfile
SetWorkingDirectory=unit
- my-app.container
[Unit]
Description=Run the my-app container
Requires=my-app.build
After=my-app.build
[Container]
Image=localhost/my-app:latest
[Install]
WantedBy=default.target
在此场景中,my-app.container 单元通过 Requires=my-app.build 和 After=my-app.build 明确声明了其启动前必须成功完成 my-app.build 服务。当管理员执行 systemctl start my-app.container 时,systemd 的依赖解析器会自动首先触发 my-app.build 服务。该服务会执行 podman build,使用 unit 目录下的 Containerfile 构建出 localhost/my-app:latest 镜像。只有在构建成功后,my-app.container 服务才会启动,从而确保了容器始终运行在最新构建的镜像之上。
2. .Build options
[Build] 单元提供了丰富的配置选项,几乎完整覆盖了 podman build 命令行的所有功能。这些选项可以被逻辑地划分为几个类别,以满足不同的构建需求。
2.1. 核心构建指令
这些选项是定义构建任务基础的必备元素,用于指定构建上下文(context)、Dockerfile 的位置以及最终生成镜像的标签。
ImageTag=
- 描述: 指定构建成功后赋予最终镜像的名称和标签。
- Podman 等效命令: --tag=localhost/imagename
- 使用场景: 这是构建镜像最核心的步骤之一,用于为生成的镜像命名,以便后续被 .container 单元或其他工具引用。例如,ImageTag=my-app:1.0。
- 注意事项: 此选项可多次使用,为同一个镜像赋予多个标签。当其他 Quadlet 单元引用此 .build 文件时,将使用第一个 ImageTag 指定的名称作为依赖的镜像名。
File=
- 描述: 指定用于构建镜像的 Containerfile(或 Dockerfile)的路径。
- Podman 等效命令: --file=/path/to/Containerfile
- 使用场景: 当你的 Containerfile 不在构建上下文的根目录,或者有特殊的命名时,需要使用此选项明确指定其位置。它也支持使用 http(s):// URL 来指定一个远程的 Containerfile。
- 注意事项: 如果提供了相对路径或远程 URL,必须同时设置 SetWorkingDirectory= 来为 podman build 提供有效的构建上下文目录。此选项是 .build 文件中的强制性选项,除非已设置 SetWorkingDirectory= 或在单元文件中直接定义了 [Service] 组的 WorkingDirectory 字段。
SetWorkingDirectory=
- 描述: 为 podman build 提供构建上下文(context)目录。
- Podman 等效命令: podman build [OPTIONS] CONTEXT 命令中的 CONTEXT 位置参数。
- 使用场景: 用于指定 podman build 命令执行时的工作目录,所有在 Containerfile 中的 COPY 或 ADD 等指令的相对路径都基于此目录。支持本地路径、URL(用于克隆 Git 仓库或下载归档文件),以及两个特殊值:file(使用 File= 选项所在文件的父目录)和 unit(使用 .build 单元文件所在的目录)。
- 注意事项: 提供构建上下文目录是强制性的,除非已经设置了 File= 选项。当设置为 file 或 unit 时,Quadlet 会相应地设置生成的 .service 文件的 WorkingDirectory 字段。
Target=
- 描述: 在多阶段构建(multi-stage build)的 Containerfile 中,指定构建到哪一个特定的阶段。
- Podman 等效命令: --target=my-app
- 使用场景: 当你只需要构建出一个用于开发或测试的中间阶段镜像,而不是最终的生产镜像时,此选项非常有用。例如,在一个包含 builder 和 production 两个阶段的 Containerfile 中,设置 Target=builder 可以仅构建出包含编译工具和调试信息的开发镜像。
2.2. 镜像元数据配置
这些选项用于向最终生成的镜像中注入标签、注解和环境变量等元数据,以增强镜像的可追溯性、配置灵活性和文档化。
Annotation=
- 描述: 为生成的镜像添加 OCI 注解(annotation)。注解是以键值对形式存在的元数据。
- Podman 等效命令: --annotation=annotation=value
- 使用场景: 用于存储非结构化的元数据,如构建时间、版本控制信息或镜像描述。例如 Annotation=io.example.build.commit=a1b2c3d。
- 注意事项: 此选项可多次使用。
Label=
- 描述: 为生成的镜像添加标签(label)。标签也是键值对形式的元数据。
- Podman 等效命令: --label=label
- 使用场景: 用于向镜像添加可被其他工具查询和使用的结构化元数据,例如维护者信息、版本号等。例如 Label=maintainer="[email protected]"。
- 注意事项: 此选项可多次使用。
Environment=
- 描述: 为最终生成的镜像设置默认的环境变量。
- Podman 等效命令: --env foo=bar
- 使用场景: 用于定义镜像在运行时默认使用的环境变量,例如 Environment=APP_ENV=production。这等同于在 Containerfile 中使用 ENV 指令。
- 注意事项: 格式与 systemd 服务的格式相同,可以多次使用。
2.3. 构建环境与网络
这些选项用于配置 podman build 执行 RUN 指令时的临时构建容器的环境,包括网络设置、DNS解析和挂载卷,以满足复杂的构建依赖需求。
Network=
- 描述: 为执行 RUN 指令的构建容器设置网络命名空间配置。
- Podman 等效命令: --network=host
- 使用场景: 当 RUN 指令需要访问主机网络(Network=host)或者在没有网络的沙箱环境中执行(Network=none)时使用。也可以依赖于由 .network Quadlet 单元定义的自定义网络。
- 注意事项: 如果值以 .network 结尾,Quadlet 会自动添加对相应网络服务的依赖。如果找到对应的 .network 单元,Quadlet 会查找其中定义的网络名称,否则将默认使用 systemd-$name。生成的服务将依赖于为该 .network 单元生成的服务单元;即使找不到该单元文件,也会尝试依赖 $name-network.service。此选项可多次使用。
DNS=
- 描述: 为构建容器设置自定义的 DNS 服务器。
- Podman 等效命令: --dns=192.168.55.1
- 使用场景: 当构建过程需要访问特定内部网络中的资源,而这些资源需要通过特定的 DNS 服务器进行解析时使用。
- 注意事项: 此选项可多次使用。
DNSOption=
- 描述: 为构建容器设置自定义的 DNS 选项。
- Podman 等效命令: --dns-option=ndots:1
- 使用场景: 用于微调构建容器内的 DNS 解析行为,例如 DNSOption=ndots:1。
- 注意事项: 此选项可多次使用。
DNSSearch=
- 描述: 为构建容器设置自定义的 DNS 搜索域。
- Podman 等效命令: --dns-search example.com
- 使用场景: 当构建过程中需要频繁访问某个域下的多个主机时,设置搜索域可以简化主机名的书写。使用 DNSSearch=. 可以移除搜索域。
- 注意事项: 此选项可多次使用。
Volume=
- 描述: 在执行 RUN 指令期间,为构建容器挂载一个卷。
- Podman 等效命令: --volume /source:/dest
- 使用场景: 当构建过程需要访问主机上的文件(如缓存、配置文件)或依赖于由 .volume 单元创建的命名卷时使用。
- 注意事项: 格式为 [[SOURCE-VOLUME|HOST-DIR:]CONTAINER-DIR[:OPTIONS]]。如果源路径以 . 开头,Quadlet 会解析为相对于单元文件的路径。如果源以 .volume 结尾,则会自动添加对相应卷服务的依赖。如果找到对应的 .volume 单元,Quadlet 会查找其中定义的卷名称,否则将默认使用 systemd-$name。生成的服务将依赖于为该 .volume 单元生成的服务单元;即使找不到该单元文件,也会尝试依赖 $name-volume.service。此选项可多次使用。
2.4. 安全与认证
这些选项专注于处理构建过程中的安全和身份验证问题,例如访问私有镜像仓库、处理 TLS 证书以及安全地传递密钥。
AuthFile=
- 描述: 指定用于访问私有镜像仓库的认证文件的路径。
- Podman 等效命令: --authfile=/etc/registry/auth.json
- 使用场景: 当基础镜像位于需要登录的私有仓库时,此选项用于提供 podman build 所需的认证凭据。
TLSVerify=
- 描述: 控制在联系镜像仓库时是否需要 HTTPS 和验证证书。
- Podman 等效命令: --tls-verify=false
- 使用场景: 在与使用自签名证书或不安全的私有仓库交互时,可以设置为 false 来禁用 TLS 验证。在生产环境中应谨慎使用。
Secret=
- 描述: 提供一种将密钥安全注入构建环境的机制。这些密钥通过临时挂载(--mount=type=secret...)可用于 RUN 指令,但绝不会被提交到最终镜像的任何层中,从而有效防止凭据泄露。
- Podman 等效命令: --secret=id=mysecret,src=path
- 使用场景: 用于在 RUN 指令中安全地使用敏感信息(如 API 密钥、密码),通常与 Containerfile 中的 RUN --mount=type=secret... 指令配合使用。
- 注意事项: 格式通常为 secret[,opt=opt ...]。
GroupAdd=
- 描述: 为在构建容器内运行进程的主用户分配额外的组。
- Podman 等效命令: --group-add=keep-groups
- 使用场景: 当 RUN 指令需要特定的组权限来访问文件或执行操作时使用。支持 keep-groups 特殊标志。
ContainersConfModule=
- 描述: 加载指定的 containers.conf(5) 模块文件。
- Podman 等效命令: --module=/etc/nvd.conf
- 使用场景: 用于应用特定的 Podman 配置,例如为构建过程定制存储驱动、网络设置或其他运行时参数,而无需修改全局配置文件。
- 注意事项: 此选项可多次使用。
2.5. 平台与性能调优
这些选项允许用户针对特定硬件平台进行交叉编译,并对构建过程进行性能优化。
Arch=
- 描述: 覆盖要构建的镜像的体系结构,默认为主机的体系结构。
- Podman 等效命令: --arch=aarch64
- 默认值: 主机体系结构。
- 使用场景: 用于交叉编译,例如在 x86_64 主机上构建一个 aarch64 架构的镜像。
Variant=
- 描述: 覆盖要构建的容器镜像的默认体系结构变体。
- Podman 等效命令: --variant=arm/v7
- 使用场景: 当目标体系结构有多种变体时(如 ARMv7, ARMv8),用于指定具体的变体。
ForceRM=
- 描述: 控制是否在构建后始终移除中间层容器,即使构建失败。
- Podman 等效命令: --force-rm=false
- 使用场景: 默认情况下 (true),Podman 会清理中间容器以节省空间。在调试构建问题时,可以设置为 false 来保留失败步骤的中间容器,以便进入其中进行排查。
2.6. 镜像拉取
这些参数定义了镜像拉取策略、重试次数以及其间隔时间
Pull=
- 描述: 设置镜像拉取策略。
- Podman 等效命令: --pull never
- 使用场景: 控制 podman build 在构建前如何处理基础镜像。可选值包括 always(总是尝试拉取新版本)、never(从不拉取,只使用本地镜像)、missing(仅当本地不存在时拉取)。Pull=never 可用于确保可复现的离线构建。
Retry=
- 描述: 在拉取镜像时,当遇到 HTTP 错误时重试的次数。
- Podman 等效命令: --retry=5
- 使用场景: 在网络不稳定的环境中,增加重试次数可以提高基础镜像拉取的成功率。
RetryDelay=
- 描述: 两次重试之间的延迟时间。
- Podman 等效命令: --retry-delay=10s
- 使用场景: 配合 Retry 选项使用,设置一个合理的延迟可以避免因过快重试而持续失败。
Thanks & Copy
podman-systemd.unit - systemd units using Podman Quadlet