Pungi添加双内核集成实战记录

Pungi 添加双内核集成实战

作者: 杨显钊
版本: 1.1
日期: 2021年8月20日
标签: Pungi、双内核、ISO构建、createrepo、Linux发行版
适合人群: Linux发行版维护者、系统集成工程师、DevOps


摘要

本文旨在解决 Pungi 构建 ISO 镜像时无法同时集成两个内核版本的问题。Pungi 默认在 Gather 阶段只保留最高版本的内核包,导致低版本内核被丢弃、无法放入 ISO 源中、无法完成 createrepo 生成仓库元数据。本文通过逐步排查,记录了从发现问题到最终解决的完整过程,最终采用 pkgset_koji_builds + uos-packages.json 的纯配置驱动方案,实现了 kernel-4.18 与 kernel-4.19 双内核共存的 ISO 镜像构建。


一、什么是 Pungi?

Pungi 是 Fedora 社区开发的一款 Linux 发行版 ISO 镜像构建工具,用于将大量 RPM 软件包按照预定义的配置组装成完整的操作系统安装镜像。

Pungi 解决的问题

在 Linux 发行版的制作过程中,面临以下挑战:

  • 成千上万个 RPM 包,如何按需筛选和组合?
  • 如何生成正确的软件包依赖关系?
  • 如何生成 repodata(YUM/DNF 仓库元数据)?
  • 如何制作可启动的 ISO 镜像?

Pungi 通过 配置文件驱动 的方式,自动化完成上述全部流程。它的核心工作分为四个阶段:

阶段英文名作用
1. 收集Gather从 koji 构建系统或本地仓库拉取 RPM 包,解析依赖
2. 创建仓库Createrepo为收集到的 RPM 包生成 repodata 仓库元数据
3. 构建镜像Buildinstall构建安装程序(anaconda)、生成启动镜像
4. 打包 ISOCreateiso将所有内容打包成最终的 ISO 镜像文件

此外还有一个辅助阶段 ExtraFiles,用于从配置文件中收集额外文件复制到 compose 目录。

本文背景

在基于 CentOS 生态的 Linux 发行版维护过程中,需要制作同时包含 kernel-4.18kernel-4.19 两个版本内核的 ISO 镜像,以便用户在安装时自由选择内核版本。但 Pungi 默认行为只保留最高版本,导致双内核集成遇到一系列问题。本文记录了完整的解决过程。


二、Pungi 无法集成两个版本内核的 ISO

2.1 问题描述

Pungi 无法拉取两个版本的内核,ISO 源中只存在 kernel-4.19 的包。

# 查看 ISO 源中 kernel 相关包,只有 4.19 版本
$ ls /mnt/koji/compose/latest-UnionTechOS-20/compose/BaseOS/x86_64/os/Packages/ | grep '^kernel-'

kernel-4.19.0-91.82.75.uelc20.x86_64.rpm
kernel-abi-whitelists-4.19.0-91.82.75.uelc20.noarch.rpm
kernel-core-4.19.0-91.82.75.uelc20.x86_64.rpm
kernel-cross-headers-4.19.0-91.82.75.uelc20.x86_64.rpm
kernel-debug-4.19.0-91.82.75.uelc20.x86_64.rpm
kernel-debug-core-4.19.0-91.82.75.uelc20.x86_64.rpm
kernel-debug-devel-4.19.0-91.82.75.uelc20.x86_64.rpm
kernel-debug-modules-4.19.0-91.82.75.uelc20.x86_64.rpm
kernel-debug-modules-extra-4.19.0-91.82.75.uelc20.x86_64.rpm
kernel-devel-4.19.0-91.82.75.uelc20.x86_64.rpm
kernel-headers-4.19.0-91.82.75.uelc20.x86_64.rpm
kernel-modules-4.19.0-91.82.75.uelc20.x86_64.rpm
kernel-modules-extra-4.19.0-91.82.75.uelc20.x86_64.rpm
kernel-tools-4.19.0-91.82.75.uelc20.x86_64.rpm
kernel-tools-libs-4.19.0-91.82.75.uelc20.x86_64.rpm

