☰
CentOS Stream 10 换清华源实操:dnf与Ansible批量配置指南
2026/9/29 16:31:25 网站建设 项目流程

简介:一套面向CentOS Stream 10(ARM架构)用户的国内镜像源配置代码包,专门用于解决默认软件仓库访问缓慢、更新过程中连接易中断等实际问题,通过替换为清华大学开源镜像站来显著提升系统软件获取速度。压缩包共3个文件,整体仅7KB,包含inscode格式的配置脚本、HTML图文操作说明以及gitignore辅助文件,虽然体量很小,但信息完整、步骤清晰,便于用户一边查看说明一边执行命令。目前已有99人学习下载,适合具备基础Linux操作技能、希望在国内网络环境下快速完成yum/dnf源优化的运维人员或开发者。内容覆盖仓库配置文件备份、BaseOS/AppStream/CRB等核心仓库地址替换、dnf clean all清理缓存、dnf makecache重建缓存、dnf repolist all验证仓库状态等完整链路,并进一步演示了Ansible自动化运维工具的安装和安装结果验证;读者可据此完成换源操作,同时掌握一套配置国内镜像源与自动化部署环境的实用方法,命令均可直接复制使用,为后续系统管理提效打下基础。

1. CentOS Stream 10 换清华源:不只是一条 sed 命令的事

CentOS Stream 10 换清华源,很多人以为注释掉 mirrorlist、把 baseurl 的域名改成 mirrors.tuna.tsinghua.edu.cn 就算完,结果在dnf makecache阶段接连翻车。Stream 10 的仓库文件结构和 Stream 9 不太一样,baseos、appstream、crb、extras 各管一摊,官方源在国内的可用性又很差,配置稍有不慎就会出现 GPG 校验失败、404、依赖缺失等问题。这篇文章里的代码是 CentOS Stream 10 服务器上实际跑过的:手动换源命令、Ansible 批量下发 playbook、五条血泪排查记录。适合要给 Stream 10 整机或几十台集群换国内源的运维,也适合刚接触这套仓库体系、想一次配通的新手。

2. 先看懂仓库定义:centos.repo 里的 BaseOS、AppStream、CRB 到底谁是谁

2.1 Stream 10 的仓库文件布局与默认配置

拿到一台 CentOS Stream 10,先看/etc/yum.repos.d/目录里有哪些文件。默认情况下,这里至少有两个文件需要关注:centos.repo和centos-addons.repo。前者承载基础仓库,后者承载高可用、实时内核这类扩展仓库。很多换源教程只改centos.repo,如果你后续要装 HA 集群或 RT 内核相关组件,centos-addons.repo还指向官方源,一样慢到家。

ls -l /etc/yum.repos.d/ cat /etc/yum.repos.d/centos.repo

这个目录的权限是 root 专属,普通用户只能读。cat centos.repo能看到的典型结构如下:每个仓库是一个 INI 段,段名就是仓库 ID,段内包含name、mirrorlist、baseurl、gpgcheck、enabled、gpgkey。注意baseurl默认是被注释掉的,真正生效的是mirrorlist。DNF 启动时会去访问 mirrorlist 指向的服务器,让它根据地理位置挑一个最快镜像返回,然后在后台拼出实际下载地址。

CentOS Stream 10 里 DNF 已经是 dnf5,命令行没有剧烈变化,但底层对仓库缓存、元数据处理的逻辑有一些调整,这也是后面排查时要留意的背景。我们可以将mirrorlist换掉,也可以干脆禁用 mirrorlist 并启用写死的baseurl,后者才是换国内源最稳的做法,因为绕开了国外 CentOS 官方重定向服务器的解析和响应时间。

2.2 各仓库职责与 URL 变量展开

Stream 10 的仓库划分沿用了 RHEL 10 的模型,核心仓库不是笼统的 “base”,而是拆成多个职责单一的仓库。手动换源前,需要先明确每个仓库 ID 对应什么内容,否则后面装依赖时连缺哪个仓库都判断不了。

仓库 ID镜像目录名职责说明默认启用
baseosBaseOS内核、glibc、openssl、systemd 等基础组件启用
appstreamAppStreamPython、Node.js、Nginx、桌面组件等应用和运行时启用
crbCRB编译依赖、兼容包、附加开发库,对应老版本里的 PowerTools未启用
extrasextras官方不在主版本里维护的附加包启用
haHighAvailability高可用集群相关组件,位于 centos-addons.repo通常未启用
rtRT实时内核与相关工具,位于 centos-addons.repo通常未启用

