LabHub
学习 学习路径 课程

RHEL 系管理

createrepo_c 与 repodata

在 LabHub 中继续学习

一句话总结

createrepo_c 会扫描 rpm 目录并生成 repodata/。其中的 repomd.xml 是指向其他元数据文件的目录。

概念图: 生成 repodata/ · 全部文件 · 防止中间代理或 CDN 返回过期副本。 · 默认为 sha256

为什么需要这样做

仅仅把 RPM 文件复制到目录中,并不能使其成为 dnf 软件仓库。dnf 不会每次都 打开所有软件包,而是查询 repodata 中的版本、依赖关系和文件列表。因此, 添加软件包后如果不更新元数据,服务器上的实际文件就会与客户端看到的 列表不一致。理解这种差异后,才能区分缓存或权限问题与遗漏仓库生成步骤的问题。

它是如何工作的

dnf install -y createrepo_c
createrepo_c /srv/repo/labhub

ls -1 /srv/repo/labhub/repodata/
# repomd.xml
# <checksum>-primary.xml.gz
# <checksum>-filelists.xml.gz
# <checksum>-other.xml.gz
文件 内容
repomd.xml 目录,记录各元数据的位置、校验和与时间
primary 名称、版本、依赖关系与摘要
filelists 软件包中包含的全部文件列表
other 变更日志

之所以能通过 dnf provides '*/nginx.conf' 进行基于文件的搜索,依靠的正是 filelists

文件名前面的校验和前缀是 --unique-md-filenames(默认值)产生的结果。它能防止中间代理或 CDN 返回过期副本。 文件名会随内容改变,缓存因此不会混淆不同版本。

主要选项

选项 文档规定的行为
--update “依据文件大小和 mtime,为没有变化的 rpm 复用已有元数据”
--workers N 读取 rpm 的工作进程数量
-g, --groupfile 包含 comps 组文件
-s, --checksum repomd 与软件包所用的校验和类型,默认为 sha256
--compress-type bz2、gz、zck、zstd、xz
-i, --pkglist 指定要包含的软件包列表文件
--retain-old-md N 要保留的旧版 repodata 数量
-x, --excludes 排除模式

-d/--database(生成 sqlite)已经弃用。如果在旧操作手册中看到这个选项,可以将其删除。

--pkglist 与清单关联起来是一项良好实践。 直接把导入清单用作 pkglist,就能从结构上防止清单与实际仓库不一致。

更新

添加软件包后,必须重新生成元数据。

createrepo_c --update /srv/repo/labhub
dnf clean expire-cache
dnf repolist

遗漏 --update 是隔离网络中最常见的报障原因。 文件明明看得见,dnf 却不知道它的存在。

repo 文件与验证

[labhub-local]
name=LabHub local (snapshot 2026-08-20)
baseurl=file:///srv/repo/labhub
enabled=1
gpgcheck=0
metadata_expire=-1

需要确认以下三类行为。

dnf repolist -v
dnf repoclosure --repo=labhub-local
dnf install --assumeno <패키지>

dnf repoclosure列出依赖关系无法在仓库内部得到满足的软件包。 它是用作导入前检查门禁的最佳工具。

createrepo_c /srv/bundle/rpms
dnf repoclosure --repofrompath=bundle,/srv/bundle/rpms --repo=bundle

--repofrompath 无需创建 .repo 文件就能临时指定仓库,在验证脚本中非常实用。

清理旧软件包

dnf repomanage --old --keep 2 /srv/repo/labhub
dnf repomanage --old --keep 2 /srv/repo/labhub | xargs -r rm -v
createrepo_c --update /srv/repo/labhub

保留多少个版本,就决定了能够回滚多远。 如果每月导入一次并保留 3 个版本,就能回滚到大约 3 个月内的版本。

实际工作中会遇到的情况

在仓库显示名称中写入快照日期。name=... (snapshot 2026-08-20) 这样标明日期,六个月后只需查看 dnf repolist -v 的一行输出,就能确定仓库对应的时间点。

下一个实验要做什么

收集 rpm,用 createrepo_c 创建仓库,编写 .repo 文件,只启用这个仓库完成安装,然后添加软件包并通过 --update 更新元数据。