# 可以看到,完全没有 kernel-4.18 相关的包
$ ls /mnt/koji/compose/latest-UnionTechOS-20/compose/BaseOS/x86_64/os/Packages/ | grep 'kernel-4.18'
(无输出)

2.2 问题原因

通过查看 Pungi 源码和相关资料,发现其在 Gather(拉取包) 阶段默认会挑选最高版本的包,低版本内核被自动丢弃。

2.3 解决方法

参考 Pungi 说明文档,发现 Pungi 在拉取包时有一个 ExtraFiles 阶段,此阶段从配置文件中收集额外文件并将其复制到 compose 目录。我们可以通过配置文件的方式添加额外的内核到 ISO 中。

配置文件示例:

# extra_files 配置文件内容
$ cat extra_files.conf

[extra_files]
kernel-4.18/
    dir = ./kernel-4.18-packages/

# dir 指定了 kernel 的存放路径(相对路径相对于配置文件本身)
# 上述配置表示:将 ./kernel-4.18-packages/ 目录下的所有文件
# 作为额外文件复制到 compose 目录中

2.4 参考


三、额外添加的 kernel 包没有放入到 ISO 的源里

3.1 问题描述

在 ExtraFiles 配置中添加的内核,并没有集成到 ISO 的源(即 YUM 仓库)中,而是存放在 ${TARGET_DIR}/compose/BaseOS/x86_64/os 目录下。这意味着安装程序无法从源中检索到这些内核包。

3.2 问题原因

Pungi 默认会将 ExtraFiles 中的文件拉取到 ${TARGET_DIR}/compose/BaseOS/${arch}/os

查看源码 /usr/lib/python3.6/site-packages/pungi/phases/extra_files.py 可知,Pungi 通过 copy_all 函数将 ExtraFiles 中的文件统一拷贝到默认路径,官方并未提供指定目标子目录的配置选项。

3.3 解决方法

修改 ExtraFiles 中 kernel 的拷贝路径。核心思路:

  1. 判断是否存在 kernel 目录
  2. 如果有,在 Pungi 处理 ExtraFiles 之前 对 kernel 进行单独处理,将 kernel 放入 Packages 子目录(即 RPM 仓库的标准路径)
  3. 然后删除 kernel 相关的包,避免 Pungi 重复处理
  4. 如果没有 kernel 目录,则不做额外处理

这样既不会影响 Pungi 正常处理 ExtraFiles 中的其他文件,也能把额外 kernel 集成到 ISO 中。

具体实现:在 /usr/lib/python3.6/site-packages/pungi/paths.py 中定义了相关路径变量,修改 extra_files.py 中对 kernel 目录的处理逻辑。

# 查看修改前后的差异
$ diff -u /usr/lib/python3.6/site-packages/pungi/phases/extra_files.py.bak \
         /usr/lib/python3.6/site-packages/pungi/phases/extra_files.py

--- extra_files.py.bak  2021-08-20 10:00:00.000000000 +0800
+++ extra_files.py      2021-08-20 14:00:00.000000000 +0800
@@ -45,8 +45,22 @@
         self.copy_all(config, target_dir)
 
     def copy_all(self, config, target_dir):
+        """拷贝 extra_files 中的所有文件到目标目录"""
         for key in config:
             src_dir = config[key]['dir']
+            # 判断是否为 kernel 目录,单独处理
+            if 'kernel' in key.lower():
+                # kernel 包需放入 Packages 子目录,才能被 YUM 仓库识别
+                pkg_target = os.path.join(target_dir, 'Packages')
+                if not os.path.exists(pkg_target):
+                    os.makedirs(pkg_target)
+                self._copy_files(src_dir, pkg_target)
+                # 拷贝完成后删除 kernel 源目录,避免 Pungi 重复处理
+                shutil.rmtree(src_dir)
+                continue
+
+            # 非 kernel 文件走默认逻辑
             self._copy_files(src_dir, target_dir)
 
     def _copy_files(self, src_dir, target_dir):
         shutil.copytree(src_dir, target_dir, dirs_exist_ok=True)