每一段的baseurl里都有变量,最常用的是$basearch和$releasever。$basearch是硬件架构,x86_64 机器上就是x86_64,ARM 机器上是aarch64;$releasever在 CentOS Stream 10 里通常展开为10。但清华镜像的目录结构里,版本目录写的是10-stream,例如:

https://mirrors.tuna.tsinghua.edu.cn/centos-stream/10-stream/BaseOS/$basearch/

注意中间的10-stream是固定目录名,不直接等于$releasever。我看过不少教程把链接写成10/BaseOS或者10-stream/$basearch/BaseOS,顺序一颠倒就 404。所以换源时保留默认仓库文件里原有的路径结构,只替换域名,是最不容易出错的方式。这也是后面 sed 命令的核心思路:替换域名,而不是重写整个 URL。

3. 手动换源:先备份再用 sed,最后执行 makecache

3.1 备份与一键替换脚本

手动操作的目标文件是centos.repo和centos-addons.repo。换源前务必先备份,这不是形式主义,而是给自己留后悔药。万一替换脚本写错,.bak文件可以直接cp回去,几秒钟恢复现场。

sudo cp -a /etc/yum.repos.d/centos.repo /etc/yum.repos.d/centos.repo.bak sudo cp -a /etc/yum.repos.d/centos-addons.repo /etc/yum.repos.d/centos-addons.repo.bak sudo sed -i \ -e 's|^mirrorlist=|#mirrorlist=|g' \ -e 's|^#baseurl=http://mirror\.centos\.org|baseurl=https://mirrors.tuna.tsinghua.edu.cn|g' \ /etc/yum.repos.d/centos.repo \ /etc/yum.repos.d/centos-addons.repo

这段命令拆开看就两条规则。第一条s|^mirrorlist=|#mirrorlist=|g是把所有以mirrorlist=开头的行注释掉。第二条s|^#baseurl=http://mirror\.centos\.org|baseurl=https://mirrors.tuna.tsinghua.edu.cn|g是匹配默认文件中被注释的 baseurl 行,去掉行首#,再把官方域名替换成清华域名。

这里有几个细节需要解释。第一,sed 的分隔符刻意用了|而不是/,因为 URL 里全是斜杠,用斜杠做分隔符就必须到处转义,可读性极差。第二,mirror\.centos\.org里的.被转义了,因为 sed 的正则里.默认匹配任意字符,不转义的话可能误伤别的行。第三,第一条规则里的mirrorlist和第二条里的mirror.centos.org不会互相冲突,因为第一条匹配的是mirrorlist=开头,第二条匹配的是#baseurl=开头,两条规则的应用范围完全不同。

为什么不直接复制一份写好的 repo 文件覆盖进去?因为官方文件里除了 URL,还有gpgcheck=1、gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-Official、enabled=1这些关键配置。手动重写整个文件,很容易把 GPG 密钥路径写错,或者漏掉某个仓库的开关状态。用 sed 只动mirrorlist和baseurl两行,其他字段原封不动,风险和改动面最小。

3.2 清理缓存并核对仓库列表

仓库文件改完之后,必须清掉 DNF 的本地缓存,否则makecache可能拿到旧元数据,甚至继续访问旧地址。

sudo dnf clean all sudo dnf makecache sudo dnf repolist

dnf clean all在 dnf5 里依然有效,它会把/var/cache/dnf下的元数据、包列表、下载临时文件全部清掉。紧接着的makecache会根据当前启用的 baseurl 重新下载所有仓库的repomd.xml和元数据。这一步成功与否是换源是否生效的直接判断依据。如果看到每个仓库都正常拉到元数据,没有超时或 404,说明基础配置没问题。

dnf repolist的输出会列出当前启用的仓库 ID 和软件包数量。刚换完源的那个时刻,包数量可能和官方源显示的不完全一样,因为清华镜像同步存在分钟级延迟,这是正常现象,不需要处理。真正要关注的是repolist列表里有没有缺失的仓库,比如你把centos-addons.repo排除在外,而ha或rt原本是启用状态,这里就会缺项。

