ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

rpm包管理完全指南:从依赖解析到离线安装与打包实践

rpm包管理完全指南:从依赖解析到离线安装与打包实践 这两年搞Linux运维绕不开的一个词就是rpm。不管你是装MySQL、装Docker还是给内网机器批量部署软件最终都要跟rpm包打交道。尤其是CentOS、Rocky、openEuler这些企业级系统rpm就是最底层的软件安装基石。很多人对rpm的印象停留在rpm -ivh xxx.rpm这个安装命令上一旦碰到依赖报错就懵了要么百度一堆命令乱试要么直接换yum、dnf结果问题越搞越复杂。其实rpm这套体系远比想象中有逻辑从安装、查询、校验到打包每一个操作背后都有规则可循。这篇文章我把这些年积累的rpm经验做个系统梳理从原理到实操、从命令都踩坑一次讲透适合刚接触Linux的新手也适合想把这块补扎实的运维。1. 内容整体设计与思路拆解1.1 RPM是什么为什么它如此重要rpm的全称是Red Hat Package Manager最早由Red Hat开发后来成了Linux世界里最主流的软件包管理格式之一。我们常说的“装个rpm包”本质上是把一个软件编译好的二进制文件、配置文件、依赖库、文档等东西按特定规则打成一个后缀为.rpm的压缩包再由系统统一解压安装、登记管理。这里有个关键点很多人没意识到rpm不只是一个“解压工具”它背后有一个完整的数据库。每当你装一个rpm包系统就会在/var/lib/rpm老版本是/var/lib/rpm新版本可能是/var/lib/rpm下的sqlite或db3文件里记录这个包的文件列表、版本号、安装时间、依赖关系。类似图书馆的图书管理系统——每本书放哪个书架、作者是谁、有没有被借走都在台账里记得清清楚楚。有了这个数据库rpm才能做到三件普通解压做不到的事一是查询某个文件属于哪个包、某个包装了没有二是校验关键文件被动过没有、被谁改过三是依赖管理装A包时需要B包装B包时又依赖C包一条链能帮你理清。1.2 面对包管理先想清楚“为什么选rpm而不是别的”很多新人会问既然有yum、dnf这种能自动解决依赖的工具为什么还要学rpm我个人的体会是——yum和dnf是“高级接口”rpm才是“底层内核”。yum下载的底层还是rpm包dnf解析依赖的底层还是rpm数据库。你踩到的很多yum报错追根溯源问题都出在rpm层面。再比如离线环境、内网隔离环境没法用yum去联网拉包这时候就只能靠rpm包手动安装。我遇到过一次生产环境要装MySQL 8.0服务器上不了外网yum源的地址全被策略封了最后就是从自己笔记本上rpm包拷过去装的。没有rpm功底这个环境你寸步难行。所以在思路上我的建议是yum/dnf负责“日常在线装包”rpm负责“离线安装、查询校验、故障排查、打包分发”。两者配合使用而不是只学一个。这也是我写这篇文章的底层逻辑——不是让你丢掉yum而是让你在yum失灵的时候还有第二把钥匙。2. 核心细节解析与实操要点2.1 安装rpm包之前必须弄清的一堆参数rpm安装命令的标准写法是rpm -ivh package.rpm这四个字母各有讲究-iinstall安装-vverbose显示详细信息-hhash显示进度条用#号表示进度我见过不少新人在内网拷包时直接敲rpm -i xxx.rpm结果屏幕上什么都不显示还以为卡死了。其实-v和-h只是让你看到过程功能上并不影响安装结果。所以敢不敢不加敢。但建不建议不建议。生产环境装包信息越多越好进度条看起来也直观。还有几个经常用得上的参数单独拎出来说--force强制安装。典型场景是同一个包版本已存在但你想覆盖安装。暴力是暴力但要清楚这会把旧文件覆盖掉有风险。--nodeps忽略依赖安装。这个参数很危险装了缺依赖的包程序通常起不来数据库里还留一个“残缺记录”后续装依赖再回来查也容易乱。我的建议是能不用就不用实在要试也只能在测试环境里试。--replacefiles允许覆盖其他包产生的文件。跨包文件冲突时用比如两个包都要写同一个配置文件。这里我插一句经验装包之前最好先用rpm -qp package.rpm --requires查一下这个包依赖哪些库和包。这叫“先探路再上路”比装上之后报错再回头排查要省力得多。2.2 查询、校验、卸载每个动作都有门道查询是最常用的rpm功能也是排查问题的第一板斧。几个高频命令列一下rpm -qa # 列出所有已安装的包 rpm -qa | grep mysql # 按关键字搜索包 rpm -q nginx # 查询某个包是否安装 rpm -qi nginx # 显示包的详细信息 rpm -ql nginx # 列出包安装后产生的所有文件 rpm -qf /etc/nginx/nginx.conf # 查文件属于哪个包 rpm -qc nginx # 只看配置文件列表 rpm -qd nginx # 只看文档文件列表这里我最常用的是rpm -qf。有一次排查负载均衡配置异常怀疑nginx.conf被人改坏了一查才知道这个文件根本不归nginx管是系统自带的另一个包生成的。这种“文件归属”问题没有rpm几乎没法定位。校验命令是rpm -V作用是拿数据库里的记录和磁盘上的实际文件做对比查看哪些文件被动过手脚rpm -V nginx没输出表示文件没变动。有输出的时候每个字母都有含义开头可能是S大小变化、M权限变化、5MD5校验值变化、U属主变化、G属组变化。比如输出里出现S.5....T.基本说明文件内容被改过了。卸任的时候服务起不来了不要急着重装先V一下多半能看出端倪。卸载命令是rpm -e package这里有个常见误区卸载时写包名而不是包文件名。很多新手敲rpm -e nginx-1.20.1.rpm结果直接报错“package nginx-1.20.1.rpm is not installed”。正确的是写包名也就是rpm -e nginx。卸载时如果有其他包依赖这个包会提示依赖失败这时候别硬删先把依赖它的包处理掉。2.3 依赖关系rpm系最让人头疼却又必须理解的一点我见过很多初学Linux的人对依赖关系深恶痛绝因为报错信息长得吓人比如error: Failed dependencies: libssl.so.10()(64bit) is needed by mysql-community-server-8.0.30-1.el7.x86_64别怕这类报错翻译一下就是mysql这个包需要系统里有libssl.so.10这个库而当前系统里没有或者只有一个更高版本rpm不认。rpm的依赖匹配是严格的、精确的。它不像人脑不会认为“libssl.so.10和libssl.so.1.1差不多”哪怕就差一个数字rpm也会拒绝安装。这是为了保证程序调库时一定能找到声明的那一个版本毕竟动态库的新旧版本经常互相不兼容。解决依赖的正确思路是先用rpm -qp mysql-community-server.rpm --requires列出所需依赖然后逐个检查系统里有没有对应的包没有就找对应版本的rpm包装上。这里推荐一个反向命令rpm -q whatprovides libssl.so.10能直接告诉你这个库由哪个包提供省得自己去猜。3. 实操过程与核心环节实现3.1 离线环境安装MySQL 8.0的完整流程离线装MySQL是rpm实操里最典型的场景。我需要强调MySQL官方提供的rpm包本身拆成了server、client、common、libs等多个子包它们之间存在依赖顺序而且共同依赖一个libaio库。装的时候不用按字母表但必须保证顺序正确我一般按这个顺序来rpm -ivh mysql-community-common-8.0.36-1.el7.x86_64.rpm rpm -ivh mysql-community-client-plugins-8.0.36-1.el7.x86_64.rpm rpm -ivh mysql-community-libs-8.0.36-1.el7.x86_64.rpm rpm -ivh mysql-community-client-8.0.36-1.el7.x86_64.rpm rpm -ivh mysql-community-server-8.0.36-1.el7.x86_64.rpm为什么要先装libs再装server因为server依赖libs里的动态库如果顺序反过来第一轮就报缺库。这四个包不要求在同一条命令里一次装完分四条命令来更容易看出哪一步出了问题。装完之后还要做两件事一是mysqld --initialize初始化数据目录二是改配置文件里的字符集、端口等参数。很多新手装完MySQL就往里连一报错就怀疑rpm装坏了其实rpm只是把文件放到位初始化是另一道工序两者不能混为一谈。3.2 用rpmbuild打包自己的rpm包除了安装别人的包还有一个高端操作叫“打包”也就是把你自己编译好的软件做成rpm包方便内网批量分发。这个技能我用得最多的场景是编译好了OpenSSH新版本需要给几十台机器批量升级或者内核模块、自研小工具需要标准化交付。打包前的准备是安装rpm-build包yum install rpm-build然后创建标准的目录结构mkdir -p ~/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}路径含义BUILD解压源码后的构建目录RPMS打包好的二进制rpm输出目录SOURCES存放源码压缩包SPECS存放spec文件这是打包的“配方”SRPMS源码rpm包输出目录核心是spec文件里面定义了包的元信息、依赖、安装前后要执行的脚本。一个最简单的spec示例Name: hello Version: 1.0 Release: 1 Summary: A simple test package License: MIT %description This is a demo rpm package. %prep %setup -q %build make %install mkdir -p %{buildroot}/usr/local/bin cp hello %{buildroot}/usr/local/bin/ %files /usr/local/bin/hello文件里每个块都有明确作用%prep负责准备源码%build负责编译%install负责把编译产物放到临时根目录%files声明哪些文件要进包。写好后执行rpmbuild -bb hello.spec生成的包在~/rpmbuild/RPMS/x86_64/下拿去别的机器上rpm -ivh就能装了。这里有个打包时的常见坑%install阶段忘了建目录比如直接写install -m 755 hello %{buildroot}/usr/local/bin/hello如果buildroot下的/usr/local/bin目录不存在安装就报错。所以先mkdir -p再cp这个习惯能省不少时间。3.3 经典场景CentOS 8 / openEuler上打包OpenSSH新版本顺着打包的话题我再展开讲一个更贴近生产的热搜场景——给CentOS 8定制OpenSSH RPM包。背景是这样的CentOS 8默认的OpenSSH版本可能是8.0或8.2但安全扫描报告要求升级到更高版本而系统的AppStream源里又没有更新版怎么办自己编译再分发还是自己打rpm包分发我推荐后者。用rpmbuild把OpenSSH打包的好处是可以依赖系统已有的OpenSSL、PAM等库还能在spec里处理配置文件覆盖的问题比裸编译后手动拷贝规范得多。实际操作为例yum install -y rpm-build gcc gcc-c make openssl-devel pam-devel zlib-devel rpmdevtools rpmdev-setuptree cd ~/rpmbuild/SOURCES wget https://cdn.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-9.6p1.tar.gz然后从Github上找一个适配你系统的openssh.spec模板放进~/rpmbuild/SPECS/。注意几个关键改动Version:改成9.6p1对应的版本号spec里通常写作9.6%configure参数里加上你需要的编译选项%install之后加一行mkdir -p %{buildroot}/etc/ssh因为OpenSSH的配置文件如果在老版本安装过更新时RPM会提示config文件冲突提前在spec里写好处理方式会顺滑很多。改完执行rpmbuild -bb openssh.spec顺利的话~/rpmbuild/RPMS/x86_64/下会生成openssh、openssh-clients、openssh-server三个rpm包。升级时先装server再装client注意保留旧的/etc/ssh/sshd_config因为新包会用.rpmnew后缀生成新配置模板而不是直接改旧的。这中间最麻烦的是spec文件里那些%pre、%post脚本——它们负责在安装前后启停服务、生成密钥对。如果脚本写得不对装完新包sshd起不来远程排查只能靠带外管理卡很狼狈。我的经验是第一次打包前先看看系统原来自带的OpenSSH spec是怎么写的照猫画虎把服务启停逻辑抄过来比你凭空想象要稳得多。4. 常见问题与排查技巧实录4.1 报错“no found rpm command”怎么救新装的极简系统或者容器镜像里可能压根没有rpm命令。这时候你要判断一下系统是Debian系还是Red Hat系如果是Ubuntu、Debian本来就不该用rpm应该用dpkg。如果是CentOS/Rocky却找不到rpm说明你安装时选了“最小化且不带rpm”的定制包或者PATH有问题。恢复的办法是从同版本系统的安装ISO里找到rpm这个包或者从阿里云镜像下载curl -o rpm.rpm https://mirrors.aliyun.com/centos/7/os/x86_64/Packages/rpm-4.11.3-48.el7_9.x86_64.rpm但这里有个鸡生蛋的问题没有rpm命令你怎么装rpm包办法是用rpm2cpio配合cpio手动解压rpm2cpio rpm.rpm | cpio -idmv /usr/bin/rpm /usr/lib64/librpm*把二进制和库文件直接释放到系统目录里rpm命令就能用了。这类操作不常用但了解思路对理解rpm安装本质很有帮助——rpm包本质上就是一个归档文件安装过程就是解压加登记。4.2 依赖地狱缺库、版本冲突、重复安装rpm系最经典的坑就是“依赖地狱”我简单整理一个速查表在这里方便你按图索骥。现象最常见原因推荐排查手段缺libxxx.so.1装包前没查依赖系统缺库rpm -q whatprovides libxxx.so.1提示already installed包已安装但你想重装rpm -e 包名后重装或是用--force覆盖提示conflicts with file两个包产出同一个文件用rpm -qf查看文件归属决定保留哪个卸载报依赖失败有其他包依赖它rpm -e --nodeps强删但之后必须补装依赖方安装完成但命令找不到PATH路径不对rpm -ql 包名查看文件实际安装路径做软链或加PATH处理依赖问题的基本功是先诊断再动手。我最常用的诊断命令就是上面表格第一行那个rpm -q whatprovides它能根据库文件名反查来源包再配合yum自动下载依赖。比如rpm -q whatprovides libssl.so.10()(64bit)输出会告诉你这个库由openssl10之类的包提供找到对应的rpm包装上问题就解了。怕手动找依赖太费劲的话可以先把包放进一个目录用yum localinstall *.rpm让yum帮你把依赖一起装——但请注意如果整个系统完全无法联网、没有本地镜像源yum也帮不了你最终还是得靠手动逐个补齐。4.3 rpm数据库损坏后的急救措施还有一种比较少见但一遇到就让人头大的问题rpm数据库损坏。表现是执行任何rpm -qa都报rpmdb: PANIC: fatal region error detected或者进程卡住不动。造成原因通常是磁盘写入中断、强制断电或者人为删掉了/var/lib/rpm下的某个文件。急救手段按严重程度排序可以这样操作先备份再重建cp -a /var/lib/rpm /var/lib/rpm.bak rm -f /var/lib/rpm/__db.* rpm --rebuilddb__db.*是rpm数据库的锁文件和环境文件删掉之后用--rebuilddb重新建库绝大多数索引问题都能解决。如果还不行就从同版本系统恢复Packages这个数据库文件再执行rpm --rebuilddb。这里有个经验即使你觉得数据无价也别在恢复过程中重启机器因为重建到一半断电反而更容易二次损坏。4.4 装完Docker/MySQL起不来的排查路径最后补一个综合性的排查套路这也是新手群里问得最多的问题rpm装完一个服务一切正常就是起不来怎么查我的排查顺序是固定的你可以直接抄作业先看服务和日志systemctl status docker journalctl -u docker | tail -50再看依赖库是否齐全ldd /usr/bin/docker | grep not foundldd输出里有not found基本可以确定是缺动态库。这说明你的rpm包装上了但它的依赖没装全——这种情况常见于手动rpm -ivh时跳过了某些依赖包。如果ldd全过但程序还是起不来再检查系统日志和内核日志dmesg | tail -20Docker这类软件还会涉及cgroup、防火墙、内核模块等情况问题往往不在rpm包本身而在系统环境。rpm只能保证文件在正确的位置保证不了每个软件都能适应当前内核这也是“装包成功但运行失败”的真正原因。5. RPM与APT两大包管理体系的对位理解5.1 RPM和APT的本质差异学Linux的人迟早会碰到“rpm和apt哪个好”的争论。我的结论是没有绝对的优劣它们有各自的设计哲学。rpm是Red Hat系的主心骨偏向“内核级”管理包格式统一为rpm数据库记录详细。apt最初服务于Debian系配套的包格式是deb。但在实际使用中有个很重要的区别rpm本身不解决依赖解析问题需要靠yum、dnf、zypper这些上层工具来实现“自动补依赖”而apt天生就把依赖解析做在了工具链里apt install一条命令能从远程仓库把所有依赖拉齐。类比一下rpm像市政道路基础设施本身很硬核yum/dnf是给道路配的信号灯和导航apt则是从一开始就规划好的智能交通系统。两者各有拥趸不过作为一个在CentOS、Ubuntu之间来回切换多年的运维我的真实体感是RPM系适合紧贴企业环境的定制化部署APT系在社区生态和上手友好度上更占优。5.2 热词“rpm和apt”映射出的选型建议很多刚入门Linux的朋友会纠结“到底该学哪个”。我的建议很直接看你的目标环境来定不用提前站队。如果未来主要在服务器运维方向发展国内企业里CentOS、Rocky、openEuler、统信UOS的占比很高这些全是rpm系你绕不开rpm。如果做嵌入式、做开发环境Debian、Ubuntu是主流apt更顺手。真要成为TT专业选手两个体系都要懂但可以先用一个体系建立核心概念另一个体系等用到再类比着学事半功倍。在“rpm vs apt”对比中知识点迁移其实很快rpm的-qa对应dpkg的-lyum的install对应apt的installjust不同的“软件包格式”和“数据库位置”而已。理解了包管理器的本质是“归档记录依赖解析”两个体系一天就能切换过来。6. 经验延伸玩转rpm的几个进阶操作6.1 把rpm包转成其他格式cpio解包探秘有些时候我们不想“安装”某个rpm包只是想看看里面到底有什么文件或者只想提取其中某个二进制又不让它进系统数据库。最常见的做法就是用rpm2cpio解包rpm2cpio nginx-1.20.1-10.el7.x86_64.rpm | cpio -idmv执行完之后当前目录会多出一个按rpm包内结构展开的目录树里面能直接找到/etc/nginx/nginx.conf这样的文件。这个方法在排查“配置文件到底长什么样”时有奇效比装包再进目录找或者rpm -ql盲猜快得多。顺带说一句这个操作也解释了rpm包的本质——它就是一个带元信息头的cpio归档。rpm数据库只是对解压出来的文件做登记如果你把rpm包解开手动拷贝文件系统对这几个文件是没有记录的将来卸载、校验都不会处理它们。这也是“手动拷贝安装”不如“rpm安装”的重要原因。6.2 PyInstaller和Go项目的rpm化思路最后分享一个我工作中处理自研工具的方式。很多团队的自研工具不是用C写的而是Python或者Go。这两类项目的分发方式经常是“拷个二进制到处跑”但在规范化的企业环境里临时目录里放着一堆裸二进制既不便于版本管理也不便于审计。我把这类项目也打成rpm包思路很简单对于Go项目编译出单个静态二进制直接放进rpm包/usr/local/bin/mytool即可。spec文件的%install阶段只需要一条install命令。对于Python项目用PyInstaller等方式打成单个可执行文件或者把整个site-packages打包进rpm但要注意依赖了哪些系统库利用spec里的Requires字段声明清楚。再配合企业内部的Yum仓库比如Nexus、Artifactory的yum源就能做到“自研工具也走统一的rpm安装、升级、卸载流程”。以后审计起来一句rpm -qa | grep mytool就能查到在哪些机器、什么版本比“文件在哪个目录”清楚得多。我个人在实际操作中的体会是rpm这套体系越往深处用越能感受到它的设计严谨尤其是数据库和校验这两个特性让系统状态可追溯、可验证这在多机、大规模环境里是非常重要的底气。希望这篇整理能帮你把rpm从“装包命令”升级成真正的系统管理思维下次踩坑的时候至少能说出问题出在哪一环。
返回列表