1. 为什么RedHat的yum源总是让人头疼:订阅机制与镜像源的基本认知
刚装完一台 RedHat 服务器,大部分人第一件事就是敲yum install -y wget,结果屏幕上直接甩出一行:"This system is not registered with an entitlement server. You can use subscription-manager to register."那一刻的心情,经历过的人都懂。RHEL 和 CentOS 不一样,它的软件仓库默认跟订阅体系绑定,不注册就装不了包;就算你有企业订阅,在国内机房走官方 CDN 拉包,那个速度也经常慢到让人怀疑人生。所以"RedHat 国内镜像源"和"本地 yum 源"这套双保险方案,几乎成了每个搞 Linux 运维的人绕不开的必修课。
先说清楚一件事:官方源、国内镜像源、本地源,这三者的定位完全不同。
官方源是 Red Hat 通过 subscription-manager 提供的,走的是cdn.redhat.com,需要订阅账号,而且下载速度在国内很不稳定。国内镜像源指的是阿里云、清华 TUNA、腾讯云这些第三方同步的仓库,速度快、延迟低,但它们同步的是 CentOS、Rocky Linux、AlmaLinux 这类 RHEL 衍生发行版的仓库,而不是 Red Hat 官方仓库——原因很简单,Red Hat 的 Redistribution Policy 不允许第三方直接分发 RHEL 的二进制包。本地 yum 源则是把你手上的 RHEL ISO 镜像或者收集好的 RPM 包塞进本地目录,让系统直接从文件系统读包,完全脱离网络依赖。
这篇文章就围绕这三类源展开,从原理讲到实操,覆盖 RHEL 6 到 9 的常见版本差异。适合刚入职的运维实习生、被领导丢了一台没订阅的 RHEL 服务器的开发同学,以及所有想在离线内网里把软件源搭明白的同行。
1.1 RedHat订阅绑定机制:为什么一装完就报错
RHEL 的yum在设计上就跟 CentOS 不同。CentOS 的/etc/yum.repos.d/里是 CentOS-Base.repo 这类直接指向公共镜像站的文件;而 RHEL 装完之后,repo 文件里写的 baseurl 指向的是subscription.rhsm.redhat.com,这个地址只有在系统完成订阅认证之后才会返回有效的仓库元数据。
你看到的 "not registered with an entitlement server" 就是这套机制在起作用。要解决它有两条路:一是老老实实用subscription-manager register --username xxx --password xxx --auto-attach注册订阅;二是不管订阅,直接把 repo 指向可用的第三方镜像或本地源。对很多没有采购订阅、或者被内网策略挡住外网连接的场景来说,第二条路几乎是唯一选择。
还有一个隐藏坑:就算你成功注册了订阅,yum repolist里显示的仓库 id 也是rhel-7-server-rpms这种格式,而且 RHEL 按 minor version 分发仓库(比如 7.9、8.8、9.2),官方源的$releasever变量会展开成7Server、8、9.2这样的值。你自己写第三方源时要是用了这个变量,很容易对不上镜像站实际的目录结构,这是后文要重点讲的坑。
1.2 镜像源选择:三个方案怎么取舍
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| Red Hat Developer 订阅 | 官方支持、包版本完全匹配 | 需要注册账号、绑定 MAC | 开发环境、有合规要求的场景 |
| 国内 CentOS/Rocky/AlmaLinux 镜像 | 速度快、包数量多、无需注册 | 非官方、存在兼容风险 | 测试环境、开发机、容器构建 |
| 本地 ISO 源 | 完全匹配、离线可用、速度最快 | 包版本固定在 ISO 发行时间 | 内网隔离、生产环境基线管控 |
说句实在话,生产环境我一般不推荐把 CentOS 或 Rocky 的 repo 直接配到 RHEL 上。虽然它们跟 RHEL 二进制兼容度很高,但 Red Hat 官方不背书,万一yum update把核心包跟redhat-release搞出依赖冲突,背锅的是你自己。生产上最稳的是"本地 ISO 源 + 官方订阅源"组合,或者只用一个本地源锁死版本。镜像源方案更适合实验环境、研发机器,还有那些"先能把包装上再说"的应急场景。
2. 国内镜像源配置实操:从手工编写repo文件到验证生效
先强调一个安全习惯:改任何 yum 源之前,先备份。很多人拿到一台 RHEL 就直接rm -rf /etc/yum.repos.d/*,结果换源失败后想还原,啥也没了。正确的做法是把原始 repo 文件挪到一个备份目录,出问题随时能切回去。
2.1 备份与清理:动手前先做对的两件事
登录服务器后,先确认当前系统版本和架构,这决定了后面所有路径怎么写。
cat /etc/redhat-release uname -m比如输出Red Hat Enterprise Linux Server release 7.9 (Maipo)加x86_64,那就按 RHEL 7 的路径处理。接着备份:
mkdir -p /etc/yum.repos.d/backup mv /etc/yum.repos.d/*.repo /etc/yum.repos.d/backup/ ls /etc/yum.repos.d/备份完以后,目录里应该是空的。这时候千万别急着写新文件,先看一眼系统有没有残留的缓存。如果之前yum尝试连接官方源失败过,缓存里可能有一堆半死不活的元数据,建议先清理:
yum clean all rm -rf /var/cache/yum/*注意:yum clean all对没有可用 repo 的系统也能执行,不会报错,放心跑。
2.2 手工编写.repo文件:字段拆解与完整示例
.repo文件的格式不复杂,但每个字段都值得理解,不然遇到问题你都不知道往哪查。
[repo-id] # 仓库唯一标识,不能跟其他 repo 重复 name=仓库显示名 # 给人看的描述,不影响功能 baseurl=仓库地址 # 可以是 http://、https://、file:// enabled=1 # 1 启用,0 停用 gpgcheck=0 # 是否校验包签名,生产建议开 gpgkey=密钥地址 # gpgcheck=1 时必填baseurl是灵魂。如果 baseurl 写错,yum会报 "Cannot retrieve metalink for repository" 或者 "Errors during downloading metadata"。国内用户最常用的是阿里云镜像,RHEL 7 配合 CentOS 7 仓库的配置如下:
[aliyun-c7-base] name=Aliyun CentOS 7 - Base baseurl=https://mirrors.aliyun.com/centos/7/os/x86_64/ enabled=1 gpgcheck=0 [aliyun-c7-updates] name=Aliyun CentOS 7 - Updates baseurl=https://mirrors.aliyun.com/centos/7/updates/x86_64/ enabled=1 gpgcheck=0 [aliyun-c7-extras] name=Aliyun CentOS 7 - Extras baseurl=https://mirrors.aliyun.com/centos/7/extras/x86_64/ enabled=1 gpgcheck=0如果你手上是 RHEL 8 或 9,就别再用 CentOS 7 的仓库了,包管理器已经换成了 dnf(yum只是个软链接),仓库结构也变成了 BaseOS、AppStream 两大块。用 Rocky Linux 8 的镜像做例子:
[aliyun-rocky8-baseos] name=Aliyun Rocky Linux 8 - BaseOS baseurl=https://mirrors.aliyun.com/rockylinux/8/BaseOS/x86_64/os/ enabled=1 gpgcheck=0 [aliyun-rocky8-appstream] name=Aliyun Rocky Linux 8 - AppStream baseurl=https://mirrors.aliyun.com/rockylinux/8/AppStream/x86_64/os/ enabled=1 gpgcheck=0 [aliyun-rocky8-extras] name=Aliyun Rocky Linux 8 - Extras baseurl=https://mirrors.aliyun.com/rockylinux/8/extras/x86_64/os/ enabled=1 gpgcheck=0这里有一个非常关键的细节:别在 baseurl 里用$releasever变量。RHEL 7 上这个变量会展开成7Server,而镜像站的实际路径是7;RHEL 8/9 上会展开成8.8或9.2,而镜像站路径是8或9。如果非要省事,可以在/etc/yum.conf里加一行硬编码:
[main] releasever=7但更推荐的做法是直接写死 URL,一目了然,排错的时候少一个变量干扰。
2.3 GPG签名处理:验证与绕过的权衡
我在上面的示例里全部写了gpgcheck=0,这是很多人照抄后忽略的一点。gpgcheck=0的意思是跳过 RPM 包签名校验,好处是配置简单、不依赖额外的公钥,坏处是没法验证包的完整性——在公网上这是有风险的。
如果你要开gpgcheck=1,就得把对应发行版的公钥导入系统。以 CentOS 7 镜像为例:
rpm --import https://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7然后在 repo 文件里加上:
gpgcheck=1 gpgkey=https://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7Rocky Linux 的公钥地址是https://mirrors.aliyun.com/rockylinux/RPM-GPG-KEY-Rocky-8,AlmaLinux 是https://mirrors.aliyun.com/almalinux/RPM-GPG-KEY-AlmaLinux。
我的建议是:实验室、内网测试机,gpgcheck=0问题不大,图个方便;能接入公网、或者要过等保的机器,务必开签名校验。多一条rpm --import的成本,换来的是供应链安全。
2.4 验证命令:repolist与makecache的组合用法
写完 repo 文件后,别急着装包,按顺序跑三条命令:
yum clean all yum makecache yum repolistmakecache会去拉取每个启用仓库的元数据并缓存在本地,这一步能暴露 90% 的配置错误。看到repolist输出里有仓库 id、名称和包数量,说明源已经通了。再顺手装个小包装试一下:
yum install -y wget vim tree如果makecache阶段报错,优先去看我在第五部分写的排查链路,绝大多数问题都能在那里找到答案。
3. 离线环境下的本地yum源:用ISO镜像搭建最可靠的软件仓库
如果说国内镜像源解决的是"慢"的问题,那本地 yum 源解决的就是"没网也要能装包"的问题。内网隔离环境、涉密网段、云上的 VPC 子网,这些场景下没有外网出口,但运维需求一样不少。这时候,一张 RHEL 安装 ISO 就是你最可靠的软件仓库。
3.1 为什么还要做本地源:离线内网的首选方案
很多人觉得:"我直接把 ISO 挂载到光驱里,手动rpm -ivh挨个装包不就行了?" 短期救急可以,但长期不可行。原因有三:
第一,RPM 包之间有依赖关系,手装一个包可能触发五六个依赖,每个依赖又有各自的依赖,装到怀疑人生。用 yum 源的方式,包管理器会自动解析并解决依赖。
第二,ISO 里的包版本是固定的,但项目后期可能需要升级某个组件。你无法保证本地一定能联网去下载新版 RPM,所以本地源还需要支持"把新收集的 RPM 包加进去重新生成元数据"的能力,这就涉及createrepo了。
第三,yum 的事务机制、历史记录、回滚能力,这些是手装 RPM 完全不具备的。源配好后,yum history list、yum downgrade这套操作都变得可用,出问题能回溯。
3.2 ISO镜像挂载:loop设备与自动挂载配置
先把 ISO 文件想办法传到服务器上,如果机器有光驱,也可以直接挂载虚拟光驱。下面是两种常见方式的命令。
方式一:ISO 文件放在/root/下
mkdir -p /media/rhel7 mount -o loop /root/rhel-server-7.9-x86_64-dvd.iso /media/rhel7 df -h /media/rhel7方式二:VMware/KVM 里把 ISO 挂到虚拟光驱
mkdir -p /media/cdrom mount /dev/sr0 /media/cdrom lsblk # 先确认光驱设备名是 sr0 还是 cdrom如果你的机器重启后还要用这个源,建议写进/etc/fstab实现开机自动挂载。以文件 ISO 方式为例:
/root/rhel-server-7.9-x86_64-dvd.iso /media/rhel7 iso9660 loop,ro,_netdev 0 0有几点注意:_netdev参数在虚拟机里很重要,它告诉系统等网络就绪后再挂载,避免开机制卡在挂载检查上;ro表示只读,防手滑;如果以后把 ISO 文件路径改了,记得同步改/etc/fstab,否则开机报Failed to mount /media/rhel7,系统会卡在 emergency mode。
3.3 直接用ISO现有repodata:RHEL 7/8/9的路径差异
挂载成功后,先看看 ISO 里有没有现成的仓库元数据:
ls /media/rhel7/repodata/RHEL 7 的安装 DVD 在根目录下就带了repodata/repomd.xml,这说明整个 ISO 根目录就是一个完整的 yum 仓库,直接写 repo 文件就行。
[local-rhel7-dvd] name=Local RHEL 7 DVD baseurl=file:///media/rhel7 enabled=1 gpgcheck=0RHEL 8 和 9 不一样,ISO 根目录下没有 repodata,仓库被打散到了子目录。以 RHEL 9 为例:
ls /media/rhel9/ # 输出示例:AppStream BaseOS EULA images isolinux media.repo ...所以要配两个仓库:
[local-rhel9-baseos] name=Local RHEL 9 BaseOS baseurl=file:///media/rhel9/BaseOS enabled=1 gpgcheck=0 [local-rhel9-appstream] name=Local RHEL 9 AppStream baseurl=file:///media/rhel9/AppStream enabled=1 gpgcheck=0baseurl写成file://加绝对路径时,注意路径不要带引号、不要有尾随空格。我见过有人从记事本复制内容,把不可见字符带进了 repo 文件,yum怎么都读不对,最后cat -A才定位到问题。
3.4 createrepo自定义仓库:当RPM来自多个渠道
ISO 里的包毕竟是发行时固定的。真实场景里,你可能从官网、从同事的 U 盘、从代码仓库的产物目录里拿到各种 RPM,它们散落一地,没有统一的 repodata。这时候就要用createrepo把这些 RPM 整理成一个标准仓库。
先把所有 RPM 收集到一个目录:
mkdir -p /data/localrepo/Packages cp /path/to/rpms/*.rpm /data/localrepo/Packages/注意:RHEL 7 的 RPM 包通常位于 ISO 的Packages/子目录里,RHEL 8/9 则在BaseOS/Packages/和AppStream/Packages/下。
然后安装 createrepo。如果你还没有可用的 yum 源,可以直接从 ISO 里用 rpm 装:
# RHEL 7 rpm -ivh /media/rhel7/Packages/createrepo-0.9.9-28.el7.noarch.rpm # RHEL 8/9 建议用 createrepo_c rpm -ivh /media/rhel9/BaseOS/Packages/createrepo_c-*.rpm装好之后生成元数据:
createrepo /data/localrepo以后往里加了新 RPM,不用全量重建,用增量模式更快:
createrepo --update /data/localrepo最后写 repo 文件指向这个自定义仓库:
[local-custom] name=Local Custom RPM Repo baseurl=file:///data/localrepo enabled=1 gpgcheck=0createrepo生成的是repodata/repomd.xml,yum靠它定位仓库根目录。凡是报 "File /data/localrepo/repodata/repomd.xml does not exist" 的,基本都是没执行createrepo或者执行错了目录。
4. 从0到1完整实验:一台RHEL 7.9从裸机到双源配置完成
前面讲了一堆理论,这里把整个流程从头到尾串一遍。所有命令我都实际跑过,按顺序复制粘贴基本不会翻车。
4.1 实验环境描述与前提准备
实验机是一台 RHEL 7.9 x86_64,最小化安装,没有注册任何订阅。网络环境上,这台机器能访问外网,但官方 CDN 速度不理想,所以我先配置国内镜像源验证网络方案;随后断网,再配置本地 ISO 源验证离线方案。整个实验走完,最终实现"有网用镜像源,断网用本地源"的灵活切换。
提前准备两样东西:
- RHEL 7.9 安装 ISO(用于搭建本地源)
- 能联网的终端(SSH 登录用)
4.2 网络源配置完整过程
登录系统后,依次执行以下命令:
# 步骤1:确认系统版本和当前订阅状态 cat /etc/redhat-release subscription-manager status 2>&1 | head -5 # 步骤2:备份默认 repo 文件 mkdir -p /etc/yum.repos.d/backup mv /etc/yum.repos.d/*.repo /etc/yum.repos.d/backup/ # 步骤3:写入阿里云镜像源 cat > /etc/yum.repos.d/aliyun.repo << 'EOF' [aliyun-c7-base] name=Aliyun CentOS 7 - Base baseurl=https://mirrors.aliyun.com/centos/7/os/x86_64/ enabled=1 gpgcheck=0 [aliyun-c7-updates] name=Aliyun CentOS 7 - Updates baseurl=https://mirrors.aliyun.com/centos/7/updates/x86_64/ enabled=1 gpgcheck=0 [aliyun-c7-extras] name=Aliyun CentOS 7 - Extras baseurl=https://mirrors.aliyun.com/centos/7/extras/x86_64/ enabled=1 gpgcheck=0 EOF # 步骤4:清理缓存并生成新缓存 yum clean all yum makecache # 步骤5:验证仓库列表 yum repolist # 步骤6:测试安装 yum install -y wget vim tree gcc如果一切顺利,yum repolist会输出三个仓库及各自的包数量,测试安装也不报错。注意yum makecache这一步可能需要一点时间,取决于你的带宽和机器性能,耐心等它跑完。
4.3 本地源配置完整过程
网络源配好后,接着演示离线场景。把安装 ISO 传到/root/下,然后执行:
# 步骤1:挂载 ISO mkdir -p /media/rhel7 mount -o loop /root/rhel-server-7.9-x86_64-dvd.iso /media/rhel7 # 步骤2:确认挂载成功 ls /media/rhel7/repodata/ # 步骤3:写本地源 repo 文件(注意先禁用网络源) cat > /etc/yum.repos.d/local.repo << 'EOF' [local-rhel7-dvd] name=Local RHEL 7 DVD baseurl=file:///media/rhel7 enabled=1 gpgcheck=0 EOF # 步骤4:禁用网络源,模拟离线 sed -i 's/enabled=1/enabled=0/' /etc/yum.repos.d/aliyun.repo # 步骤5:清理并验证 yum clean all yum makecache yum repolistrepolist此时应该只显示local-rhel7-dvd这一个仓库。装个测试包确认本地源可用:
yum install -y lrzszlrzsz是 rz/sz 命令的包,运维经常用,在 RHEL 7 DVD 里有,适合做验证。
4.4 双源共存时的优先级控制
实际工作中,我不建议同时启用网络源和本地源。原因我在前面提过:CentOS 镜像源里的包跟 RHEL ISO 里的包版本可能不一致,两个源同时启用时,yum 会优先选择版本号更高的包,这有可能导致核心组件被意外升级到 CentOS 的版本,触发依赖冲突。
控制优先级的正确姿势是:平时只开本地源,需要装新软件时临时启用网络源,装完立刻禁掉。用 yum 的--disablerepo和--enablerepo参数最灵活:
# 临时查一下网络源里有没有某个包 yum --enablerepo=aliyun-* list available | grep nginx # 临时从本地源安装(网络源保持禁用) yum --disablerepo='*' --enablerepo=local-rhel7-dvd install -y httpd不要依赖 repo 文件里priority插件,那是第三方插件,默认系统没装,多一层维护成本。用命令参数动态控制,简单可靠,也方便写进脚本。
5. 常见问题与踩坑实录:排查思路比答案更重要
配置 yum 源这件事,报错信息五花八门,但底层原因翻来覆去就那么几个。我建议你遇到问题先别急着搜答案,按照下面的链路一步步排查,多来几次就有肌肉记忆了。
5.1 "Errors during downloading metadata"完整排查链路
这个报错几乎每个人都遇到过,它表示 yum 在拉取仓库元数据时失败了。我按排查顺序列一下:
第一步:清理所有缓存
yum clean all rm -rf /var/cache/yum/*很多"metadata 下载失败"其实是缓存损坏导致的。这一步零成本,先跑掉。
第二步:确认 repo 文件里没有残留的官方仓库
ls /etc/yum.repos.d/ cat /etc/yum.repos.d/*.repo | grep -E "baseurl|mirrorlist"如果发现还有指向subscription.rhsm.redhat.com的条目,但没有订阅,就直接把它们移到 backup 目录。残留的官方仓库是 RHEL 上最典型的 "Errors during downloading metadata" 来源。
第三步:单独测试 baseurl 是否可达
curl -I https://mirrors.aliyun.com/centos/7/os/x86_64/repodata/repomd.xml如果 curl 能返回200 OK,说明网络通、路径对,问题大概率在 yum 缓存或 repo 文件格式上。如果 curl 超时或返回 404,分两种情况处理:
- 超时:检查 DNS 和防火墙,
getent hosts mirrors.aliyun.com看解析是否正常,ping看网络是否通。 - 404:检查路径,重点看是不是少了
x86_64层级,或者版本号写错了。
第四步:抓取详细日志
yum repolist -v tail -50 /var/log/yum.log-v参数会输出每个仓库的详细信息,包括它实际拼接出来的 baseurl。这一步能直接暴露出元变量没展开的问题——比如你看到了mirrors.aliyun.com/centos/7Server/os/x86_64/,就说明$releasever被展开了,把 repo 文件里的变量改成写死的7即可。
5.2 RHEL版本差异对照:6/7/8/9的坑各有不同
同一套配置思路,换到不同版本上,细节差距挺大。我整理了一张速查表:
| RHEL 版本 | 包管理器 | 仓库目录结构 | $releasever展开值 | 典型坑 |
|---|---|---|---|---|
| 6 | yum 3.2 | 单一 os 目录 | 6Server | CentOS 6 已 EOL,镜像源只剩 vault 归档 |
| 7 | yum 3.4 | 单一 os 目录 | 7Server | 官方 CDN 慢,需手动配国内源 |
| 8 | dnf/yum 4 | BaseOS + AppStream | 8 | module stream 概念引入,部分包需先dnf module enable |
| 9 | dnf 4 | BaseOS + AppStream | 9.2 | 极简安装镜像不自带 packages 目录,需用完整 DVD |
RHEL 6 的 yum 版本很老,对 https 支持不完善,配国内源时建议用http://而不是https://,不然会报 SSL 相关的错误。RHEL 8 和 9 则反过来,阿里云镜像站已经强制 https 支持,直接用就行。
RHEL 8/9 还有一个 module stream 的坑:比如你要装 nodejs,yum install nodejs可能会提示 "No match for argument",因为 nodejs 的版本是通过模块方式管理的。需要先查看可用的模块流:
dnf module list nodejs dnf module enable nodejs:18这个机制在 RHEL 7 上完全不存在,如果你按照 7 的经验去操作 8/9,大概率会在这里卡一下。
5.3 其他高频问题速查表
| 报错信息 | 原因 | 解决办法 |
|---|---|---|
| Public key for xxx is not installed | 开 gpgcheck 但没导入公钥 | rpm --import <公钥地址> |
| Cannot retrieve metalink for repository | 官方金属链不可达 | 清掉官方 repo,只留可用的镜像/本地源 |
| Delta RPMs disabled | dnf 的正常提示,不是错误 | 忽略,或者安装 deltarpm 开启增量 |
| Protected multilib versions | 系统同时存在不同架构的同名包 | 不要混装 CentOS/RHEL 包,或--setopt=protected_multilib=false谨慎绕过 |
| No package xxx available | 当前启用的仓库里没有这个包 | 检查 EPEL 是否配置,或yum search xxx确认包名 |
| File repomd.xml does not exist | 本地目录没跑 createrepo | 对目录执行createrepo /data/localrepo |
比较隐蔽但我也遇过一次的是:repo 文件名以.repo结尾但编码不对,文件里是 UTF-8 BOM 或者带 Windows 换行符,yum 解析时把仓库 id 解析成了乱码。排查方法很简单,用cat -A /etc/yum.repos.d/xxx.repo看一眼,如果行尾出现^M$而不是$,就用dos2unix转一下,或者重新用 Linux 环境写一遍。
最后再分享一个我自己的习惯:在一台需要长期维护的 RHEL 服务器上,本地源打底是必须的,但我会额外配一个 EPEL 源来兜底第三方软件。EPEL(Extra Packages for Enterprise Linux)是 Fedora 社区维护的 RHEL 附加仓库,里面有大量官方源不收录的工具,比如 htop、iftop、jq 这些。做法是在本地源 repo 文件之外单独建一个epel.repo,只在需要时临时启用。这样既有本地源的版本管控能力,又不至于在装运维工具的时候发现自己啥都装不了。