CentOS 10(也就是 CentOS Stream 10)出来之后,我身边不少人踩到的第一个坑就是包管理。默认源卡、部分源失效、装软件反复超时,这些在老版本上忍一忍就算了,但到 10 这一代,DNF5 带来了不少行为变化,网上很多旧版 yum 源配置教程直接不能照搬。我最近在两台干净的 CentOS 10 机器上重装了系统,把本地 yum 源挂载这套流程完整过了一遍,包括 ISO 镜像挂载、repo 文件编写、缓存刷新以及开机持久化,现在把过程记录下来,给同样需要离线装包或者做内网源的朋友做一个参考。
这套方案解决的核心问题很明确:在没有外网或者网络不稳定的环境里,用 CentOS 10 的安装镜像作为软件源,通过本地挂载的方式,让 dnf/yum 能够顺利安装、升级软件。整个过程不依赖任何额外服务,一条 mount 命令加一个 repo 文件就能干活。适合刚接触 CentOS 10 的新手,也适合需要在隔离网络内部署环境的运维人员。
1. 为什么 CentOS 10 一定要自己配 yum 源
1.1 CentOS 10 的包管理变化到底有多大
CentOS 10 已经不是过去那个“免费 RHEL 复制版”了,它是 CentOS Stream 模式下的下一个大版本。最直接的感受是包管理器从 yum 换成了 DNF5。命令层面yum还是能用的,因为它是 dnf 的符号链接,但底层解析逻辑、缓存目录、仓库配置的读取方式都有变化。
官方默认带的仓库虽然好用,但很多时候你拿到的机器是精简安装,或者所在的网络环境访问不了外部镜像站。还有更常见的情况是:公司内网完全离线,装系统的时候用了 CentOS 10 的 ISO,结果装完发现想装个 vim、nginx、编译工具链都报错,因为系统默认没有可用的软件源。这时候本地挂载 ISO 镜像就成了最务实的解。
1.2 三种典型场景对照
我总结了一下自己遇到的情况,基本可以归成三类。
第一类:纯离线环境。内网机器不允许出网,光盘或者 U 盘里有 CentOS 10 的安装镜像,这时候把镜像挂到本地目录,配置成 file:// 源,所有 rpm 包全部本地读取,速度极快,还不受带宽限制。
第二类:网络源质量太差。有些网络环境下外部镜像站连通性不稳定,装个包要重试好多次。本地挂载镜像做兜底源,再用默认源做补充,两边共存,互不干扰。
第三类:局域网互联。一台机器挂载好镜像后,通过 NFS 或者 HTTP 共享出去,整个网段的机器一起用,不用每台都去手动挂 ISO。
1.3 搞懂“挂载”和“yum 源”之间的关系
很多新手一开始会把“挂载”和“配置源”当成两件事,其实它们是一件事的前后两步。挂载是操作系统层面的动作,把 ISO 镜像文件变成一个可访问的目录;配置 yum 源则是包管理器层面的动作,告诉 dnf 去哪个目录找 repodata 元数据和 rpm 包。
打个比方,挂载就是把一箱零件搬到操作台上,配置源就是告诉装配工“零件在工具箱第二个抽屉里”。抽屉没搬到位,后面的配置怎么都白搭。所以每一步都要确认清楚,尤其是挂载完成后的目录结构,很多人就是栽在这里。
2. 拿到镜像后先别急:看清目录结构再动手
2.1 ISO 镜像里的仓库目录和旧版本完全不同
如果你用过 CentOS 7 甚至更早的版本,可能会记得挂载 ISO 之后,repodata 目录就在根目录下,一个源搞定所有事情。但 CentOS 8 之后就改了,ISO 根目录下不再直接放 repodata,而是按仓库拆分为 BaseOS、AppStream 等子目录。CentOS 10 延续了这个设计。
镜像挂载后,典型的目录结构是这样的:
/mnt/cdrom/ ├── AppStream/ │ ├── repodata/ │ └── Packages/ ├── BaseOS/ │ ├── repodata/ │ └── Packages/ ├── CRB/ │ ├── repodata/ │ └── Packages/ ├── images/ └── isolinux/这里的关键点在于:每个仓库子目录都有属于自己的 repodata/repomd.xml 文件。写 yum 源时,baseurl 必须精确指到仓库子目录这一层,而不是指到 /mnt/cdrom 根目录。如果指到根目录,dnf 会报找不到 repomd.xml。
我见过太多照搬 CentOS 7 旧教程的案例,把 baseurl 写成 file:///mnt/cdrom,然后 makecache 报错,第一反应是网络问题,查半天最后才发现是路径层级不对。
2.2 创建挂载点与文件校验
开始动手之前做三件准备工作。第一步创建挂载点,我习惯用 /mnt/cdrom,简单好记:
mkdir -p /mnt/cdrom第二步确认镜像文件完整。ISO 文件如果下载不完整或者校验值不对,mount 可能能挂上,但读取到某个 rpm 包时会报文件系统错误或者 CRC 错误。下载页面一般会提供 SHA256 校验值,用 sha256sum 比对。
sha256sum CentOS-Stream-10-*.iso第三步确认当前用户有 root 权限。mount 和修改 /etc/yum.repos.d/ 下的文件都需要 root 身份,建议直接切到 root 或者用 sudo。
2.3 一个容易被忽略的细节:loop 设备
ISO 镜像本身是一个普通文件,要通过 loop 设备把它模拟成块设备才能挂载。现在主流内核都启用了 loop 模块,大多数情况下 mount -o loop 直接能用。但极简安装的内核可能没加载,挂载时报no loop device available或者提示找不到 loop 设备。
处理办法很简单,手动加载模块再重试:
modprobe loop如果还不行,检查 /dev/loop0 是否存在。存在的话用显式指定方式挂载:
mount -o loop=/dev/loop0 CentOS-Stream-10-*.iso /mnt/cdrom3. 实测:挂载 ISO 并写 repo 文件,一个完整流程
3.1 挂载命令的选择与验证
把 ISO 挂到 /mnt/cdrom。如果镜像文件就在当前目录,命令直接写:
mount -o loop CentOS-Stream-10-*.iso /mnt/cdrom这里有个自检小技巧:挂载完不要急着配源,先看目录有没有挂对。用 df 或者 lsblk 检查:
lsblk | grep cdrom输出里应该能看到 /dev/loop0 以及后面的挂载点 /mnt/cdrom。接着进入目录,逐个查看仓库子目录:
ls /mnt/cdrom/ ls /mnt/cdrom/BaseOS/repodata/repomd.xml ls /mnt/cdrom/AppStream/repodata/repomd.xml只要 repomd.xml 文件存在,路径就没问题。这是整个配置过程中最重要的验证动作。
3.2 编写本地 repo 文件,两个仓库别漏
CentOS 10 下官方大仓库至少包含 BaseOS 和 AppStream,安全相关软件可能还要用到 CRB。我建议大家在 repo 文件里把镜像里存在的仓库都写进去,用不到的时候反正也不影响,需要的时候就能直接用。
在 /etc/yum.repos.d/ 下新建一个独立文件,不要随便改动系统自带的那些 repo 文件。我习惯命名为 local.repo,内容如下:
[c10-local-baseos] name=CentOS Stream 10 - Local BaseOS baseurl=file:///mnt/cdrom/BaseOS enabled=1 gpgcheck=0 [c10-local-appstream] name=CentOS Stream 10 - Local AppStream baseurl=file:///mnt/cdrom/AppStream enabled=1 gpgcheck=0 [c10-local-crb] name=CentOS Stream 10 - Local CRB baseurl=file:///mnt/cdrom/CRB enabled=1 gpgcheck=0注意看 baseurl 的写法,file://协议后跟的是绝对路径,不是普通的文件路径写法。有人写成file:///mnt/cdrom/BaseOS,也有人会漏掉一个斜杠,结果 dnf 怎么都识别不了。
3.3 刷新缓存并验证源可用
配置写完,先清理缓存再重建:
dnf clean all dnf makecacheDNF5 下 makecache 的输出会有进度条,如果看到Metadata cache created或者类似表述,说明源没问题。然后执行:
dnf repolist输出里应该能看到 c10-local-baseos 和 c10-local-appstream 这两个仓库,状态是启用的。
再做一次真正的软件安装测试,最好选一个镜像里肯定包含的包:
dnf install -y vim-enhanced如果能顺利解析依赖并完成安装,说明本地源已经完全可用。这一步我每次都会做,因为 repolist 正常不代表包真的在预期路径,只有实际装一次才能确认。
3.4 开机自动挂载:fstab 的正确姿势
机器一旦重启,手动 mount 的 ISO 就会掉。如果你的环境需要长期使用本地源,得把挂载关系写进 /etc/fstab。格式如下:
/path/to/CentOS-Stream-10-xxx.iso /mnt/cdrom iso9660 loop,ro 0 0第一列写镜像文件的完整路径,第二列写挂载点,第三列文件系统类型先用 iso9660,第四列是挂载选项,loop 表示作为 loop 设备挂载,ro 表示只读。如果镜像文件系统实际是 UDF 格式,第三列改成 udf 即可,这个在挂载报wrong fs type的时候可以试。
写完之后先别急着直接 reboot,用下面命令验证 fstab 配置没有语法错误:
mount -a如果没有新报错,这条命令什么都不会输出。它会把 fstab 里没挂上的条目全部挂一遍。确认没问题后再重启,或者直接mount -o loop /path/to/CentOS-Stream-10-xxx.iso手动挂载也可以,反正最终效果一致。
补充一个细节:fstab 里镜像路径如果包含空格,需要用转义符\040替代空格。不想记这个规则的话,最简单的办法是把 ISO 文件放到一个没有空格的路径下,比如 /opt/iso/ 目录。
4. 排坑实录:容易翻车的细节一次说完
4.1 网络旧教程最容易误导的 repomd.xml 报错
这是我在各个平台上被问得最多的问题。报错信息大致长这样:
Errors during downloading metadata for repository 'c10-local-baseos': - Curl error (-37): Couldn't open file /mnt/cdrom/repodata/repomd.xml问题基本都出在 baseurl 指向了 /mnt/cdrom,也就是镜像根目录。老版本 CentOS 7 这么写没问题,但 CentOS 10 的 ISO 里,repodata 被拆到 BaseOS、AppStream 等子目录。解决办法就是把 baseurl 改成指向对应仓库子目录。
还有一种情况是目录结构里根本没有 BaseOS 目录,只有 packages 或者 repodata 直接出现在根目录,这种一般是用了精简版镜像或者 boot ISO。精简版镜像的 packages 很少,不适合做完整本地源,建议换成 DVD 版或者完整版 ISO。
4.2 gpgcheck 到底要不要开
我在本地源的配置里默认写了 gpgcheck=0,这是有意为之。离线环境下,如果镜像本身来源可靠,关掉签名检查是最省事的做法,因为 CentOS 10 的密钥文件名在不同版本里有差异,我在 /etc/pki/rpm-gpg/ 下见过好几个不同命名的 key 文件,手动指定 gpgkey 如果写错文件名,反而会报Public key for xxx.rpm is not installed。
如果对安全要求高,必须开签名检查,先把官方密钥导入:
rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-*然后把 repo 文件里的 gpgcheck 改成 1,并去掉 gpgkey 那一行的注释。注意导入密钥的命令里通配符的含义,把目录下所有密钥一次性导入,避免漏掉导入。验证装包时不再报公钥错误,就算配置成功。
4.3 DNF5 命令行为差异
CentOS 10 默认的包管理是 DNF5,和之前的 dnf 4 相比,有几个细节需要注意。
第一,dnf clean all和dnf makecache仍然有效,但缓存目录路径可能不同,清理完输出会提示缓存目录位置,不用特别在意。
第二,dnf repolist仍然可用,但想看到更详细的信息,用dnf repolist -v。在 DNF5 里部分选项的缩写形式变了,有些旧脚本里写的yum --noplugins这样的参数不一定继续兼容。
第三,yum命令在 CentOS 10 中是存在的,它是指向 dnf 的符号链接。但不要因此就认为所有 yum 插件都能继续用,有些第三方插件没有适配 DNF5,加载时会报警告。如果警告不影响装包,可以忽略;如果有影响,把 /etc/yum.conf 里相关的插件配置注释掉。
4.4 想要禁用网络源,只保留本地源怎么操作
有些场景要求安装软件必须全部来自本地源,比如离线安全审计。这时候直接把系统自带的仓库全部禁用,再安装时指定仅用本地仓库:
dnf install --disablerepo='*' --enablerepo='c10-local-*' nginx这条命令的星号要注意用单引号包住,防止 shell 通配符展开。还有一种做法是直接编辑 /etc/yum.repos.d/ 下系统自带的 repo 文件,把每个源的 enabled=1 改成 enabled=0,不过这样改动面太大,而且系统升级时有可能被覆盖,不如安装时手动指定来得干净。
4.5 makecache 卡住不动的解决思路
本地挂载源理论上是纯本地读取,不该卡住。但如果你用的不是 file:// 协议配的源,而是用 http:// 指向局域网内的共享服务,makecache 卡住多半是网络服务的问题。
先 curl 测试一下 baseurl 的 HTTP 响应是否正常:
curl -I http://192.168.1.10/centos10/BaseOS/repodata/repomd.xml如果响应正常,再检查客户端 DNS 和防火墙。如果响应超时,排查服务端 nginx 权限配置,重点看目录是否有 execute 权限,repodata 文件是否能正常读取。注意不要把这个问题带进本地挂载场景,自己切源时先确认用的是 file:// 协议。
5. 本地源还能怎么玩:局域网共享与离线同步
5.1 一台机器挂载,整个内网共用
本地挂载如果只在一台机器上用,其实有点浪费。我一般在服务器上挂载好 ISO 后,通过 NFS 共享给内网的其他机器。服务端操作:
dnf install -y nfs-utils mkdir -p /srv/centos10 mount -o loop CentOS-Stream-10-*.iso /mnt/cdrom这里不建议直接把 /mnt/cdrom 作为 NFS 导出目录,某些情况下 loop 挂载的目录权限会有限制,跨国 NFS 授权时有点别扭。我习惯把 ISO 内容重新 bind 到另外的导出目录:
mkdir -p /srv/centos10 mount --bind /mnt/cdrom /srv/centos10然后在 /etc/exports 里加一行:
/srv/centos10 192.168.1.0/24(ro,sync,no_root_squash)改完导出配置后生效:
exportfs -ra客户端那边只要挂载 NFS 路径,repo 文件写法不变:
mount -t nfs 192.168.1.10:/srv/centos10 /mnt/cdrombaseurl 照样写 file:///mnt/cdrom/BaseOS。这样整个网段的机器都能使用同一份源,不用每台机器都去单独放 ISO 文件。
5.2 做离线仓库同步:让本地源更完整
如果镜像里的包不够用,需要把线上仓库完整同步到本地,用dnf reposync可以做到。先安装对应工具包,然后指定仓库 ID 同步:
dnf install -y dnf-plugins-core dnf reposync --repoid=baseos --download-path=/data/centos10/baseos同步完成后,生成的目录里有 Packages 和 repodata,可以继续通过 createrepo_c 重新生成元数据。这个流程更适合做企业内部持续分发的离线源,和单纯的 ISO 挂载形成互补。第一次同步数据量很大,建议挂在带宽稳定的时候跑,同步完成后验证方式和前面一样,重点确认 repomd.xml 存在。
5.3 实际使用中的一点心得
踩过几次坑之后,我现在配置本地源会按固定节奏来:先挂载、再看目录、再写 repo、再 makecache、最后装包验证。每一步都有明确的验证动作,不会盲目继续。
因为 CentOS 10 的 repodata 拆分了,所以ls repodata这个动作我会做两遍,BaseOS 一遍、AppStream 一遍。写 repo 文件时,我习惯把一个仓库内容完整写完后放一个空行再写下一个,方便出错时快速定位是哪个仓库的配置问题。
最后再分享一个小技巧:ISO 挂载源虽然是只读的,但 dnf 的 makecache 会产生缓存文件,这些缓存不受 ISO 只读影响,所以离线环境下用本地源装包并不会额外占用 ISO 所在磁盘的写空间。不过/var/cache/dnf如果放在系统盘,装大批量包之前记得看一眼剩余空间,避免把系统盘给撑满。