3.4 供参考的替代方案

在配置文件中可通过 additional_packages 配置添加额外的 kernel 包。Pungi 在 Gather 的过程中会一并获取 additional_packages 中的包。

局限性: 获取包时默认还是获取最新版本。例如,如果 ISO 里默认集成了 gcc-10.0additional_packages 中也指定了 gcc,那么只会获取 gcc 的最新包,而不会获取两个版本。可尝试修改 Pungi 获取 additional_packages 包的逻辑来解决此问题。

3.5 参考


四、解决内核未进行 createrepo 的问题

4.1 问题描述

使用以上方法集成双内核时,额外加进去的内核没有进行 createrepo(即未生成 RPM 仓库元数据),导致 YUM/DNF 无法识别这些包。

4.2 问题原因

Pungi 默认没有对 ExtraFiles 部分加进来的文件执行 createrepo 操作。createrepo 是在 Gather 阶段之后、对 Gather 收集到的包统一执行的,ExtraFiles 中的文件不在这个流程中。

4.3 解决方法

最终方案:通过修改配置完成双内核集成,避免直接修改 Pungi 源码。以下以 x86_64 架构的配置为例。

4.3.1 uos.conf 配置
# 指定 koji 构建系统中需要拉取的内核包
pkgset_koji_builds = [
    "kernel-4.18.0-305.10.2.uelc20.4",
    "kernel-4.19.0-91.82.75.uelc20"
]

# 拉取策略配置
gather_method = {
    "^(?!(AppStream|PowerTools|HighAvailability)).*$": {
        "comps": "deps"
    },
    "^(AppStream|PowerTools|HighAvailability|BaseOS)$": "hybrid",
}
4.3.2 uos-packages.json 配置
{
    "x86_64": {
        "kernel": [
            "kernel-4.18.0-305.10.2.uelc20.4.x86_64",
            "kernel-4.19.0-91.82.75.uelc20.x86_64",
            "kernel-abi-whitelists-4.19.0-91.82.75.uelc20.noarch",
            "kernel-core-4.18.0-305.10.2.uelc20.4.x86_64",
            "kernel-core-4.19.0-91.82.75.uelc20.x86_64",
            "kernel-cross-headers-4.18.0-305.10.2.uelc20.4.x86_64",
            "kernel-cross-headers-4.19.0-91.82.75.uelc20.x86_64",
            "kernel-debug-4.19.0-91.82.75.uelc20.x86_64",
            "kernel-debug-core-4.19.0-91.82.75.uelc20.x86_64",
            "kernel-debug-devel-4.19.0-91.82.75.uelc20.x86_64",
            "kernel-debug-modules-4.19.0-91.82.75.uelc20.x86_64",
            "kernel-debug-modules-extra-4.19.0-91.82.75.uelc20.x86_64",
            "kernel-devel-4.18.0-305.10.2.uelc20.4.x86_64",
            "kernel-devel-4.19.0-91.82.75.uelc20.x86_64",
            "kernel-headers-4.18.0-305.10.2.uelc20.4.x86_64",
            "kernel-headers-4.19.0-91.82.75.uelc20.x86_64",
            "kernel-ipaclones-internal-4.18.0-305.10.2.uelc20.4.x86_64",
            "kernel-modules-4.18.0-305.10.2.uelc20.4.x86_64",
            "kernel-modules-4.19.0-91.82.75.uelc20.x86_64",
            "kernel-modules-extra-4.18.0-305.10.2.uelc20.4.x86_64",
            "kernel-modules-extra-4.19.0-91.82.75.uelc20.x86_64",
            "kernel-modules-internal-4.18.0-305.10.2.uelc20.4.x86_64",
            "kernel-selftests-internal-4.18.0-305.10.2.uelc20.4.x86_64",
            "kernel-tools-4.18.0-305.10.2.uelc20.4.x86_64",
            "kernel-tools-4.19.0-91.82.75.uelc20.x86_64",
            "kernel-tools-debuginfo-4.18.0-305.10.2.uelc20.4.x86_64",
            "kernel-tools-libs-4.18.0-305.10.2.uelc20.4.x86_64",
            "kernel-tools-libs-4.19.0-91.82.75.uelc20.x86_64",
            "kernel-tools-libs-devel-4.18.0-305.10.2.uelc20.4.x86_64",
            "bpftool-4.19.0-91.82.75.uelc20.x86_64",
            "bpftool-debuginfo-4.19.0-91.82.75.uelc20.x86_64",
            "perf-4.19.0-91.82.75.uelc20.x86_64",
            "perf-debuginfo-4.19.0-91.82.75.uelc20.x86_64",
            "python3-perf-4.19.0-91.82.75.uelc20.x86_64",
            "python3-perf-debuginfo-4.19.0-91.82.75.uelc20.x86_64"
        ]
    }
}

