
上周又有人在群里发截图Ubuntu 22.04 的终端里敲下yum install vim回了一句 command not found接着照着网上搜到的帖子apt install yum装上再敲同样的命令屏幕上滚出几十行红字依赖报错。这个场景我见过太多次了。Linux 世界里 apt 和 yum 分属两个不同的发行版家族Ubuntu 是 Debian 系原生包管理器是 apt 加 dpkgyum 是 Red Hat 系的东西它的下一代叫 dnf。在 Ubuntu 上装 yum、给 yum 配源、做源的更新这一整套操作本身是成立的但它的意义和大多数人的预期完全不同中间还埋着几个很容易踩的坑。这篇就把 Ubuntu 上装 yum 的完整过程、yum 源文件的字段结构、换源与刷缓存的动作顺序、以及几类高频报错的排查链路一次讲透同时也会把 Ubuntu 自己换 apt 源的正确姿势单独拎出来说清楚因为搜Ubuntu 源更新的人里一大半真正想要的是后者。1. 别急着敲 apt install yum先分清 apt、dpkg、yum、dnf 各自的辖区1.1 两套体系除了都叫包管理器几乎没有任何共同点Debian 系的软件包格式是.deb底层工具是dpkg负责解包、写数据库、记录文件清单apt站在 dpkg 上面负责去远程仓库拉元数据、算依赖关系、按顺序调用 dpkg。整个体系的本地数据库在/var/lib/dpkg/下用dpkg -l就能看到系统里所有已安装的包。Red Hat 系的软件包格式是.rpm底层工具是rpm数据库默认在/var/lib/rpm/yum是 rpm 之上的依赖解析和仓库管理工具配置文件读/etc/yum.conf和/etc/yum.repos.d/*.repo缓存落在/var/cache/yum/。CentOS 8 之后官方主推 dnfdnf 用 libsolv 做依赖求解速度和依赖冲突处理比 yum 3.x 好不少但配置文件格式和 repo 文件语法基本兼容所以老教程里的.repo写法在 dnf 上照样能跑。这两套体系的核心差异在于它们各自维护一套独立的已安装包数据库互不感知。你在 Ubuntu 上用 dpkg 装了 vimrpm 数据库里依然是一片空白反过来你在 Ubuntu 上把某个 rpm 包装进去了dpkg 也完全不知道这些文件的存在。这个互不感知是后面一切麻烦的根源记住这一点后面很多现象就都能解释了。1.2 到底什么场景会真的在 Ubuntu 上装 yum不是所有在 Ubuntu 上找 yum 的人都是走错了门。我实际遇到过这几类需求交付脚本兼容性测试。甲方给的部署脚本开头就是yum install -y xxx你想在自己的 Ubuntu 开发机上先跑一遍看看流程看看到底会卡在哪一步。CI 流水线跑在 Ubuntu runner 上但代码里带了针对 CentOS 的构建逻辑需要验证语法层面的正确性。给别的机器准备源文件。手上有几台 Rocky 或 CentOS 的服务器要离线配源想在自己的 Ubuntu 笔记本上把.repo文件写好、把 rpm 包按目录结构整理好再打包传过去。教学和自学。想直观对比两套包管理器的输出差异或者单纯想搞清楚yum clean all到底删了什么文件。这几类需求里前两类勉强能靠 Ubuntu 上的 yum 跑通一部分第三类根本不需要装 yum写个文本文件而已第四类装完就能看到现象。真正用 Ubuntu 上的 yum 去给 Ubuntu 装软件这个需求是不存在的。1.3 不同 Ubuntu 版本里 yum 包的可用性差别很大Debian 和 Ubuntu 的仓库里确实有一个叫yum的包但它和 RHEL 系自带的 yum 不是同一个东西。Debian 侧对它做过移植和裁剪去掉了大量和 RHEL 强绑定的逻辑也未必带着完整的插件生态。更麻烦的是各版本情况不一致较老的版本能直接装依赖链完整较新的版本里可能因为依赖包被移除而装不上或者装上之后插件缺失。这里没有一张能覆盖所有版本的对照表唯一靠谱的做法是在目标机器上现场确认apt-cache policy yum apt-cache depends yum第一条命令看仓库里到底有没有这个包、候选版本是多少、当前是否已装第二条把依赖树列出来看看依赖的 python 解释器、rpm 库这些能不能被满足。如果apt-cache policy yum的输出里 Candidate 那一栏是(none)说明这个源里根本没有后面就不用费劲了直接跳到第 4、5 章去研究 repo 文件结构用不上装 yum 这一步。顺带说一句WSL 里的 Ubuntu 也是 Ubuntu仓库情况同样取决于发行版本号不是WSL 特供版别指望它有什么不同。2. 装 yum 前必须核对的三项环境信息与一条回滚预案2.1 三条命令把底摸清发行版、架构、Python 现状动手之前先采集三组信息后面排查问题时全靠它们。第一组是发行版和版本号lsb_release -a cat /etc/os-releaselsb_release不一定预装/etc/os-release是标准文件一定有。搞清楚自己是 20.04、22.04 还是 24.04这不只是知道版本这么简单——24.04 的 apt 源格式换了后面第 5 章会展开讲。第二组是架构uname -m dpkg --print-architecture输出x86_64和amd64是同一件事只是两套命名习惯。如果是 ARM 机器会显示aarch64/arm64这一点在你后面去镜像站找 rpm 包路径时非常关键路径里的x86_64换成aarch64之后很多包根本不存在。第三组是 Python 现状which python3 python python3 -V head -1 /usr/bin/yum 2/dev/null || echo yum 尚未安装最后那条命令是提前看一眼如果 yum 已经存在它的脚本用哪个解释器启动。这类工具大多是用 Python 写的脚本第一行的 shebang 决定了它由哪个解释器执行一旦这个解释器和脚本语法不匹配就会报 SyntaxError而报错信息往往看不出是解释器的问题。这是后面第 6 章一条排查链路的伏笔。2.2 依赖链上最容易被忽略的一环系统 Python 不要乱动这里插一段我认为比装 yum 本身更重要的经验。RHEL 系机器上yum 和系统自带的 Python 版本是强绑定的很多老版本 yum 脚本头一行写的就是 Python 2。有些人为了跑某个新工具手动把/usr/bin/python指向了 Python 3结果 yum 立刻全线崩溃连卸载重装都做不了最后只能拿救援模式进系统修。这个坑在服务器运维里属于经典事故。Ubuntu 上虽然情况不同但同一个道理不要把系统默认的 Python 解释器做全局替换。真要装新版本 Python用update-alternatives管理多版本或者用虚拟环境隔离别去动/usr/bin/python3这个符号链接指向的实体。Ubuntu 的系统工具链里有大量脚本依赖它动了之后 apt 自己都可能出问题。在 Ubuntu 上装 yum 之所以要提这个是因为apt install yum会顺带拉入 rpm 相关的库和工具这些工具里同样有脚本依赖解释器。装之前确认系统 Python 是干净的能省掉后面一堆玄学问题。2.3 备份清单和回滚路径装之前把这几样东西记下来或备份好/etc/apt/sources.list和/etc/apt/sources.list.d/整个目录打包成 tar 放到家目录。后面折腾源的时候手一抖改错了直接解回来。/etc/yum.conf和/etc/yum.repos.d/如果已经存在的话。当前已装包清单dpkg --get-selections ~/pkg-list-before.txt。这条命令在系统崩了想对比差异时能救命。回滚路径也要想清楚。卸载就用sudo apt remove yum但这里有个细节apt remove yum只删 yum 本身它拉入的 rpm 等依赖会留在系统里。如果你确定不再需要可以用sudo apt autoremove清理孤立的依赖包但执行前一定先加--dry-run看一眼要删什么sudo apt autoremove --dry-run我见过有人直接 autoremove结果把一些看起来没人依赖但实际上被手工装的工具一起清掉了。养成先 dry-run 的习惯代价是几秒钟收益是避免一次事故。3. Ubuntu 上把 yum 装起来从 apt install 到命令能执行3.1 更新索引并安装标准流程只有两步sudo apt update sudo apt install -y yum第一条刷新本地索引第二条真正安装。如果这一步报无法定位软件包 yum说明当前源里没有或者源本身有问题先回去看第 2 章的环境确认再跳到第 5 章检查 apt 源配置。安装过程中留意终端输出里列出了哪些新增包。典型的会带上rpm、rpm-common以及若干 Python 库。这些名字记一下出问题的时候知道是哪个组件在捣乱。3.2 装完之后为什么几乎装不了任何软件这是所有人装完 yum 之后最想不通的地方命令能跑yum --version也正常输出但yum install任何一个包都会失败。原因在 1.1 节已经埋下了这里展开说。yum 装包的工作流大致是读 repo 文件里的地址下载 repodata 元数据在本地算出依赖树然后调用 rpm 把包写进 rpm 数据库同时校验文件冲突。问题出在最后一步——Ubuntu 上的 rpm 数据库是刚被创建出来的空库里面一条记录都没有。于是 yum 会认为系统里连 glibc、bash 这些东西都没装然后试图从仓库里把整个基础系统重装一遍而这些 rpm 包安装时会往/usr/bin、/lib这些目录写文件和 dpkg 已经管理的文件直接冲突。就算你强行用--nodeps跳过依赖检查塞进去一个包结果也不会好dpkg 不知道这些文件存在下次 apt 升级时可能把它们覆盖掉或者因为文件冲突直接报错停下。系统会进入一种两套包管理器互相打架的状态非常难受。所以结论很明确Ubuntu 上的 yum 可以当配置解析器和元数据下载器用不能当真正的包管理器用。想验证这个结论随便挑一个包试一次就知道了。如果目标只是在 Ubuntu 上拿到某个 rpm 文件有更直接的路子按镜像站上的 repodata 索引里的路径直接用wget下载或者用apt-get download拿 deb 包。没必要绕道 yum。3.3 验证安装结果与第一轮检查装完之后跑这几条yum --version yum repolist all ls -l /etc/yum.repos.d/ cat /etc/yum.confyum --version正常会打印版本号和配置目录位置。如果这里直接抛出一段 Python 的 SyntaxError 或者 ImportError说明脚本的 shebang 指向的解释器和脚本语法对不上用head -1 /usr/bin/yum看一眼它调的是哪个解释器再用apt-cache depends yum核对依赖列表看是不是某个解释器或库没有正确装上。yum repolist all会列出识别到的所有仓库包括启用和禁用的。输出里出现repolist: 0是正常的因为/etc/yum.repos.d/目录刚开始一般是空的或者只有 Ubuntu 打包时带的占位文件。这一步的目的不是让它列出多少仓库而是确认 yum 能正常读取配置目录并且没崩。4. 把 .repo 文件拆成零件看yum 源的每一个字段在管什么4.1 一个仓库文件的完整字段说明yum 读的所有仓库定义都在/etc/yum.repos.d/目录下而且只认.repo后缀。文件名随便起但后缀必须是.repo写成.repo.txt、.conf都不会被读取。这个细节坑过不少人尤其是从 Windows 传文件上来的时候系统自动加了后缀。一个典型的仓库定义长这样[base] nameBase Repository baseurlhttp://mirrors.aliyun.com/rockylinux/9/BaseOS/x86_64/os/ enabled1 gpgcheck1 gpgkeyfile:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9 metadata_expire3600 cost1000逐字段说清楚字段作用注意事项[base]仓库 ID必须全局唯一不能有空格只用字母数字和短横线name人类可读的描述随便写只影响显示baseurl仓库根地址指向的是 repodata 所在目录的上级目录mirrorlist镜像列表地址与 baseurl 二选一同时存在时 mirrorlist 优先enabled是否启用1 启用0 禁用默认 1gpgcheck是否校验包签名1 校验0 不校验gpgkey公钥位置支持file://和http://两种写法metadata_expire元数据缓存有效期秒设太大会导致新包看不到cost仓库优先级权重数值越小优先级越高exclude排除的包名支持通配符如kernel*关于baseurl指向哪一层这是最容易写错的地方。你打开浏览器访问镜像站看到的是.../9/BaseOS/x86_64/os/这样的目录里面有一个repodata子目录和一个Packages子目录。baseurl 就写这个os/这一层不要写到 repodata 里面去。写成.../os/repodata/是最常见的低级错误报错信息是下载 repomd.xml 失败。4.2 mirrorlist 和 baseurl 该选哪个mirrorlist 指向一个纯文本列表里面一行一个镜像地址yum 会从中选一个用。理论上更健壮某个镜像挂了能自动切下一个。但它有两个现实问题一是列表文件需要维护方持续更新很多老发行版停止支持后这个列表就没人管了指向的地址全部失效二是排查问题时链路变长你不确定 yum 最终用的是哪个地址。baseurl 是硬编码一个地址简单直接出问题一眼就能看出来。我的建议是在自己维护的机器上一律用 baseurl 写死一个国内公共镜像站的地址同时把 mirrorlist 那行注释掉或者删掉。理由是可控性远比自动切换重要镜像站本身可用性都挺高真挂了手动改一行也很快。而且写死地址之后第 6 章那类下载元数据失败的报错排查会简单很多直接curl那个地址看返回码就行。4.3 gpgcheck 关不关一个需要想清楚的问题gpgcheck 决定 yum 是否用公钥去校验下载下来的 rpm 包签名。校验能挡住的场景是镜像站被劫持、下载过程中包被篡改、或者有人故意往仓库里塞了伪造的包。很多教程为了一次跑通直接教你写gpgcheck0省掉配公钥的麻烦。这样做确实能立刻解决报错但你要清楚代价你放弃了验证包来源的能力装进来的东西是什么全凭运气。生产环境上我强烈建议保持gpgcheck1公钥从发行版官方的 keyring 包里取比如 Rocky 系统上可以装rocky-release或rocky-gpg-keys包公钥会自动落到/etc/pki/rpm-gpg/目录直接引用就行。如果确实需要临时关掉校验来先跑通流程那就只关这一个仓库别去改全局配置/etc/yum.conf也别在多个仓库里批量关。问题定位完之后马上改回来。5. 源更新的动作分解换地址、清缓存、重建元数据谁先谁后5.1 换源改的是哪一行以及 Ubuntu 自己换源的正确姿势先纠正一个高频混淆在 Ubuntu 上谈源的更新指的应该是 apt 源不是 yum 源。这两个是完全不同的文件。Ubuntu 的 apt 源在较老版本里是/etc/apt/sources.list单文件一行一条记录。换源就是把里面的archive.ubuntu.com、security.ubuntu.com替换成国内镜像站域名。但 Ubuntu 24.04 换了格式改用/etc/apt/sources.list.d/ubuntu.sources是 deb822 风格的结构化文件Types: deb URIs: http://archive.ubuntu.com/ubuntu/ Suites: noble noble-updates noble-backports Components: main restricted universe multiverse Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg拿老教程里的sed命令去替换 24.04 上已经不存在的sources.list命令会静默成功但什么都没改然后你会很困惑为什么速度没变。所以第一步永远是确认文件在哪grep -rn archive.ubuntu.com /etc/apt/这条命令会告诉你真实的配置落在哪个文件里两边都查省得漏掉。至于用哪个镜像站选离自己网络近的就行各家都有完整的 Ubuntu 镜像。换完之后sudo apt update sudo apt-cache policy | head -20第二条命令能看出实际生效的源地址确认改动落地了。5.2 yum clean all 和 makecache 到底在删什么、下什么回到 yum 这边。改完 repo 文件之后不能马上执行安装因为本地还存着旧源的元数据。这时候要跑的是一组固定动作yum clean all yum makecacheyum clean all清理的是/var/cache/yum/下的内容具体包括packages下载下来的 rpm 文件、metadata仓库元数据、dbcache解析后的数据库缓存、headers、plugins和expire-cache几个子目录。注意它不会碰/etc/yum.repos.d/里的配置文件也不会动 rpm 数据库所以这个命令是安全的出问题的时候可以放心执行。yum makecache做的是相反方向的事把每个启用仓库的 repodata 下载到本地并解析成缓存下次安装时就不用再跑网络了。顺序不能颠倒。先 clean 再 makecache这才是用新配置重建缓存。反过来先 makecache 再 clean等于白干一遍。如果想更精细一点可以只清元数据不清包文件yum clean metadata yum makecache fastmakecache fast会先尝试复用已有缓存速度快一些。不过在刚换完源的场景下我一般还是老老实实跑完整的clean all加makecache慢几十秒换取确定性。5.3 用 Ubuntu 当跳板给 RHEL 系机器准备源文件这是我个人用得最多的场景也顺便回答为什么要在 Ubuntu 上折腾 yum 源。假设手上有一批 Rocky 9 的机器在内网不能直连外网需要在 Ubuntu 笔记本上把 repo 文件和离线包准备好再整体拷进去。流程大概是第一步在 Ubuntu 上把仓库文件写好用 Rocky 9 的镜像路径[rocky-baseos] nameRocky Linux 9 BaseOS baseurlhttp://mirrors.aliyun.com/rockylinux/9/BaseOS/x86_64/os/ enabled1 gpgcheck1 gpgkeyhttp://mirrors.aliyun.com/rockylinux/RPM-GPG-KEY-Rocky-9第二步用wget按 repodata 里的索引把需要的 rpm 拉下来按Packages/目录结构存在本地。要精确知道某个包在哪个子目录可以从primary.xml.gz里查或者更省事地用一个 Rocky 容器临时跑dnf download。第三步如果要让内网机器像访问网络仓库一样访问这个本地目录就在 Ubuntu 上起一个静态文件服务python3 -m http.server 8080 --directory /path/to/repo-root然后内网机器的 repo 文件里 baseurl 就写http://ubuntu-ip:8080/。这样完全不需要在那台 Ubuntu 上跑 yum 本身只需要它当个文件服务器加配置编辑器。这个方案的好处是分工清晰Ubuntu 负责文本和网络RHEL 系机器负责 rpm 和依赖求解两者各干自己擅长的事绕开了第 3.2 节说的那堆问题。6. 报错现场五类高频问题的定位链路6.1 下载元数据失败从 repomd.xml 往回查报错长这样Error: Failed to download metadata for repo base: Cannot download repomd.xml这条链路我按顺序查四件事第一把 baseurl 拼上repodata/repomd.xml用curl -I请求一次curl -I http://mirrors.example.com/rockylinux/9/BaseOS/x86_64/os/repodata/repomd.xml看到 404 就是路径写错了看到 200 说明地址没问题问题在本地。第二看是不是 mirrorlist 在作怪。如果 repo 文件里两行都在yum 会优先用 mirrorlist而那份列表很可能已经过期。把 mirrorlist 那行注释掉重试。第三看发行版是不是已经停止支持。CentOS 8、CentOS 7 这些版本陆续停服之后原来的镜像路径会被移走再访问就是 404。这种情况得把 baseurl 改成归档地址。判断方法很简单访问镜像站的根目录看看原来那个版本号目录还在不在。第四检查代理和时间。有些内网机器要用代理才能出网/etc/yum.conf里没配proxy就会一直失败。时间不对会导致 TLS 握手失败用timedatectl看一眼同步状态。6.2 GPG 校验失败分清是缺公钥还是真被改过两类报错要分清GPG key retrieval failed: [Errno 14] ... Public key for xxx.rpm is not installed第一种是公钥本身没拿到通常是gpgkey那行的地址访问不通或者写成了需要额外配置的格式。先curl一下那个 key 地址能不能下载。第二种是公钥有了但包的签名对不上。这可能是仓库被换过、包被重打过也可能是公钥版本不对——比如你把 Rocky 9 的公钥配到了访问 Rocky 8 仓库的配置上。核对一下公钥和仓库版本是否对应。处理这类问题正确顺序是先确认公钥能下、再确认版本匹配、最后才考虑临时关校验。不要一看到 GPG 报错就把 gpgcheck 改成 0那等于把安全机制整个拆掉。6.3 命令找不到或 Python 报错从 shebang 往回查如果敲yum提示 command not foundwhich yum ls -l /usr/bin/yum看文件是否存在、是否有执行权限。如果路径里有但执行报错看报错类型。Python 的 SyntaxError 或 ImportError 基本都指向解释器问题用head -1看 shebang 指向哪个解释器再确认那个解释器是否装了脚本需要的模块。有时候现象会伪装成别的问题比如报No module named yum看起来像 yum 没装实际是 Python 的模块搜索路径没包含 yum 的安装目录。这种情况用dpkg -L yum列出这个包装了哪些文件看看模块落在哪再对照python3 -c import sys; print(sys.path)的输出。6.4 锁文件残留Another app is currently holding the yum lock这个报错说明有个进程占着锁没释放通常是上次操作被 CtrlC 中断留下的ls -l /var/run/yum.pid cat /var/run/yum.pid先看那个 PID 对应的进程是不是还在运行。如果在跑等它跑完。如果进程早就不在了锁文件就是残留删掉即可sudo rm -f /var/run/yum.pid删之前务必确认没有正在运行的 yum 进程否则会破坏正在进行的安装事务。这个习惯比命令本身重要。6.5 依赖求解失败先分清是真缺包还是索引过期Error: Package: xxx requires: yyy这类报错的第一反应不该是去找包而是先确认元数据是新的一版。索引太旧会让 yum 看不到仓库里新增的依赖包。先跑一次yum clean all yum makecache再看。如果刷完缓存还是报缺依赖那就是仓库本身确实没有。这时候看缺的是什么如果是基础库说明仓库配置不完整比如只配了 BaseOS 没配 AppStream如果是第三方包那就是需要额外引入对应的仓库。这类问题在 Rocky、Alma 上尤其常见因为它们的软件包是按仓库拆分的缺一个仓库就缺一批包。用yum repolist列出所有启用的仓库对照官方文档确认该有的都配齐了。7. 几个我实际踩过的坑以及什么时候该放弃 yum先说一个最容易被忽略的.repo文件后缀和编码。从 Windows 传配置文件到 Linux 上文件名可能被加上了.txt行尾可能变成 CRLF。这两个问题都会让 yum 完全读不到配置而且报错信息不会告诉你原因只会说找不到仓库。拿到配置文件后先跑file /etc/yum.repos.d/*.repo如果输出里有 CRLF line terminators用sed -i s/\r$//处理一遍。这个动作应该加进肌肉记忆里。第二个坑是在 Ubuntu 上装了 yum 之后忘了它和 apt 是两套东西。有人装完 yum 之后一直在纠结为什么 yum 装的包 apt 看不到然后在两个工具之间反复横跳最后系统里文件冲突一堆。记住第 1 章的结论Ubuntu 上就以 apt 为准yum 只在明确知道自己在干什么的时候用。第三个坑是镜像站的选择要匹配发行版。把 Ubuntu 的包路径配上 CentOS 的地址或者反过来都会得到 404。不同发行版的目录结构差异不小Rocky 的包在BaseOS和AppStream两个目录下CentOS 7 是os和updates写之前去镜像站根目录逛一圈比照着教程抄快得多。至于什么时候该放弃如果你在 Ubuntu 上折腾 yum 超过半小时还是跑不通任何一个实际安装那就该停下来了。因为 Ubuntu 上本来就不需要 yum 来管理软件你继续投入时间的地方是一个它设计上就不打算承担的角色。换成用 apt 管理 Ubuntu 自己用容器或者虚拟机专门跑 RHEL 系的机器把两件事彻底隔开效率会高得多。我在自己机器上就是这么干的宿主机跑 Ubuntu 日常开发需要研究 rpm 和 yum 的时候随手起一个 Rocky 的容器配置文件和命令行全在里面练练完销毁宿主机干干净净。这个习惯帮我省掉了大量把一个工具用在不该用的地方带来的排查时间。