createrepo_c 与 repodata
一句话总结
createrepo_c 会扫描 rpm 目录并生成 repodata/。其中的 repomd.xml 是指向其他元数据文件的目录。
为什么需要这样做
仅仅把 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 更新元数据。