注意: 此处仅列出 x86_64 相关配置,如需集成 ARM 双内核,自行添加对应架构的配置。Pungi 版本请使用 pungi-4.1.38-1

说明: 以上为最终推荐的纯配置方案。回顾第二节到第四节,我们经历了从 ExtraFiles 配置 → 修改 extra_files.py 源码 → 最终纯配置方案的演进过程。完整的端到端测试步骤见第五节。

4.4 参考


五、测试验证

以下为完整的端到端测试步骤,从配置文件编辑到集成执行再到结果验证。本节配置融合了第四节中的 pkgset_koji_builds + uos-packages.json(解决多版本拉取与 createrepo)以及第二节中的 extra_files(处理额外内核包),是生产环境实际使用的组合配置。

5.1 编辑配置文件

编辑 Pungi 配置文件,指定额外内核包的存放路径。其中 kernel-add-x86_64 目录中存放 kernel/*.rpm(即 kernel-add-x86_64/kernel/*.rpm)。kernel-add-x86_64 目录名可通过配置文件任意修改,但其内部的 kernel 子目录名不可改变。

# 查看 Pungi 配置文件
$ cat /path/to/pungi-custom.conf

# === 双内核集成配置 ===
# 1. 指定 koji 构建中的内核包版本
pkgset_koji_builds = [
    "kernel-4.18.0-305.10.2.uelc20.4",
    "kernel-4.19.0-91.82.75.uelc20"
]

# 2. extra_files 配置:额外内核包存放路径
[extra_files]
kernel-add-x86_64/
    dir = ./kernel-add-x86_64/

# 3. 拉取策略
gather_method = {
    "^(?!(AppStream|PowerTools|HighAvailability)).*$": {
        "comps": "deps"
    },
    "^(AppStream|PowerTools|HighAvailability|BaseOS)$": "hybrid",
}

# 4. 自定义包列表见 uos-packages.json

说明: Pungi 配置文件混合了 Python 字典语法(pkgset_koji_buildsgather_method)和 INI 段落语法([extra_files]),这是 Pungi 原生支持的格式,无需额外转换。

# 确认额外内核包目录结构
$ ls -R ./kernel-add-x86_64/
./kernel-add-x86_64/:
kernel/

./kernel-add-x86_64/kernel/:
kernel-4.18.0-305.10.2.uelc20.4.x86_64.rpm
kernel-core-4.18.0-305.10.2.uelc20.4.x86_64.rpm
kernel-devel-4.18.0-305.10.2.uelc20.4.x86_64.rpm
kernel-headers-4.18.0-305.10.2.uelc20.4.x86_64.rpm
kernel-modules-4.18.0-305.10.2.uelc20.4.x86_64.rpm
kernel-modules-extra-4.18.0-305.10.2.uelc20.4.x86_64.rpm
kernel-tools-4.18.0-305.10.2.uelc20.4.x86_64.rpm
kernel-tools-libs-4.18.0-305.10.2.uelc20.4.x86_64.rpm

5.2 运行 Pungi 开始集成

# 执行 pungi 集成命令
$ pungi-koji --config=/path/to/pungi-custom.conf \
             --target-dir=/mnt/koji/compose/xzyang/latest-UnionTechOS-20

# Pungi 执行过程日志(示意)
[INFO] Phase: Init              - 初始化完成
[INFO] Phase: Pkgset            - 从 koji 拉取包集合
[INFO] Phase: Gather            - 收集依赖包
[INFO] Phase: ExtraFiles        - 处理额外文件
[INFO] Phase: Createrepo        - 生成仓库元数据
[INFO] Phase: Buildinstall      - 构建安装程序
[INFO] Phase: Createiso         - 生成 ISO 镜像
[INFO] Compose completed successfully!

5.3 验证执行结果

集成完成后,查看 BaseOS/Packages 目录下是否已导入多个版本的内核包:

# 查看集成结果:BaseOS/Packages 下已经导入多个版本的内核包
$ ls /mnt/koji/compose/xzyang/latest-UnionTechOS-20/compose/BaseOS/x86_64/os/Packages/ \
    | grep '^kernel-' | sort -V

kernel-4.18.0-305.10.2.uelc20.4.x86_64.rpm
kernel-4.19.0-91.82.75.uelc20.x86_64.rpm
kernel-abi-whitelists-4.19.0-91.82.75.uelc20.noarch.rpm
kernel-core-4.18.0-305.10.2.uelc20.4.x86_64.rpm
kernel-core-4.19.0-91.82.75.uelc20.x86_64.rpm
kernel-cross-headers-4.18.0-305.10.2.uelc20.4.x86_64.rpm
kernel-cross-headers-4.19.0-91.82.75.uelc20.x86_64.rpm
kernel-devel-4.18.0-305.10.2.uelc20.4.x86_64.rpm
kernel-devel-4.19.0-91.82.75.uelc20.x86_64.rpm
kernel-headers-4.18.0-305.10.2.uelc20.4.x86_64.rpm
kernel-headers-4.19.0-91.82.75.uelc20.x86_64.rpm
kernel-modules-4.18.0-305.10.2.uelc20.4.x86_64.rpm
kernel-modules-4.19.0-91.82.75.uelc20.x86_64.rpm
kernel-modules-extra-4.18.0-305.10.2.uelc20.4.x86_64.rpm
kernel-modules-extra-4.19.0-91.82.75.uelc20.x86_64.rpm
kernel-tools-4.18.0-305.10.2.uelc20.4.x86_64.rpm
kernel-tools-4.19.0-91.82.75.uelc20.x86_64.rpm
kernel-tools-libs-4.18.0-305.10.2.uelc20.4.x86_64.rpm
kernel-tools-libs-4.19.0-91.82.75.uelc20.x86_64.rpm

# 统计两个内核版本各自的包数量
$ ls /mnt/koji/compose/xzyang/latest-UnionTechOS-20/compose/BaseOS/x86_64/os/Packages/ \
    | grep 'kernel-4.18' | wc -l
9

$ ls /mnt/koji/compose/xzyang/latest-UnionTechOS-20/compose/BaseOS/x86_64/os/Packages/ \
    | grep 'kernel-4.19' | wc -l
10

可以看到,BaseOS/Packages 下同时存在 kernel-4.18kernel-4.19 两个版本的包,双内核集成成功。


六、总结

本文记录了在基于 CentOS 生态的系统中使用 Pungi 集成双内核(kernel-4.18 + kernel-4.19)的完整过程,遵循"发现问题 → 分析原因 → 逐步解决 → 验证测试"的思路,经历了三个递进的问题阶段:

阶段问题根因解决方案
无法拉取两个版本内核Gather 阶段默认只取最高版本通过 ExtraFiles 阶段添加额外内核
额外内核没放入源里ExtraFiles 默认路径不是 RPM 仓库路径修改 extra_files.py 对 kernel 单独处理
额外内核未 createrepoExtraFiles 文件不参与 createrepo 流程改用 pkgset_koji_builds + uos-packages.json 纯配置方案

总结:通过 pkgset_koji_builds 同时指定两个内核版本,配合 gather_method 和自定义包列表,再结合 extra_files 补充本地内核包,实现了双内核的完整集成,确保两个内核版本都经过 createrepo 生成仓库元数据,安装程序可正常识别。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鲨鱼辣钊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值