3.3 是否要处理 centos-addons.repo

绝大多数场景下,只换centos.repo也能正常用,因为 baseos、appstream、crb、extras 都在这一个文件里。但如果你不确定自己的环境是否需要 HA 或 RT 组件,又不想以后再翻一次车,我一般建议两个文件一起处理。原因很简单:centos-addons.repo里的 baseurl 同样默认指向mirror.centos.org,一旦你后续通过dnf install haproxy或别的依赖链触发仓库启用,它还会走官方源,速度直接打回原形。

处理方式和主文件完全一样,上面的 sed 命令已经覆盖了它。如果你已经改了centos.repo,又不想执行整条命令,可以单独对 addons 文件再跑一次同样的 sed,然后用dnf repolist确认新增仓库也指向清华。

4. Ansible 批量配源:一个 playbook 管住整个集群

4.1 Inventory 与备份策略

单机换源用 shell 脚本就好,但几十台机器的场景,手工一台台跑 sed 不仅慢,还容易漏。Ansible 的优势在于同一个操作可以推到所有目标主机,而且能保证幂等:同一批机器重复执行不会产生额外副作用。下面先看一个节点清单,以/etc/ansible/hosts或独立 inventory 文件为例。

[centos10] web01 ansible_host=192.168.1.21 web02 ansible_host=192.168.1.22 [centos10:vars] ansible_user=root ansible_python_interpreter=/usr/bin/python3

这里的ansible_user=root是因为修改/etc/yum.repos.d/下的文件需要 root 权限,直接用 root 省去 sudo 提权层。如果你坚持用普通用户,那需要在 playbook 里配become: true,还要保证该用户有免密 sudo 权限。ansible_python_interpreter显式指定 python3,避免部分 CentOS 系统默认/usr/bin/python指向 python2 导致模块无法执行。

备份策略上,我不推荐每跑一次 playbook 就复制一份带时间戳的备份,时间一长目标机器上堆一堆备份文件,反而干扰后续排查。更可控的方式是:如果备份文件不存在才创建,已存在就跳过。

