3 个不稳定版本
新 0.3.1 | 2024年8月22日 |
---|---|
0.3.0 | 2024年7月18日 |
0.2.12 | 2023年11月28日 |
#371 在 开发工具
122 每月下载次数
115KB
2K SLoC
rpmoci
rpmoci 从 RPM 软件包构建 OCI 容器镜像,使用 DNF。它本质上是在 dnf install --installroot=/some/rootfs PACKAGE [PACKAGE ...]
的基础上进行容器化的包装。
rpmoci 功能
- 确定的 rpmoci 使用类似 bundler/cargo 等的包文件/锁定文件范式锁定 RPM 依赖关系,可以生成具有相同摘要的可重复镜像。
- 非特权 rpmoci 可以在没有访问容器运行时和在不需要 root 权限的环境中构建镜像(这依赖于用户能够创建 用户命名空间)
- 小型 rpmoci 镜像仅从您请求的 RPM 和其依赖项构建,因此不包含不必要的依赖项。
rpmoci 的设计受到了 apko 和 distroless 工具的影响。
安装
rpmoci 依赖于 dnf 的运行时,因此需要具有 dnf 支持的 Linux 发行版。
rpmoci 可从 crates.io 下载,因此您需要一个 Rust 工具链。您还需要安装 sqlite、python3 和 openssl 开发包(例如,在 Fedora 和 RHEL 衍生产品上安装 sqlite-devel
、python3-devel
和 openssl-devel
)。
然后通过 cargo 安装 rpmoci
cargo install rpmoci
构建
根据上述内容,您需要安装 dnf、Rust、python3-devel 和 openssl-devel。
cargo build
无根设置
当 rpmoci 以非 root 用户运行时,它将自动尝试设置一个用户命名空间来在其中运行。rpmoci 将用户的 uid/gid 映射到用户命名空间中的 root。
它还尝试将当前用户的subuid/subgid范围映射到用户命名空间,这对于rpmoci从包含非root用户所有文件的RPM中创建容器是必需的。
rpmoci要求至少分配999个子uid/subgid给您的用户。您可以在https://rootlesscontaine.rs/getting-started/common/subuid/中创建它们。
入门指南
您需要创建一个rpmoci.toml文件。例如:
[contents] # specifies the RPMs that comprise the image
repositories = [ "mariner-official-base" ]
packages = [
"tini"
]
[image] # specifies image configuration such as entrypoint, ports, cmd, etc.
entrypoint = [ "tini", "--" ]
这配置了rpmoci从mariner-official-base存储库安装tini
及其依赖项,并配置了镜像入口点使用tini
。
然后可以将其构建成镜像
sudo rpmoci build --image tini --tag my-first-rpmoci-image
镜像将创建在名为tini
的OCI布局目录中。rpmoci不处理镜像分发 - 预期用户将使用oras或skopeo之类的工具将镜像推送到注册表。
将创建一个锁文件rpmoci.lock
,以便您可以稍后重新运行构建并获取相同的软件包。前提是它们仍然存在于指定的存储库中... rpmoci支持供应商RPM,因此您可以在不依赖于它们的情况下重复锁定构建
参考
软件包规范
存储库配置
存储库部分定义了RPM的来源。
在入门指南示例中,存储库是通过运行系统上的repo ID指定的。如果您想创建一个可移植的rpmoci.toml
(例如,在Fedora/Ubuntu/Mariner上运行时构建相同的镜像),也可以在rpmoci.toml
中完全指定存储库。
存储库可以通过其基本URL指定
[contents]
repositories = ["https://packages.microsoft.com/cbl-mariner/2.0/prod/base/x86_64"]
或通过包清单文件中的附加配置选项定义(默认为rpmoci.toml
,在CLI上可以通过-f FILE
指定)
[[contents.repositories]]
url = "https://packages.microsoft.com/cbl-mariner/2.0/prod/base/x86_64/"
options = { includepkgs = "foo,bar" }
默认情况下,gpgcheck
和sslverify
被启用 - 可以通过options
字段禁用。
除了通过repo ID显式指定的存储库之外,忽略所有系统存储库。支持dnf插件,但rpmoci不支持指定插件配置。
软件包配置
软件包规范添加到contents.packages
键下。支持本地和远程软件包
[contents]
repositories = ["https://packages.microsoft.com/cbl-mariner/2.0/prod/base/x86_64"]
packages = [
"postgreqsl", # a package from the above repository
"path/to/local.rpm", # a local RPM
]
文档文件
是否将文档文件包含在生成的容器中可以通过content.docs
布尔字段指定。默认情况下不包含文档文件,以优化镜像大小。
GPG密钥配置
GPG密钥可以通过存储库选项或gpgkeys
字段配置
[contents]
repositories = ["https://packages.microsoft.com/cbl-mariner/2.0/prod/base/x86_64"]
gpgkeys = [
"https://raw.githubusercontent.com/microsoft/CBL-Mariner/2.0/SPECS/mariner-repos/MICROSOFT-RPM-GPG-KEY"
]
packages = [
"postgresql"
]
在构建镜像时,将使用配置的GPG密钥验证软件包签名,除非是本地软件包或存储库中的软件包,其中gpgcheck
已显式禁用。
认证RPM存储库
要使用需要HTTP基本身份验证的仓库,在toml文件中指定仓库的id
,并定义环境变量RPMOCI_<id>_HTTP_USERNAME
和RPMOCI_<id>_HTTP_PASSWORD
作为HTTP认证凭据,其中<id>
是仓库id的大写。
例如,使用以下配置,您需要定义环境变量RPMOCI_FOO_HTTP_USERNAME
和RPMOCI_FOO_HTTP_PASSWORD
[[contents.repositories]]
url = "https://packages.microsoft.com/cbl-mariner/2.0/prod/base/x86_64/"
id = "foo"
镜像配置
可以在image
键下指定额外的镜像配置。
[contents]
repositories = ["https://packages.microsoft.com/cbl-mariner/2.0/prod/base/x86_64"]
gpgkeys = [
"https://raw.githubusercontent.com/microsoft/CBL-Mariner/2.0/SPECS/mariner-repos/MICROSOFT-RPM-GPG-KEY"
]
packages = [
"postgresql"
]
[image]
entrypoint = ["tini", "--"]
cmd = [ "foo" ]
exposed_ports = ["8080/tcp"]
[image.envs]
RUST_BACKTRACE = "1"
RUST_LOG = "hyper=info"
上述OCI镜像规范的config
部分映射到rpmoci.toml
中的镜像部分。例如,要指定镜像标签,可以使用image.labels
部分,要指定镜像环境变量,使用image.envs
。
默认情况下,PATH环境变量设置为/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
,但可以通过image.envs
字段进行覆盖。
/etc/os-release
可以通过content.os_release
布尔字段指定/etc/os-release
是否在解析过程中自动包含为依赖项,从而安装到生成的镜像中。这使SBOM和漏洞扫描工具能够更好地确定镜像中软件包的来源。默认情况下,此字段是启用的。
您还可以通过将发行版的<distro>-release
包添加到包数组中包括/etc/os-release
文件:此字段存在是为了确保默认包括/etc/os-release
文件。
弱依赖
rpmoci不会安装弱依赖,优化小型容器镜像的大小。
镜像构建
运行rpmoci build --image foo --tag bar
将构建一个OCI格式的容器镜像。
$ rpmoci build --image foo --tag bar
...
$ cat foo/index.json | jq
{
"schemaVersion": 2,
"manifests": [
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:1ad8cc1866d359e4e2ecb37fcc96759815540f06cb468811dcb9b8aac51da90d",
"size": 350,
"annotations": {
"org.opencontainers.image.ref.name": "bar"
}
}
]
}
然后可以使用OCI工具(如skopeo或oras)复制此镜像。例如,将其复制到本地Docker守护进程
$ skopeo copy oci:foo:bar docker-daemon:foo:bar
Getting image source signatures
Copying blob 77b582c1f09c done
Copying config 577bea913f done
Writing manifest to image destination
Storing signatures
锁文件
rpmoci使用DNF生成构建的锁文件。这可以用作随后通过rpmoci build --locked
重复构建。
可以通过运行rpmoci update
来创建或更新锁文件。
$ rpmoci update
Adding filesystem 1.1-10.cm2
Adding grep 3.7-2.cm2
Adding openssl 1.1.1k-17.cm2
Adding libgcc 11.2.0-2.cm2
Adding postgresql 14.2-2.cm2
Adding libxml2 2.9.14-1.cm2
Adding ncurses-libs 6.3-1.cm2
Adding pcre 8.45-2.cm2
Adding pcre-libs 8.45-2.cm2
Adding glibc 2.35-2.cm2
Adding bash 5.1.8-1.cm2
Adding libsepol 3.2-2.cm2
Adding libcap 2.60-1.cm2
Adding krb5 1.19.3-1.cm2
Adding openldap 2.4.57-7.cm2
Adding coreutils 8.32-3.cm2
Adding postgresql-libs 14.2-2.cm2
Adding libselinux 3.2-1.cm2
Adding openssl-libs 1.1.1k-17.cm2
Adding readline 8.1-1.cm2
Adding tzdata 2022a-1.cm2
Adding xz-libs 5.2.5-1.cm2
Adding libstdc++ 11.2.0-2.cm2
Adding zlib 1.2.12-1.cm2
Adding e2fsprogs-libs 1.46.5-1.cm2
Adding gmp 6.2.1-2.cm2
Adding bzip2-libs 1.0.8-1.cm2
可重复构建
假设RPMs可以可重复安装(如果涉及具有不可重复安装后脚本的RPMs,rpmoci构建将不会是可重复的),rpmoci可以生成位可重复的容器镜像构建。rpmoci试图从容器镜像中移除非确定性的来源,并尊重SOURCE_DATE_EPOCH环境变量。
当未设置SOURCE_DATE_EPOCH时,OCI镜像配置中的镜像创建时间设置为当前时间。在这种情况下,rpmoci仍然会从镜像中删除非确定性数据,并且可以通过设置SOURCE_DATE_EPOCH为镜像的创建时间(通过将镜像配置中的时间戳转换为自Unix纪元以来的秒数)来在以后重现构建。
此功能仅在Mariner Linux上进行了测试,但当rpmoci在将rpmdb作为sqlite数据库写入/var/lib/rpm/rpmdb.sqlite
的任何Linux发行版上运行时,应能正常工作。
供应商
可以使用rpmoci vendor
将RPMs供应商到文件夹中。可以在构建期间使用供应商文件夹以避免接触软件包仓库。
$ rpmoci vendor --out-dir vendor
$ ls vendor
ls vendor
031e779a7ce198662c5b266d7b0dfc9eece9c0c888a657b6a9bb7731df0096d0.rpm 8ea3d75dbb48fa12eacf732af89a600bd97709b55f88d98fe129c13ab254de95.rpm
...
$ rpmoci build --image foo --tag bar --vendor-dir vendor
由于rpmoci当前尝试从供应商目录安装所有RPMs,因此来自不同调用rpmoci vendor
的供应商目录应保持隔离。
SBOM支持
rpmoci没有原生SBOM支持,但由于它仅使用标准OS包功能,因此可以使用trivy和syft等SBOM生成器生成生成图像的SBOM。
开发
rpmoci是用Rust编写的,目前通过嵌入的Python模块使用DNF解析RPMs。
它依赖于python3-devel
和openssl-devel
。
检出项目后,您可以执行以下操作
cargo run
来运行它,或使用cargo-generate-rpm构建RPM
cargo generate-rpm
测试
测试是通过cargo test
运行的。在tests/it.rs
中的集成测试运行rpmoci build
,因此必须以root权限运行,或者已设置用户命名空间支持。
测试使用test-temp-dir,因此可以将TEST_TEMP_RETAIN
环境变量设置为1
,以便在<CARGO_TARGET_DIR>/tests
中进行调试时保留测试目录。
依赖关系
~57MB
~1M SLoC