
没找到rpm命令——这个搜索词我见过太多次了。有的是刚装了极简版系统有的是连yum都没有的最小化容器还有一批人其实是想装软件但不知道从哪下手。RPM作为Red Hat系Linux发行版最底层的包管理工具八成的软件安装、卸载、排查问题最后都要落到它头上。这篇东西就围绕RPM本身展开从原理到命令从实战到报错排查把我在服务器上踩过的坑和验证过的思路一次性说清楚适合刚接触CentOS、Rocky、Fedora、openEuler这些发行版的新手也适合平时主要用yum/dnf但想搞懂底层机制的老手。1. 先搞懂RPM的运行机制后面所有命令都好记了1.1 RPM到底是什么它和tar.gz、deb差在哪RPM的全称是Red Hat Package Manager早期是Red Hat公司开发的包管理工具后来被Fedora、CentOS、Rocky Linux、SUSE、openEuler等一大堆发行版采用慢慢成了Linux生态里事实上的标准之一。它的核心任务就是解决软件安装的三个老大难问题文件该放哪、依赖怎么办、卸载了怎么清理。对比一下就很好理解。tar.gz源码包本质上就是一堆文件扔给你你自己编译、自己复制到 /usr/local 下卸载的时候如果忘了当初装过什么基本就变成一地鸡毛。Windows里的“绿色软件”虽然免安装但DLL缺失、注册表残留也是常态。RPM做的事情是把编译好的二进制文件、配置文件、文档、依赖关系、安装卸载脚本全部打成一个带元信息的包安装时往系统里写一份“安装清单”卸载时按清单挨个清理升级时也能精准替换出变化的文件。再说rpm和apt的关系。这两个词经常被放在一起问其实rpm是一个底层包格式和工具deb是另一个生态Debian/Ubuntu家族的包格式apt则是Debian系的包管理器它调用dpkg来干活。到了Red Hat系这边yum和dnf就相当于apt的角色底层调用rpm。所以你在CentOS里用yum install本质上是yum先把依赖算清楚然后调rpm -i去真正安装。rpm和apt在那个热搜词里并列出现大家真正想问的其实是“CentOS和Ubuntu的软件安装到底有什么区别”理解了rpm和deb这两个底层包格式的差异这个问题就解决了大半。1.2 RPM包的结构和命名规范看名字就能认出大半信息一个典型的RPM包文件名长这样openssh-10.3-1.el9.x86_64.rpm拆开来看格式是 name-version-release.arch.rpm。name软件名比如openssh。version软件本身的上游版本号10.3。release发行版打包的修订号1。同一个上游版本不同发行版或不同打包者的release可能不同。el9表示这是面向RHEL 9系含Rocky、AlmaLinux等构建的。arch架构。x86_64是64位Intel/AMDaarch64是ARM 64位i686是32位noarch表示不依赖架构的纯脚本或数据包。为什么要搞这么细因为RPM在安装时会检查架构是否匹配。你在一台x86_64服务器上硬装一个aarch64的包装之前就会报“wrong architecture”。同理el9的包通常在el8上也可以装但el8的包在el9上偶尔会因为库版本太旧或路径变化而装不上所以下载包的时候先看release字段里的系统版本标识能避开大半兼容性问题。RPM安装完软件后会把包的名称、版本、文件列表、依赖关系、安装时间等元信息写入一个叫rpmdb的数据库位置在 /var/lib/rpm。注意rpmdb里记录的是包的逻辑信息不是把文件复制到数据库里。你后续执行rpm -qa查询已安装的包查的就是这个数据库而不是去磁盘上扫文件名。这也是RPM速度快的原因——一个文件系统全盘扫描可能要几分钟查数据库就是毫秒级的事。2. 高频命令实战查询、安装、卸载、升级一套流程全吃透2.1 查询篇rpm -q系列判断装没装、文件是谁的查询是RPM日常使用频率最高的场景没有之一。最基本的用法是 rpm -q 包名包名不写全称写软件名就行但要注意是rpmdb里的name不是文件名。比如rpm -q openssh输出 openssh-9.0p1-16.el9.x86_64 就代表已经装了如果输出 package openssh is not installed 就是没装。更常用的几个组合rpm -qa # 列出所有已安装的包 rpm -qa | grep mysql # 查看mysql相关的包列表 rpm -qi openssh # 查看包详细信息含安装时间、License、URL rpm -ql openssh # 列出这个包装了哪些文件 rpm -qf /etc/ssh/sshd_config # 反查这个文件属于哪个包 rpm -qc openssh # 只列出配置文件 rpm -qd openssh # 只列出文档文件rpm -qa 输出的数量经常上万所以基本都搭配grep使用。反查文件归属这个能力在排查问题时特别有用。比如你发现 /usr/lib64/libssl.so.3 被意外覆盖了想找回它原本属于哪个包一条rpm -qf就一目了然。还有个细节要注意rpm -ql 列出的文件如果在磁盘上被删了RPM只会忠实地从数据库里读记录不会主动提示你文件缺失。这时候要用 rpm -V 来验证文件完整性。比如怀疑sshd二进制被替换或者权限被改坏执行rpm -V openssh有输出就说明文件状态和安装时不一致S代表大小变了M代表权限变了5代表MD5校验变了看到这些基本上就该重新安装恢复。2.2 安装与升级-i、-U、-F三兄弟到底怎么选RPM安装相关的命令有三个功能相近但逻辑不同用错场景会出问题。rpm -ivh 包名.rpm # 安装新包 rpm -Uvh 包名.rpm # 升级包如果没装过则执行安装 rpm -Fvh 包名.rpm # 只升级已安装的包如果没装过则跳过-v 显示详细信息-h 打印进度条。建议日常操作都带上不然装大包的时候半天没输出还以为卡死了。-i适合安装一个全新的软件。比如你下载了 vsftpd-3.0.5-1.el9.x86_64.rpm第一次装它用rpm -ivh。但如果你之前已经装过vsftpd再执行-i会报“already installed”。这时候应该用-U它会卸载旧版本再装新版本配置文件的处理策略是尽量保留旧配置。-F这个参数用得少但在批量更新场景很好用。比如你从某镜像站下载了一堆rpm包放进目录想“只升级本机已经装过的没装过的别碰”直接rpm -Fvh *.rpm它会自动跳过所有未安装的包。这在处理openssh批量升级这类场景时非常合适不会因为你多下了一个本机不需要的包就引发额外安装。安装时最常见的报错是依赖缺失。比如下载了某个包想安装系统提示error: Failed dependencies: libcrypto.so.3()(64bit) is needed by ...这时候与其一个个去找rpm包我个人建议直接改用yum localinstall或者dnf localinstall。它会自动从已配置的yum源里拉取缺失的依赖比手动找包省力得多。后面实战部分会演示这个用法。2.3 卸载篇rpm -e的坑和.rpmsave文件卸载用 rpm -e 包名。注意这里同样用包名不是文件名rpm -e vsftpd如果这个包被其他包依赖卸载时会提示依赖错误。比如你卸载一个库文件包但还有好几个软件依赖它系统会列出来默认直接拒绝卸载。强制卸要用 --nodeps但我建议不到万不得已别用。一旦强制卸载了被依赖的库依赖它的软件会进入一个“半死不活”的状态二进制还在但运行必然报错排查起来非常痛苦很多时候比重新装一遍还费时间。还有个容易被忽略的细节卸载带配置文件的包时RPM不会直接删除配置文件而是把原配置改名为 配置文件名.rpmsave 保留下来。比如卸载openssh后/etc/ssh/sshd_config.rpmsave 会留在原地。这是RPM的设计——担心你要重新装回旧版本配置还能复用。但如果确定不再需要记得手动清理这些.rpmsave文件不然日积月累/etc目录下全是垃圾文件。卸载docker相关的rpm包时会遇到另一种情况docker-ce包体积大、文件多、还有systemd单元卸载过程中偶尔会因为容器正在运行而失败。正确顺序是先systemctl stop docker卸载容器和镜像再执行rpm -e docker-ce最后检查 /var/lib/docker 目录是否残留大文件需要的话手动删除。3. 实战一用RPM方式安装MySQL 8.0附阿里云Yum源配置3.1 为什么不建议直接官网下单个rpm包硬装很多人在“rpm安装mysql”这个关键词上翻车一上来就跑去MySQL官网下载了一个mysql-community-server的rpm包然后rpm -ivh执行结果被一串依赖错误弹回来——libaio.so.1缺失、perl缺失、ncurses-compat-libs缺失……挨个下载挨个报错心态瞬间爆炸。原因在于MySQL Server不是单包交付的软件。官方把MySQL拆成了server、client、common、libs、icu-data-files等多个rpm包server只是最上面的一层它声明了一堆依赖而你下载的时候往往只下了一个file包依赖链自然就断了。所以我的建议分两种场景如果有外网环境直接配置官方MySQL Yum源用yum install一把梭如果必须用离线rpm包交付也别一个一个rpm -ivh而是把所有需要的rpm包放到同一个目录然后使用yum localinstall在dnf环境是dnf localinstall批量安装让yum自动从本地目录和其他源里解决依赖问题。3.2 实操配置阿里云镜像源再用localinstall装MySQL先配置一个相对好用的yum源。以阿里云镜像站为例CentOS 7上备份原repo文件然后拉取新的repo配置mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo yum clean all yum makecache然后去MySQL官网下载需要的rpm包这里以8.0.36版本为例把server、client、common、libs、icu-data-files这几个都放到 /data/mysql-rpm 目录下cd /data/mysql-rpm yum localinstall -y mysql-community-{server,client,common,libs,icu-data-files}-*.rpmyum localinstall和rpm -ivh的本质区别在于前者会把本地rpm包当作可用的依赖来源同时还会去已配置的yum源里拉其他缺失的依赖一条命令就把整个依赖树补齐了。如果用rpm -ivh每个缺失依赖都要手动找包效率差出几个量级。装完之后做基础初始化mysqld --initialize --usermysql systemctl start mysqld systemctl enable mysqld grep temporary password /var/log/mysqld.logMySQL 8.0初始化时会自动生成一个临时密码在日志的末尾。首次登录mysql -uroot -p ALTER USER rootlocalhost IDENTIFIED BY 你的新密码;这里要提醒两个点。第一MySQL 8.0的密码策略默认要求长度至少8位、包含大小写字母数字和特殊字符密码太简单会被直接拒绝。第二如果之前已经用yum装过别的版本MySQL再用localinstall装新版本可能碰到版本冲突正确姿势是先rpm -qa | grep mysql清理干净旧包再装新版。3.3 内网离线环境的RPM包下载技巧内网机器不能访问外网需要在一台能上网的机器上下载rpm包再拷贝进去。简单粗暴的办法是yumdownloader。以vsftpd为例yumdownloader --resolve vsftpd--resolve参数会把所有依赖的包也一并下载这是离线安装的关键。不带这个参数你下载的只是一个独立的包拷贝到内网一样会缺依赖。如果要下载特定版本的openssh比如openssh 10.3这是近期关注度很高的版本可以先确认本地源的版本yum list available openssh如果源里没有目标版本就去发行版的软件包仓库按版本号精确搜索。下载时注意核对文件名里的el版本和架构字段比如在Rocky 9上就要选el9.x86_64的包在openEuler上则需要选对应openEuler版本构建的rpm。openEuler这类国产发行版虽然也使用RPM规范但glibc版本、库文件路径和RHEL系有差异跨系统拿包容易踩坑尽量用本发行版官方仓库或镜像站里的包。4. 进阶操作把mysql8.0.36源码包制作成RPM包4.1 为什么要把源码打成RPM包很多人在“mysql8.0.36源码包制作成rpm包”这个关键词上搜索多半是遇到了这样的场景公司内网服务器不能访问外网但需要给几十台机器装同一个自定义版本的MySQL而且编译参数还要保持一致。如果每台机器都手动编译源码光耗时就能把人逼疯。RPM打包的优势在于把整个编译过程固化成SPEC文件编译好的二进制、配置文件、安装卸载逻辑全部标准化。一次构建处处安装。打好的rpm包可以放进内网自建的Yum仓库所有机器执行yum install mysql-community-server就能装出完全一致的环境升级、卸载也和其他软件一样统一管理。4.2 准备构建环境和目录结构开始之前先装构建工具yum install -y rpm-build rpmdevtools然后执行rpmdev-setuptree这个命令会在家目录生成 rpmbuild 目录结构~/rpmbuild/ ├── BUILD # 源码解压和编译的工作目录 ├── RPMS # 生成的二进制rpm包 ├── SOURCES # 存放源码包 ├── SPECS # 存放spec文件 └── SRPMS # 生成的源码rpm包把mysql源码包放进SOURCES目录。注意源码包的名字要和后续spec文件里Source0的字段对应上。4.3 编写SPEC文件核心字段逐个聊SPEC文件是rpm打包的核心。创建一个 mysql-community.spec 文件最关键的内容是Name: mysql Version: 8.0.36 Release: 1%{?dist} Summary: MySQL 8.0.36 custom build License: GPLv2 Source0: mysql-8.0.36.tar.gz %description Custom MySQL build with specific compile options. %prep %setup -q %build cmake . \ -DWITH_BOOST/usr/local/boost \ -DCMAKE_INSTALL_PREFIX/usr/local/mysql \ -DMYSQL_DATADIR/data/mysql make -j$(nproc) %install make install DESTDIR%{buildroot} %files /usr/local/mysql/bin/* %post # 安装后执行的初始化脚本命令 /sbin/ldconfig每个字段都有讲究。Source0是源码包的来源rpmbuild会在SOURCES目录里找同名文件。%prep阶段解压源码并进入目录%setup -q是标准用法。%build阶段执行编译cmake参数要和你想定制的功能一一对应比如Boost路径、安装前缀、数据目录。%install阶段把编译产物安装到临时根目录%{buildroot}rpmbuild随后会把%{buildroot}里的内容打包成rpm。%files声明哪些文件会被打进包里路径是相对安装前缀的相对路径。%post是安装后执行的脚本适合做ldconfig刷新动态链接库、创建系统用户这类事。写SPEC文件最忌的就是%files路径写少写漏。编译安装在 /usr/local/mysql 下可能生成几百个文件如果%files里只写了bin目录其他文件装完就“失踪”了。宁可多写别漏写。如果觉得逐个列太麻烦库文件目录和bin目录可以直接用通配符。还有个大坑是源码包体积。MySQL 8.0.36的源码包接近200MB加上依赖的Boost库整个编译过程在普通虚拟机上可能要30到60分钟。rpmbuild执行过程中如果中途报错退出BUILD目录里会残留半成品再次构建时可能会因为目录冲突或文件残留而失败。稳妥的做法是每次构建前清理BUILD目录rm -rf ~/rpmbuild/BUILD/*4.4 执行rpmbuild并验证产物SPEC文件写好后执行cd ~/rpmbuild/SPECS rpmbuild -ba mysql-community.spec-ba选项会同时生成二进制rpm包和源码rpm包。构建结束后到 RPMS/x86_64 目录下查看产物ls -lh ~/rpmbuild/RPMS/x86_64/然后可以用刚才学到的命令验证rpm -qpi mysql-community-8.0.36-1.el9.x86_64.rpm rpm -qpl mysql-community-8.0.36-1.el9.x86_64.rpm确认元信息和文件列表都正确后就可以把这个包拷贝到生产环境安装了。如果公司有内网Yum仓库把包传上去执行createrepo更新仓库元数据整个交付流程就自动化了。5. 常见问题与排查技巧实录5.1 高频报错类型速查表结合我这些年处理过的服务器问题RPM相关的报错主要集中在下面几类报错特征原因解决办法没找到rpm命令系统极简安装rpm没装用dnf/yum安装rpm或从安装介质中恢复Failed dependencies依赖缺失或用例不匹配用yum/dnf localinstall替代rpm -ivhNOKEYGPG公钥未导入rpm --import GPG-KEY文件conflicts with file文件被其他包占用用rpm -qf排查占用包确认后卸载或加--replacefilesalready installed包已经装过用rpm -U替换或先rpm -e卸载wrong architecture架构不匹配下载对应架构的rpm包rpmdb open failedrpm数据库损坏用rpm --rebuilddb重建数据库“没找到rpm命令”通常发生在极简容器镜像或者刚装完的最小化系统里这种系统连yum也没有rpm的安装需要借助安装介质或包管理器的自举机制处理起来比较绕。遇到这种情况我的建议是先确认发行版是什么再找对应的安装方法。如果是Docker容器直接在构建镜像时声明基于的基础镜像包含rpm作为运行时依赖即可。实际上热词“没找到rpm命令”里多数人是在问“为什么我的系统没有rpm”答案大概率是装系统时选择了不带包管理的最小组件。NOKEY报错出现在下载包后有GPG签名、但本机没有导入对应公钥的情况下。解决起来直接rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release实际路径根据发行版可能不同。如果是从第三方源下载的包需要导入第三方提供的GPG公钥。rpmdb损坏是个相对罕见但破坏力很大的问题症状是执行任何rpm命令都报错。先备份原数据库再用 --rebuilddb 重建cp -a /var/lib/rpm /var/lib/rpm.bak rpm --rebuilddb5.2 rpm2cpio不想安装也能提取包内文件遇到一个rpm包想看看里面的文件或者只想提取其中某个二进制不必安装用rpm2cpio即可rpm2cpio openssh-10.3-1.el9.x86_64.rpm | cpio -idmv命令会在当前目录下按包内的路径结构解压出所有文件。这个技巧在处理如是“openssh 10.3 rpm包下载”这类场景时特别好用你只想拿里面的sshd二进制替换到测试机上或者想对比不同构建产物的文件差异rpm2cpio是最快的方式不用动系统里已安装的包风险为零。同样思路的还有rpm -q --dump可以查看某个已安装包内每个文件的完整路径和校验信息排查“某个文件到底来自哪个包”“这个二进制的大小和安装记录是否一致”这类问题很管用。5.3 Fedora系安装QQ rpm包的注意事项围绕“fedora 安装qq rpm”不少人遇到过下载了rpm包却装不上的问题。QQ for Linux官方只提供了通用的rpm包但它依赖的库在Fedora上往往版本不同或者缺失直接rpm -ivh几乎必然报错。正确做法是sudo dnf localinstall ./qq-xxx.x86_64.rpm让dnf自动解决依赖比手动找到每一个依赖包再塞进去靠谱得多。如果dnf localinstall依然报错输出去掉了包名部分的冲突信息看看是不是和系统里已有的libgtk库版本冲突。实在解决不了退而求其次安装Flatpak版或者AppImage版也能用只是集成度低一些。5.4 一键回顾rpm命令汇总把高频命令整理成一个速查清单保存一份用的时候直接查rpm -qa # 查已装的所有包 rpm -qa | grep 关键字 # 模糊查包 rpm -q 包名 # 精确查包是否已装 rpm -qi 包名 # 查包详细信息 rpm -ql 包名 # 查包装了哪些文件 rpm -qf 文件路径 # 查文件属于哪个包 rpm -qc 包名 # 查配置文件 rpm -V 包名 # 校验文件完整性 rpm -ivh 包名.rpm # 安装 rpm -Uvh 包名.rpm # 升级/安装 rpm -Fvh 包名.rpm # 只升级已装包 rpm -e 包名 # 卸载 rpm --import 公钥文件 # 导入GPG公钥 rpm --rebuilddb # 重建rpm数据库 rpm2cpio 包名.rpm | cpio -idmv # 解包但不安装这里解释一下我在实操中的一个习惯只要是能在yum/dnf层面解决的问题我基本不会先动rpm命令。rpm强在精准和底层的掌控力但yum/dnf能在依赖管理上帮你省掉大量麻烦。真正需要rpm出手的场景是yum源里没有的第三方包、离线rpm交付、以及系统rpm数据库异常时的手动修复。关于RPM我最后再分享一点个人体会。做运维和服务器管理这些年我见过太多人遇到依赖问题就加--nodeps强制安装结果系统环境越搞越乱。RPM这套体系其实设计得非常自洽依赖检查是为了保护系统的整体一致性密钥验证是为了防止包被篡改文件冲突检测是为了避免两个包抢占同一个文件。理解这些保护机制背后的用意而不是绕过它们才能把RPM用对、用好。先用好查询命令把环境摸清楚再用localinstall之类的工具处理依赖最后把版本对应和密钥验证搞定RPM这套工具链其实没有那么难。