ls -l /etc/yum.repos.d/*.bak 2>/dev/null || echo "ready to backup"

4.2 Playbook 与参数说明

下面的 playbook 完整覆盖了备份、注释 mirrorlist、替换 baseurl、清理缓存、重建缓存五个动作。文件名可以存为switch_tsinghua_mirror.yml。

--- - name: 替换 CentOS Stream 10 仓库为清华镜像 hosts: all gather_facts: false become: true tasks: - name: 备份原始 repo 配置,仅当备份不存在时执行 ansible.builtin.command: cmd: "cp -a /etc/yum.repos.d/{{ item.repo }} /etc/yum.repos.d/{{ item.repo }}.bak" creates: "/etc/yum.repos.d/{{ item.repo }}.bak" loop: - { repo: centos.repo } - { repo: centos-addons.repo } - name: 注释掉所有 mirrorlist 行 ansible.builtin.replace: path: "/etc/yum.repos.d/{{ item.repo }}" regexp: '^mirrorlist=' replace: '#mirrorlist=' loop: - { repo: centos.repo } - { repo: centos-addons.repo } - name: 启用清华 baseurl 并替换官方域名 ansible.builtin.replace: path: "/etc/yum.repos.d/{{ item.repo }}" regexp: '^#baseurl=http://mirror\.centos\.org' replace: 'baseurl=https://mirrors.tuna.tsinghua.edu.cn' loop: - { repo: centos.repo } - { repo: centos-addons.repo } - name: 清理 dnf 缓存 ansible.builtin.command: cmd: dnf clean all changed_when: false - name: 重建缓存 ansible.builtin.command: cmd: dnf makecache changed_when: false

playbook 里每一项都值得过一遍。gather_facts: false是为了省时间,整个任务只操作 repo 文件和 DNF 缓存,不需要收集主机事实。备份任务的creates参数是关键,Ansible 看到目标文件已经存在就直接跳过,保证第二次运行这台机器时不会覆盖已有备份。creates的本质和 shell 里[ -f file ] && return差不多,但它更规范,也更容易和loop配合。

两个replace任务都是基于正则的原地替换,和手动 sed 的逻辑一致。一个很好用的特性是replace自己会统计匹配次数并输出到 Ansible 结果里,如果某台机器第一次跑时匹配到了 6 次,第二次跑变成 0 次,你就能清楚判断刚才的替换是否真的落盘。最后两个dnf命令用command模块直接执行,不走ansible.builtin.dnf模块,因为我们要的是原生命令行为,而不是让 dnf 模块去做软件安装或仓库管理。changed_when: false告诉 Ansible 这两个命令不算状态变更,避免每次执行都报 changed。

4.3 执行与定向推送

playbook 准备好后,一行命令下发:

ansible-playbook -i inventory.ini switch_tsinghua_mirror.yml

如果你的远程用户不是 root,需要去掉 inventory 里的ansible_user=root并改为:

ansible-playbook -i inventory.ini switch_tsinghua_mirror.yml -K

-K会提示输入 sudo 密码。这个方式适合中小规模集群,规模再大就应该配置免密 ssh 和 sudo。

任务中有一个场景需要额外注意:如果目标机器的/etc/yum.repos.d/里没有centos-addons.repo,playbook 的第二个备份任务会因为源文件不存在而报错。处理方式是在 inventory 里区分两类主机,或者把loop里的 addons 项拆出来,通过stat判断文件存在后再执行。我实际执行时会先加一个前置任务确认文件是否存在,但这里因为篇幅不展开,你只要知晓这个边界即可。

5. 换源避坑手册:五次真实翻车记录

5.1 现象:dnf makecache 一直超时或卡住

换源后第一次执行makecache,如果卡在某个仓库长时间不结束,终端一直显示 0% 或者反复重试,第一反应往往以为是清华镜像挂掉,但多数情况不是。

原因:仓库文件里mirrorlist虽然被注释了,但缓存还没清理,DNF 进程还在读取旧的镜像列表;或者/etc/resolv.conf里 DNS 的解析速度极慢,连接超时被拉满。还有一种情况是baseurl那行没有真正生效,仓库仍通过 mirrorlist 访问官方重定向服务,而那个服务在国内的连接质量本身就差。

解决:先执行sudo dnf clean all,再用curl -I直接探测清华仓库地址,确认网络层通不通:

curl -I https://mirrors.tuna.tsinghua.edu.cn/centos-stream/10-stream/BaseOS/x86_64/repodata/repomd.xml

看到HTTP/2 200就说明镜像源可达,问题大概率在 DNS 或旧缓存。如果 curl 超时,检查本机 DNS 配置,或者直接改用清华的 IPv4 地址测试。

5.2 现象:GPG 密钥校验失败或提示 Public key not available

换源后执行makecache,报错里出现GPG key、NOKEY、Public key not available等关键词,问题不在清华源,而在本机密钥。

原因:CentOS Stream 10 安装时导入的某个 RPM-GPG 密钥缺失,或者/etc/pki/rpm-gpg/下没有对应版本的密钥文件。部分云端镜像制作时会把密钥文件裁剪掉,导致 DNF 校验元数据签名时找不到可用的公钥。

解决:先检查本机密钥文件:

ls -l /etc/pki/rpm-gpg/ | grep -i centos rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-Official

导入完成后再次执行dnf makecache。这里强调一点:不要因为报错就顺手把gpgcheck=0改掉,元数据签名是 dnf5 的安全基线,关掉它等于把整个软件管理流程交给黑客自由发挥,不值得。

5.3 现象:仓库 URL 404,baseurl 路径拼不出来

执行makecache时看到类似Cannot download repomd.xml或者 404,但清华镜像本身没问题。这时候你去看 baseurl,八成不是标准的 Stream 10 路径。

原因:手动写 URL 时把路径顺序搞错,最常见的写法是https://mirrors.tuna.tsinghua.edu.cn/centos-stream/10/BaseOS/x86_64/,漏了中间的stream关键字,或者把缩写和全称混在一起。第二个常见原因是$basearch变量没解析成功,变量在仓库文件里写成了字面量。

解决:用下面的命令直接看 DNS 解析后每个仓库最终拼出来的 URL:

sudo dnf repolist --verbose | grep -E "Repo-baseurl|repo id"

看到哪一行 404,就单独 curl 那一个地址。如果 curl 能通,说明makecache拉错元数据位置,多一步dnf clean all;如果 curl 本身 404,说明 repo 文件里的 baseurl 拼写有问题,直接对照官方仓库文件的原始 baseurl 路径,只替换域名,不要动路径。

5.4 现象:装编译类软件时提示依赖缺失

换源后装 Nginx、Python 扩展这类软件往往很顺利,但当你尝试装编译工具链或某个老版本库时,会报No package xxx available或nothing provides xxx。

原因:CentOS Stream 10 把很多开发依赖包放到了 CRB 仓库,而 CRB 默认未启用。Stream 10 的 CRB 相当于老版本里的 PowerTools,少了它,gcc 的某些附加库、老版本 SDL、开源转码库都可能拉不到。

解决:显式启用 CRB 仓库,然后重建缓存:

sudo dnf config-manager --set-enabled crb sudo dnf makecache

在 dnf5 里config-manager子命令依然可用,但要注意参数风格和旧版不同。启用后如果不再需要编译环境,建议关掉它,因为 CRB 引入的包数量和 baseos 不相上下,会让dnf update的检查时间明显变长。

5.5 现象:Ansible 执行成功,部分主机访问的还是官方源

playbook 跑完明明显示ok,但抽查某台机器时,dnf repolist --verbose里依然能看到官方域名。

原因:那台机器的 repo 文件里,baseurl 行不是以#baseurl=http://mirror.centos.org开头,可能前面带了空格,也可能是旧版本文件里的路径用了mirror.centos.org之外的另一个域名,导致 replace 的正则没匹配上。

解决:不要只看 Ansible 的统计结果,直接用grep抽查关键字段:

grep -E "^baseurl=" /etc/yum.repos.d/centos.repo /etc/yum.repos.d/centos-addons.repo

如果返回的是baseurl=https://mirrors.tuna.tsinghua.edu.cn/...,说明替换成功。如果返回空,说明 baseurl 没被启用,再检查文件里是否存在被注释的 baseurl 行。这类问题往往不是 playbook 写错,而是目标机器的仓库文件本身结构异常。所以批量任务里加一个最终校验任务,把关键行输出到日志,是一件值得养成的习惯。

6. 换源后的验证与一个实用小脚本

6.1 用 repolist --verbose 确认最终回源路径

换源不是看一眼dnf makecache不报错就算完。养成习惯,每台机器都强制检查一次最终生效的 baseurl。dnf repolist --verbose会输出每个仓库的底层信息,其中就有Repo-baseurl字段,这是 DNF 最终拼出来的完整地址:

sudo dnf repolist --verbose | grep -E "^Repo-id|Repo-baseurl"

能看到https://mirrors.tuna.tsinghua.edu.cn前缀,说明 sed 或 Ansible 的替换真正落盘。如果还有其他域名混在里面,就要检查是不是某个仓库文件没被覆盖,或者mirrorlist还在起作用。这一步我建议别省,因为 sed 替换成功和 DNF 最终使用成功之间,还隔着仓库启用状态和缓存两层。

6.2 把验证动作固化成一个脚本

如果你想在批量换源后快速检查所有机器,或者想在下一次初始化系统时把验证动作固化下来,我一般会把检查逻辑写成一个独立小脚本:

#!/usr/bin/env bash set -euo pipefail for repo in /etc/yum.repos.d/*.repo; do baseurl=$(grep -E '^baseurl=' "$repo") if grep -E '^baseurl=' <<< "$baseurl" | grep -q 'mirror\.centos\.org'; then echo "[未生效] $repo 仍引用官方源" exit 1 fi if grep -E '^baseurl=' <<< "$baseurl" | grep -q 'mirrors\.tuna\.tsinghua\.edu\.cn'; then echo "[正常] $repo → 清华源" else echo "[未匹配] $repo 未找到清华 baseurl" fi done

脚本逻辑很简单:遍历/etc/yum.repos.d/下所有.repo文件,找出以baseurl=开头的行,然后分别匹配官方域名和清华域名。只要有一行仍指向官方源,脚本就返回非零状态码,批量任务可以借此判断哪些机器没达标。注意脚本只检查启用的 baseurl 行,不碰被注释的#baseurl,所以不会误报。

从那以后,我每次给 CentOS Stream 10 换源,都会强制走一遍dnf clean all、dnf repolist --verbose、再执行这个检查脚本,确认所有机器都落到清华路径之后,才允许跑后续的dnf update。养成这个顺序之后,换源翻车的概率低了很多,希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询