刚把一个 RHEL 9.4 的离线机房环境从零配到能批量装 Oracle 19c,期间最让我头疼的就是“安装包怎么缓存下来”这件事。网上搜“RHEL 9.X缓存安装包”的人,多半是遇到了同样的场景:生产网段隔离、内网环境不允许随便连外网源、要批量初始化几十台机器,或者单纯想避免每次重装系统都重新下载那几个 G 的 ISO 和 RPM。这篇文章把我实际踩过的坑、试过可行的方案、还有那些文档里不会写的细节整理出来,给正在搞 RHEL 9.X 缓存仓库和离线部署的朋友一个可以直接抄作业的参考。
先把话说明白:这里说的“缓存安装包”,不是指浏览器缓存、也不是 redis 那种业务缓存,而是 RPM 安装包的本地化沉淀。核心无非三件事——把 RHEL 9.X 的 ISO 变成本地 yum/dnf 源,把远端仓库同步成离线目录,再把这些目录挂到内网机器上作为标准安装源。另外还会涉及 dnf 本身的包缓存机制、增量同步策略、以及 Oracle 19c 这类大型软件在离线环境下的依赖安装问题。这些内容适合 Linux 运维、实施工程师、以及需要在隔离网络里做系统交付的同行参考。
1. RHEL 9.X 的 dnf 缓存机制,先搞清楚再动手
1.1 dnf 和 yum 的关系,以及缓存到底存在于哪些层面
RHEL 9.X 已经彻底用 dnf 替换了 yum,虽然你还是能敲yum命令,但本质上它只是个指向 dnf 的兼容别名。dnf 和 yum 相比,底层依赖解析用的是 libsolv,速度更快,处理复杂依赖关系时更稳定,同时对 repo 元数据(repomd.xml 那套)的处理方式也更规范。这意味着你在网上看到的很多老教程里关于 yum 缓存目录、yum clean all的用法虽然大多还通用,但有了细微差别,比如缓存数据库的存储路径和格式就有变化。
在实际操作中,我建议你把“缓存安装包”这件事拆成三个层面看待:
dnf 自身的包缓存:也就是默认放在
/var/cache/dnf下的仓库元数据(metadata)和下载的 RPM 文件。这个缓存是“边下载边留底”的临时性缓存,设计初衷是减少同一台机器重复安装时的网络消耗,但它不是为多机共享设计的。本地仓库:你自己维护的目录结构,包含
repodata元数据和一堆 RPM 文件,通过createrepo_c生成元数据后,用 HTTP、NFS 或者本地路径提供给客户端使用。这才是“离线安装包缓存”真正要落地的形态。应用层安装包:比如 JDK 17 的 tar.gz、Oracle 19c 的 zip 包、以及各种
.bin格式的安装器。这些不属于 RPM 体系,但要跟 RPM 依赖放到同一个离线交付目录里管理。
搞清楚这三层,后面做的每一步都有明确目标了。很多人一上来就dnf install,根本没意识到系统已经下载并缓存了 RPM,后面又来问“怎么让其他机器不重新下载”,其实只需要把缓存目录转成 repo 就行。
1.2 你真的需要缓存安装包吗?判断依据
不是所有环境都需要搭一套复杂的离线缓存仓库。我见过不少团队为了内网装几台机器,花了大半天同步几个 G 的 RPM,结果一年也用不到几次。所以在动手之前,先算一笔账:
- 如果只是偶尔装一台机器,直接用 ISO 挂载做本地源就够了,成本最低。
- 如果用 RHEL 9.X 部署超过 3 台机器,且这些机器的软件版本必须一致,那就有必要做本地仓库。
- 如果网络隔离是常态,比如军工、电力、金融这种等保要求高的内网环境,那离线仓库基本是刚需。
- 如果机器数量多、需要频繁装系统或扩容,除了仓库,你还需要考虑 Kickstart 自动化安装和 DHCP/PXE 配合。
顺便说一句,RHEL 9.X 的安装包体积比 RHEL 8 又大了一圈。我手上用的 9.4 ISO 完整镜像 5.2 GB 左右,BaseOS 和 AppStream 两个仓库解压之后大约 9 GB,再把 EPEL 同步下来又要 3 GB 起步。磁盘规划的时候别只盯着仓库目录本身,还要给 createrepo_c 生成元数据留出足够的临时空间,这个后面细说。
2. 用 ISO 搭建最基础的本地安装源
2.1 挂载 ISO 并初始化仓库目录
无论后续要不要做远端同步,第一步都是先把 RHEL 9.X 的安装 ISO 用好。你从官方渠道或者镜像站下载到的 ISO(我用的 9.4 版本),里面其实已经包含了 BaseOS 和 AppStream 两个仓库的 RPM 包,只是平时安装系统时这些包没有留存在磁盘上。把 ISO 挂载出来,就是一个不需要联网的完整本地安装源。
操作步骤如下:
# 创建挂载点和仓库存放目录 mkdir -p /mnt/iso mkdir -p /data/repo/rhel94 # 挂载 ISO(假设 ISO 文件存放在 /data/iso/rhel-9.4-x86_64-dvd.iso) mount -o loop /data/iso/rhel-9.4-x86_64-dvd.iso /mnt/iso # 查看 ISO 内的仓库目录结构 ls /mnt/iso/ ls /mnt/iso/BaseOS/ ls /mnt/iso/AppStream/ISO 内部会有BaseOS、AppStream两个目录,每个目录下又有Packages和repodata。把整个目录结构原样拷贝出来,再用 createrepo_c 对拷贝后的目录重新生成元数据,就可以当本地源用了。这里有一个关键点:直接用挂载目录做源也行,但系统重启或者挂载失效后 repo 就不可用了,生产环境还是建议拷贝到磁盘上。
拷贝命令很简单,但要控制好时间:
# 静默拷贝,避免大量文件输出日志 cp -a /mnt/iso/BaseOS /data/repo/rhel94/ cp -a /mnt/iso/AppStream /data/repo/rhel94/2.2 手写 BaseOS 和 AppStream 的 repo 文件
仓库目录准备好之后,下一步是写 repo 文件。很多新手喜欢用dnf config-manager --add-repo自动生成,但那个命令生成的配置经常带着gpgcheck=1,在有密钥的离线环境下会出问题。我更推荐手写,只有几行,逻辑清晰:
# /etc/yum.repos.d/rhel94-local.repo [BaseOS-Local] name=RHEL 9.4 BaseOS (Local) baseurl=file:///data/repo/rhel94/BaseOS enabled=1 gpgcheck=0 [AppStream-Local] name=RHEL 9.4 AppStream (Local) baseurl=file:///data/repo/rhel94/AppStream enabled=1 gpgcheck=0注意:baseurl=file:///data/repo/rhel94/BaseOS这个路径要能直接看到repodata目录,不要再往后加Packages。ISO 原目录里BaseOS下面同时有Packages和repodata,createrepo 识别的是包含 repodata 的目录层。
写完 repo 文件后执行:
dnf clean all dnf makecache dnf repolist如果输出里能看到BaseOS-Local和AppStream-Local且数量不为零,说明本地源已经生效。这里最容易翻车的点:dnf clean all会把/var/cache/dnf下的所有仓库元数据和包都清掉,虽然本地源很快就能重新生成 cache,但如果你前面有临时下载的 RPM 想留作后用,先备份再 clean。这是经验之谈,我一同事就因为在拷贝 RPM 包前手贱敲了 clean,白下了两小时包。
2.3 从 ISO 拷贝仓库时容易踩的坑
ISO 挂载之后,不要直接对 /mnt/iso 里的 repodata 做 createrepo。ISO 里的 repodata 是红帽签名和校验过的,里面记录了文件校验信息,你直接引用原始 ISO 的 repo 没问题,但如果你把 Packages 目录内容改动过了(比如加了 EPEL 包进去),原 repodata 就会校验失败。最稳妥的做法就是像上面那样,先拷贝再做新的 repodata。
另外,拷贝 RPM 包时注意看磁盘空间。RHEL 9.4 DVD ISO 里 BaseOS 加 AppStream 合计大约 7~8 GB,但拷贝后占用空间会略大于 ISO 压缩体积,再用du -sh /data/repo/rhel94确认一下。如果磁盘紧张,可以只拷贝 BaseOS,暂时不做 AppStream,但这样很多软件装不了,比如 oracle-database-preinstall 这个包就在 AppStream 里。
还有一个细节:ISO 里的repodata文件虽然拷贝过来了,但最好还是重新生成一次元数据,因为后续很可能往目录里追加包。重新生成的命令:
dnf install -y createrepo_c createrepo_c --update /data/repo/rhel94/BaseOS createrepo_c --update /data/repo/rhel94/AppStream--update参数表示增量更新,只重新扫描新增或变更的 RPM,速度比全量重建快得多。如果目录里已经有 repodata,不加--update也能重建,但耗时更长。
3. 把远端仓库同步成离线安装包目录
3.1 reposync 同步的核心流程
只有 ISO 里的包在很多场景下不够用。生产环境装 Oracle 19c、JDK 17、各类中间件,依赖的 RPM 散落在 EPEL、RHEL 官方扩展源和第三方源里。这时就要用reposync把整个远端仓库下载到本地,做成离线仓库。RHEL 9.X 的 dnf 工具链里自带dnf-utils,安装后就有 reposync:
dnf install -y dnf-utils reposync --help基本同步命令是:
reposync --repoid=epel --download-metadata --downloaddir=/data/repo/epel --arch=x86_64每个参数都值得细说:
--repoid:指定要同步的仓库 ID,仓库 ID 来自你/etc/yum.repos.d/下的配置。--download-metadata:把远端仓库的 repodata 一起下载下来。这个参数在 dnf 版本的 reposync 中很关键,没有它,同步完还要手动 createrepo。--downloaddir:指定下载目录,目录会自动创建。--arch:只同步指定架构的包。如果不加,会把 noarch 和当前机器架构的包都下下来,实际中 noarch 必须保留,但其他架构(比如 aarch64 的包)就没必要出现在 x86_64 离线仓库里。
同步完成后检查一下目录:
ls /data/repo/epel/ ls /data/repo/epel/Packages/ | head如果看到Packages目录和repodata目录并存,说明元数据已经下载好了。如果只有 RPM 没有 repodata,执行:
createrepo_c /data/repo/epel/3.2 一个生产环境可用的同步脚本实例
实操中没人会手动一条条敲 reposync,都是写脚本。下面这个脚本是我在自己环境里用的,可以考虑根据自己的业务调整。
#!/bin/bash # 同步 RHEL 9.X 相关仓库到本地离线目录 # 适用:RHEL 9.2/9.3/9.4/9.6 REPO_BASE="/data/repo" SYNC_LOG="/var/log/repo-sync.log" DATE=$(date '+%Y-%m-%d %H:%M:%S') REPOS=( "BaseOS" "AppStream" "epel" "epel-modular" ) echo "[$DATE] 开始同步仓库..." >> "$SYNC_LOG" for repo in "${REPOS[@]}"; do echo "[$DATE] 同步仓库: $repo" >> "$SYNC_LOG" reposync --repoid="$repo" \ --download-metadata \ --downloaddir="$REPO_BASE/$repo" \ --arch=x86_64 \ --newest-only \ --delete >> "$SYNC_LOG" 2>&1 if [ $? -eq 0 ]; then echo "[$DATE] $repo 同步成功" >> "$SYNC_LOG" else echo "[$DATE] $repo 同步失败,错误码 $?" >> "$SYNC_LOG" fi done # 对未包含 repodata 的目录执行 createrepo_c for repo in "${REPOS[@]}"; do if [ -d "$REPO_BASE/$repo/Packages" ] && [ ! -d "$REPO_BASE/$repo/repodata" ]; then createrepo_c "$REPO_BASE/$repo" fi done echo "[$DATE] 全部仓库同步完成" >> "$SYNC_LOG"这里有两个参数要特别说明。--newest-only只同步每个软件包的最新版本,能大幅减少磁盘占用,但代价是仓库不具备历史多版本共存的能力。如果线上环境存在不同机器锁定旧版本的需求,加这个参数就会出问题。--delete会删除本地仓库里远端已经消失的包,保持本地仓库和远端完全一致,但如果远端仓库临时下线某些包,而你又刚好有机器依赖它,删了以后离线环境就装不上了。我实际使用时线上系统版本比较统一,所以两个参数都用;如果你管理的是百花齐放的环境,建议去掉这两个参数,宁可仓库大一点,也别把自己逼进死胡同。
3.3 同步频率与磁盘空间评估
很多人问“仓库多久同步一次合适”,这取决于你的业务变化节奏。RHEL 9.X 的 BaseOS 和 AppStream 更新频率大约是每月一次(红帽的 Errata 发布节奏),EPEL 变化更快,有时候一周就有好几轮更新。我的经验是:
- 有外网窗口的隔离网络:每周同步一次 BaseOS、AppStream,每天或每两天同步 EPEL。
- 完全隔离、只能通过光盘拷入:按项目节奏同步,每次上线前至少提前一周准备。
磁盘空间评估也要提前算。以 x86_64 架构为例:
| 仓库 | 全量同步预估大小 | 增量每月增长 |
|---|---|---|
| RHEL 9.X BaseOS | 约 3.5~4 GB | 150~300 MB |
| RHEL 9.X AppStream | 约 6~8 GB | 400~800 MB |
| EPEL 9 | 约 4~5 GB | 200~500 MB |
上面是基础仓库的大小,应用仓库另算。如果你还要同步 Oracle Linux 的仓库来装 Oracle 19c 预安装包,额外加 1~2 GB。
增量同步时,reposync 会对比本地和远端的元数据,只下载新增和变更的包,所以日常同步流量并不大。但首次全量同步要注意带宽和时间。我当时在百兆内网环境下同步 EPEL,4 GB 多的包跑了将近两小时,期间还断了一次。建议用screen或tmux挂后台执行,别用 SSH 直连等,断线就白干了。
3.4 基于时间戳的增量缓存方案
远端仓库的更新频率虽然不高,但每次全量扫描 metadata 还是要花时间。如果想进一步优化,可以先下载远端repomd.xml,比较<revision>时间戳,判断有没有必要同步。下面是一个简化版本:
#!/bin/bash # 比较远端与本地 repomd.xml timeStamp,决定是否同步 repo_name="AppStream" remote_url="https://mirror.example.com/rhel9/$repo_name/x86_64/os/" local_time_file="/data/repo/$repo_name/.last_sync_time" remote_time=$(curl -s "$remote_url/repodata/repomd.xml" | grep "<revision>" | sed 's/[^0-9]//g') local_time=$(cat "$local_time_file" 2>/dev/null || echo 0) if [ "$remote_time" -gt "$local_time" ]; then echo "远端已有更新,开始同步..." reposync --repoid="$repo_name" --download-metadata --downloaddir="/data/repo/$repo_name" echo "$remote_time" > "$local_time_file" else echo "远端无更新,跳过" fi这种基于时间戳的判断,能省掉不少无谓的网络传输。但要注意:不同源站的 repomd.xml 格式可能有细微差异,写脚本前先curl下来看一眼结构。
4. 把缓存仓库发布给内网其他机器
4.1 用 Nginx 提供 HTTP 仓库服务
本地仓库做好后,不可能每台机器都挂一个 file:// 路径,尤其在内网多主机场景下,标准做法是走 HTTP。Nginx 是首选,配置简单,性能稳定,RHEL 9.X 自带的 httpd 也够用,但我个人更喜欢 Nginx 的简洁。
安装并配置:
dnf install -y nginx然后修改/etc/nginx/nginx.conf,在 server 块里加一个 location:
server { listen 8080; server_name _; client_max_body_size 1G; location /repo/ { root /data; autoindex on; charset utf-8; } }启动服务:
systemctl enable --now nginx systemctl status nginx确认能访问http://your-server-ip:8080/repo/rhel94/BaseOS/repodata/repomd.xml。注意端口别被防火墙挡了,RHEL 9.X 默认 firewalld 通常会拦截 8080:
firewall-cmd --permanent --add-port=8080/tcp firewall-cmd --reload4.2 客户端 repo 文件配置
在被安装的机器上,把/etc/yum.repos.d/下默认的 redhat.repo 先禁用或移走,然后新建一个指向内网仓库的 repo 文件:
# /etc/yum.repos.d/internal.repo [BaseOS-Intranet] name=RHEL 9.X BaseOS (Intranet) baseurl=http://192.168.10.5:8080/repo/rhel94/BaseOS enabled=1 gpgcheck=0 [AppStream-Intranet] name=RHEL 9.X AppStream (Intranet) baseurl=http://192.168.10.5:8080/repo/rhel94/AppStream enabled=1 gpgcheck=0 [EPEL-Intranet] name=EPEL 9 (Intranet) baseurl=http://192.168.10.5:8080/repo/epel enabled=1 gpgcheck=0配置完成后:
dnf clean all && dnf makecache dnf repolist4.3 离线环境的 gpgcheck 策略
RHEL 9.X 默认gpgcheck=1,它会尝试导入 GPG 密钥。在内网仓库场景下,如果你只是给内部机器用,出于安全要求,可以把 GPG 密钥导出并在客户端导入;但实际运维中为了减少交付时间,很多团队直接gpgcheck=0。我个人的倾向是:内部离线环境可以关掉 gpgcheck,但前提是仓库目录的写入权限必须严格限制,只允许特定运维账号修改,毕竟仓库内容一旦被污染,关掉 gpgcheck 等于让所有客户端安装恶意包。如果你对安全要求很高,可以使用本地签名的 GPG 密钥为每个包签名,把公钥分发到客户端/etc/pki/rpm-gpg/,然后在 repo 文件里用gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-local指定。这个步骤麻烦一点,但好处是任何未经签名的包都无法被安装。
5. dnf 缓存目录:你可能忽略的安装包金矿
5.1 /var/cache/dnf 里到底有什么
聊完仓库本身,再回到“缓存”这个字眼。很多人在隔离网络里临时装了几台机器,装完发现/var/cache/dnf里静静躺着各个版本的 RPM 包,但不知道怎么利用这些包。实际上,每当你执行dnf install成功之后,dnf 默认会把下载的 RPM 包缓存在/var/cache/dnf/<repo-id>/packages/目录下。这些包往往就是你线上实际部署过的确切版本,比重新同步仓库更“对口味”。
查看缓存内容:
ls -lh /var/cache/dnf/ find /var/cache/dnf -name "*.rpm" | wc -lRHEL 9.X 的 dnf 默认配置中keepcache可能是 0,也就是安装完成后立即清掉包缓存。可以通过grep keepcache /etc/dnf/dnf.conf查看。如果想保留包缓存,编辑/etc/dnf/dnf.conf加一行:
keepcache=1设置后,以后安装的 RPM 都会留在缓存目录。如果你已经在机器上装了很多包但之前没开 keepcache,那缓存目录里大概率只有 metadata,没有实际的 RPM 包,这时候找出“曾经装过哪些包”的唯一办法是从日志里解析,不太实用。
5.2 把现有机器上的包缓存变成可用仓库
假设你有一台机器,由于种种原因它的/var/cache/dnf里攒了很多 RPM 包,正好你的离线仓库里缺这些包,那可以直接把它们提取出来合并进仓库:
# 先把缓存的 RPM 统一收集到一个目录 find /var/cache/dnf -name "*.rpm" -exec cp -n {} /data/repo/common/Packages/ \; # 更新仓库元数据 createrepo_c --update /data/repo/common/-n参数很重要,它防止同名文件被覆盖。不同仓库同名的 RPM 可能版本不同,用-n保留先拷贝的那个,避免相互覆盖导致信息丢失。合并之后的common仓库,可以作为所有其他仓库的兜底,放在 repo 文件的后面位置:
[CommonCache] name=Collected RPM Caches baseurl=http://192.168.10.5:8080/repo/common enabled=1 gpgcheck=0这种“拼凑出来的仓库”非常适合解决那种“不知道哪个仓库里才有这个包”的尴尬局面。
6. 实战场景拆解:Oracle 19c 离线安装和 JDK 17 部署
6.1 Oracle 19c 的依赖处理方案
很多刚接触 RHEL 9.X 的人会搜“rhel 9.8安装oracle 19c”,说明大家普遍关心在版本较新的 RHEL 上跑老牌商业数据库的兼容性问题。Oracle 19c 官方对 RHEL 9 的完整支持其实是逐步放开的,但安装流程里那些依赖包数量不会变少。在离线环境,Oracle 19c 的安装依赖大致包括:
oracle-database-preinstall-19c(如果能拿到这个包,依赖基本解决一半)bc、binutils、elfutils-libelf、glibc、glibc-devel、libaio、libaio-devel、libgcc、libstdc++、libstdc++-devel、make、sysstat、unixODBC等
这些包分散在 BaseOS 和 AppStream 里,少数可能在 EPEL。用离线仓库安装时:
dnf install -y oracle-database-preinstall-19c如果报缺依赖,先同步错误信息去找对应 RPM。我遇到过compat-libcap1和compat-libstdc++-33这两个包在 RHEL 9 默认仓库里根本没有,需要从老版本系统或第三方源里补。这时候你的“cache 合并仓库”就派上用场了,或者你从 Oracle Linux 的库同步这几个包。
Oracle 19c 的 zip 安装包本身(约 2.6 GB)不属于 RPM,建议放到仓库目录的侧边路径,比如/data/repo/app/oracle19c/,并在内部 wiki 里标记清楚路径和 MD5。这也是“安装包缓存”的一部分,别忽略了。
6.2 JDK 17 等应用安装包的组织方式
JDK 17 的 tar.gz 包、各种中间件安装器,这些非 RPM 格式的应用包,建议在/data/repo根目录下单独建一个apps目录,按“软件名/版本号/架构”组织:
/data/repo/apps/ ├── jdk-17/ │ ├── jdk-17_linux-x64_bin.tar.gz │ └── SHA256SUMS ├── oracle19c/ │ ├── LINUX.X64_193000_db_home.zip │ └── README.txt └── xxx_installer/统一目录的好处是,你在 Kickstart 或手工安装时,可以直接用 HTTP 把这些大文件拉下来解压,不用担心“这个包放哪了”的问题。还可以在根目录放一个INDEX.txt,记录每个软件的版本、上传时间、来源链接、安装注意事项。我在实际交付中发现,这份 index 文件往往比安装包本身还珍贵,因为半年后没人记得当时装的是哪个版本。
7. 常见问题与排查经验
7.1 reposync 下载中断或超时
同步大仓库时断连是家常便饭。reposync 本身没有断点续传,中断后重跑会对比本地已有文件并跳过已下载的包,因此一般直接重跑脚本就行。但如果你遇到反复在同一个 RPM 包上报错,可能是源站该文件损坏或不稳定,可以单独删掉这个包再重跑:
find /data/repo/epel/Packages -name "名字不一致的包.rpm" -delete还有一个隐蔽问题:某些源站虽然显示 200,但下载下来的 RPM 校验不过。reposync 同步失败时会在日志里提示校验和不匹配,这说明本地包已经损坏,必须删除重下。不要相信“文件大小一致就代表完好”这个说法,HTTP 传输中字节数对但数据变了的概率虽然低,但不是零。重下或者换源站通常能解决。
7.2 客户端报“仓库无可用元数据”或 “repomd.xml 缺失”
这种情况八成是仓库目录路径不对。用curl http://server/repo/xxx/repodata/repomd.xml测试一下,如果 404,检查你的 baseurl 是不是多了或者少了层级。另外,Nginx 的 autoindex on 可以帮忙确认目录结构,浏览器打开仓库 URL 就能看到目录树,对照一下很直观。
还有一种情况:你同步完仓库后没有把repodata目录放进上线的仓库目录,或同步时就漏了--download-metadata。处理方式很简单,在仓库目录执行:
createrepo_c /data/repo/epel/7.3 dnf makecache 太慢,尤其是在仓库包数量巨大时
如果仓库里有上万甚至几万个 RPM 包(EPEL 全量就接近这个量级),客户端每次 makecache 都要下载和解析几千个文件,速度自然慢。可以从两方面优化:
一是调服务端,给 Nginx 开 gzip:
gzip on; gzip_types application/xml text/plain;不过 RPM 包本身不重复压,主要收益来自 XML 元数据。
二是调客户端,合理使用dnf cacheonly和metadata_expire。在/etc/dnf/dnf.conf里设置:
[main] metadata_expire=6h这样六小时内客户端不会重复拉取 repodata。如果仓库内容变化不频繁,可以把时间拉大到 24h,效果明显。
7.4 小心 dnf clean all 破坏性
前面提到过,dnf clean all会把所有缓存的包和元数据都清掉。如果你刚在一台机器上通过容器或离线方式装大量软件包,而后续还想从这些包中提取文件出来做共享仓库,那就不要急着 clean。可以先拷贝走,再 clean:
mkdir -p /tmp/rpm-extract find /var/cache/dnf -name "*.rpm" -exec cp -n {} /tmp/rpm-extract/ \; dnf clean all这里追加一个小技巧:在做 dnf 操作前先确认网络源或本地源可用,避免 clean 后因源不可用导致 makecache 失败,进而无法装任何软件。我踩过一次,正因为硬盘空间报警想清理缓存,结果 clean 完发现远程源断了,当场抓瞎。
7.5 仓库更新后客户端还是装到旧版本
因为你客户端已经缓存了旧的 repodata,即使服务端仓库刚更新过,客户端的metadata_expire没到时间,就会继续用旧元数据。强制刷新很简单:
dnf clean expire-cache dnf makecache注意clean expire-cache只清过期 metadata,保留 RPM 包缓存,比clean all温和得多。
8. 最后说一个让我能睡个好觉的小技巧
每次同步完仓库之后,我一定会在/data/repo根目录生成一个SHA256SUMS文件,内容涵盖仓库里所有 RPM 包的校验和,然后把这个文件备份到独立存储或者 U 盘上。这样即使仓库盘发生静默损坏(比如坏道导致某个 RPM 包字节变化但文件系统没报错),我也可以用脚本对比校验和,把损坏的包揪出来重新同步,而不是等到某台新机器装到一半报package is damaged才追悔莫及。
生成方法很简单:
cd /data/repo find . -name "*.rpm" -type f -exec sha256sum {} \; > SHA256SUMS校验时执行:
sha256sum -c SHA256SUMS 2>/dev/null | grep -v OK没有输出就是皆大欢喜。这个动作只需要几分钟,但能避免掉线环境里最恶心的一种故障——静默损坏。做运维这些年,我越来越觉得,离线安装包缓存这件事,真正考验人的不是把包下载下来,而是把这些包管得明明白白、随时能靠得住。上面这些流程我已经在项目里稳定跑了超过半年,希望能帮你避开我当年掉进去的那些坑。