RPM(Red Hat Package Manager,递归缩写)是 Red Hat 公司开发的一套软件包管理技术体系,包含三个层面:
一种文件格式 :
.rpm包(把程序 + 元数据 + 安装脚本打包)一组管理工具 :
rpm命令行程序一个软件数据库 : 记录系统上所有已安装软件的完整信息
它诞生于 1997 年(RPM 1.0,基于 RPP 改进),目前是 Linux 世界事实上的两大包管理阵营之一 :
CentOS/RHEL 系底层包格式 : RPM , 分三层工具:
rpm: 底层工具 , 操作本地rpm包 , 不自动解决依赖yum:CentOS7默认高层包管理器 , 基于rpm, 自动处理依赖 , 拉取仓库源dnf(Dandified YUM) :CentOS8+/RHEL8+默认 ,yum升级版 ;CentOS8里yum只是dnf的软链接 , 命令几乎完全兼容
1. RPM 基础原理
rpm命令是RPM软件包的管理工具。rpm原本是Red Hat Linux发行版专门用来管理Linux各项套件的程序 , 由于它遵循GPL规则且功能强大方便 , 因而广受欢迎。逐渐受到其他发行版的采用。RPM套件管理方式的出现 , 让Linux易于安装 , 升级 , 间接提升了Linux的适用度。
2. RPM包基础
2.1 RPM包命令规则
2.1.1 基础命名规则
rpm包的命令规则方式如下图所示

软件包名称 : 软件本身名称, 单词标识软件。
版本号 : 软件作者官方的版本号
发布编号(
VERSION) : 打包这的打包修订号。软件源码版本没变, 知识修改了打包脚本、补丁, 这个数字会增加。发行版标识:
el7, 其中el = Enterprise Linux。el7 -> CentOS7/RHEL7el8 -> CentOS8/RHEL8el9 -> Rocky9/RHEL9
架构 :
x86_64,编译适配的CPU架构扩展名 :
.rpm,RPM二进制包标识源码包后缀 :
.src.rpm, 例如nginx-1.20.1-1.el7.src.rpm, 存放源代码 , 不是直接安装的二进制程序。而是通过源码包手动编译成新的rpm包。或者通过源码包获取对应的源码或者rpmbuild的编译文件
2.1.2 子包命名
很多大型软件 , 不会只打包成单个 rpm 文件 , 而是拆分成多个 RPM 子包。
RPM 打包规范支持将同一个软件项目 , 拆分成多个独立 rpm 包 , 称为子包。 打包时共用一套源码 , 版本号保持一致 , 但是拆分成多个 rpm 文件 ,每个子包只包含一部分文件。
拆包目的
按需安装 : 只安装需要的组件 , 最小化服务器安装体积(生产最小化部署很重要)
文件复用 : 公共配置、共享库抽离 , 多个组件共用一份文件 , 避免重复存放
依赖隔离 : 不同组件依赖不同软件 , 拆包减少不必要依赖
粒度可控 : 升级时可以单独升级某个子包(同版本下一般一起升级)
命名通用格式 : 软件名-子包标识-版本-发布号-架构.rpm
示例:
mariadb-5.5.68-1.el7.x86_64.rpm #主基础包
mariadb-server-5.5.68-1.el7.x86_64.rpm #服务端子包
mariadb-client-5.5.68-1.el7.x86_64.rpm #客户端子包
mariadb-libs-5.5.68-1.el7.x86_64.rpm #共享库子包
mariadb-devel-5.5.68-1.el7.x86_64.rpm #开发子包
mariadb-doc-5.5.68-1.el7.x86_64.rpm #文档子包
2.2 RPM包依赖
2.2.1 依赖基础
Linux 软件运行或编译时 , 需要调用其他文件、库、程序。RPM 包在打包时 , 会把这些需求写入包内 , 就是依赖(Requires)。 同时 , 包也可以对外提供能力 , 叫做提供(Provides)。
RPM 数据库 /var/lib/rpm 记录本机所有包的 Requires 和 Provides。 rpm 底层工具只会检查依赖 , 不会自动下载安装缺失依赖; yum/dnf 上层工具自动解析、安装依赖。
Requires(需要) : 当前包安装 / 运行 , 必须要有哪些东西。Provides(提供) : 当前包可以提供哪些文件、库、虚拟包 , 供别的包依赖。
RPM 依赖的 4 种类型
文件依赖
依赖某个具体文件路径。 例:
/usr/bin/bash, 安装包要求系统必须存在这个文件。库依赖
依赖动态共享库
.so。程序运行时加载。 示例 :libc.so.6(glibc系统基础库 , 几乎所有程序都依赖)使用命令
ldd 二进制程序查看程序运行依赖的动态库。它依赖的其实是一个文件 , 而不是软件包。该文件藏身在某一个软件包当中。我们只要将该文件所在的软件包安装上 , 该文件也就安装了。
解决方法 : 登录
www.rpmfind.net网站 , 输入库文件名称查询到对应的rpm包 , 然后安装即可。软件包依赖
依赖另外一个
RPM包(包名 , 可带版本条件) 版本条件符号 :>大于、>=大于等于 、<小于 、<=小于等于 、=等于。示例 :
nginx requires openssl >= 1.0.2安装nginx, 系统openssl版本必须大于等于1.0.2。虚拟包依赖
不是真实包名 , 打包时自定义虚拟名称 , 多个包可以
Provides同一个虚拟包。好处 : 多个软件包提供相同能力 , 依赖只写虚拟名字 , 不绑定单一包。
举例 :
httpd和nginx都可以提供webserver虚拟包。某个软件依赖webserver, 安装 httpd 或者 nginx 任意一个都满足依赖。
2.2.2 依赖查询
两类查询 : 1. 已安装包 ; 2. 未安装的 rpm 文件(加 -p)
查询包的依赖
Requires# 查询本机已安装nginx的依赖 rpm -qR nginx # 查询【尚未安装】的rpm包文件的依赖 ( 加p ) rpm -qpR nginx-1.20.1-1.el7.x86_64.rpm查询包对外提供
Provides# 查询已安装nginx提供哪些能力 rpm -q --provides nginx # 查询未安装rpm包的provides rpm -qp --provides nginx-1.20.1-1.el7.x86_64.rpm 查询哪个包提供某个文件(反向查询)
# 本机已有文件 , 查归属包 ( 读取本地rpm数据库 ) rpm -qf /usr/bin/ls # 联网查询哪个包能提供该文件 ( yum , 本机不存在文件也能查 ) yum provides */semanage
2.2.3 依赖冲突
同一个系统中 , 两个包不能同时安装 , 称为冲突 Conflicts。 打包时定义 : A 包 Conflicts B 包。安装 A 的时候 , 如果系统已有 B , 直接报错。
场景举例: mysql-community-server 和 mariadb-server 互相冲突 , 不能同时安装。
查看包冲突命令:
rpm -q --conflicts mariadb-server
rpm -qp --conflicts mariadb-server.rpm2.2.4 依赖处理机制
rpm -ivh: 安装前检查所有Requires, 依赖缺失直接终止安装 , 不会自动下载。rpm -e: 卸载前检查 , 如果别的包依赖当前包 , 卸载直接报错。--nodeps参数 : 跳过依赖检查 , 强制安装 / 卸载
rpm -ivh --nodeps xxx.rpm
rpm -e --nodeps xxx依赖本身的形式分为以下两种:
树形依赖 :
a->b->c解决方法 : 从后往前安装环形依赖 :
a->b->c->a解决方法 : 放在一条命令中安装即可
3. RPM数据库
RPM 数据库是 rpm 包管理器本地的数据库 , 当我们安装 rpm 包的时候 , rpm 会把包的元数据写入这个数据库 ; 查询、校验、卸载软件时 , rpm 读取这个数据库。
注意 : 不是存放软件本身的程序文件 !软件二进制、配置文件仍然安装在
/usr/bin、/etc等系统目录 ;RPM数据库只记录软件包的元信息。
路径 : /var/lib/rpm/ 。/var/lib/ 目录的含义 : 可变数据 ,应用程序运行产生的持久化数据。
进入 /var/lib/rpm , 里面是多个Berkeley DB(BDB)数据库文件(CentOS7) , 每个文件是独立的索引表 , 不同表保存不同信息。
在上面表格中Packages为主数据表。其余所有 .db 文件都是索引 , 用来加速各类 rpm 查询命令。需要注意 CentOS8+的rpm 数据库后端换成 sqlite , 不再是 Berkeley DB , 文件结构不一样。
当安装一个 rpm 包 , rpm 写入数据库的信息 :
软件包基础信息 : 包名、
version、release、arch、打包时间、厂商、许可证、描述文件清单 : 该包安装的所有文件、目录、软链接;每个文件的权限、属主、属组、大小、
MD5校验码;标记哪些是配置文件、哪些是文档依赖信息 :
Requires(该包依赖的库 / 文件 / 包) ;Provides(该包对外提供的库 / 虚拟包) ;Conflicts(冲突包)变更记录 : 安装时间
因此当使用rpm命令查询包相关信息(执行 rpm -ql nginx)的时候, rpm 不是去扫描磁盘 , 而是读取数据库里记录的文件列表。
rpm -V nginx: 读取数据库保存的文件属性、MD5, 和磁盘上真实文件对比,判断是否改动。
rpm -qf /usr/bin/nginx: 查询Basenames索引 ,找到该文件归属的包。
另外RPM 数据库同一时间只允许一个 rpm 事务操作。 当执行 rpm 安装、升级、卸载时,会加锁 ; 此时如果再开一个窗口执行 rpm/yum, 会报错。
RPM数据库有一个常见的故障问题。当数据库因为断电宕机、磁盘满、并发操作等原因导致 数据库损坏时, 会出现以下内容报错信息:
error: db5 error(11) from dbenv->open: Resource temporarily unavailable
error: cannot open Packages index using db5 - Resource temporarily unavailable (11)
error: cannot open Packages database in /var/lib/rpm如果需要修复, 需要提前备份对应的目录文件: cp -r /var/lib/rpm /var/lib/rpm.bak
如果因为并发操作导致锁文件残留。直接删除对应的锁文件:
rm -f /var/lib/rpm/__db*删除锁文件后 , 重新执行
rpm命令测试Berkeley DB数据库损坏 , 重建数据库rpm --rebuilddb读取
Packages主表 , 重新生成所有索引文件(Name、Files、Depends等索引)注意 :
--rebuilddb不会删除Packages主表 , 只是重建索引 ; 如果Packages文件本身损坏严重 , 该命令修复失败。重建过程中, 不能断电。重建时不要同时运行
yum/rpm。如果Packages主文件损坏 , 重建无效 , 本机包信息丢失 , 只能重装系统。
3. RPM包来源
3.1 发行版官方仓库
系统安装后默认配置的仓库 , 由发行版维护团队打包、测试、签名 , 最安全、依赖最匹配。
CentOS 官方仓库分层
另外各大知名公司也会提供对应的官方仓库源:
https://www.centos.org/download/http://mirrors.aliyun.comhttp://mirrors.sohu.comhttp://mirrors.163.com
3.2 第三方公共仓库
大量软件不在官方仓库中 , 由社区或厂商维护
以 EPEL 为例(最常用的第三方源)
# CentOS 7:直接装
yum install -y epel-release
# 查看来源:这个包本身就在官方 Extras 仓库里
yum info epel-release
# 安装后启用
yum clean all
yum makecacheEPEL 全称 Extra Packages for Enterprise Linux , 是 Fedora 项目为 RHEL/CentOS 提供的补充仓库 , 不替代、不冲突官方仓库——官方有的包 EPEL 默认不提供。
仓库冲突问题
多个第三方仓库提供同一个软件的不同版本时 , 会造成冲突:
# 控制优先级,避免仓库打架
yum install -y yum-plugin-priorities # CentOS 7
# 在 repo 文件中加入 priority=1(数字越小优先级越高)
[epel]
name=EPEL
priority=10最佳实践 : 生产服务器上只启用必要的仓库。装完就禁用(
enabled=0) ,避免yum update时意外升级。
3.3. 软件官方网站
数据库、中间件、商业软件等通常由厂商直接提供 RPM:
示例, Nginx 官方仓库
# 下载官方仓库配置包(一次性配置好 repo 和 GPG key)
rpm -Uvh https://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm
# 之后像装普通软件一样安装(版本比官方仓库新)
yum install nginx这类 *-release.rpm 包的作用 : 自动写入 /etc/yum.repos.d/xxx.repo 并导入 GPG 公钥 , 是官方推荐的接入方式。
3.4 社区聚合网站
使用原则:
用它们定位软件在哪个仓库 → 然后配置仓库用
yum装直接下载单个
RPM手动装是下策(依赖问题、版本错配)注意选择匹配自己系统的版本 :
el7/el8/el9不能混装
3.5 自建来源
本地目录仓库
mkdir -p /opt/localrepo # 放入 rpm 包后生成索引 createrepo /opt/localrepo # 配置 file:// 协议仓库 cat > /etc/yum.repos.d/local.repo <<EOF [local] name=Local RPMs baseurl=file:///opt/localrepo enabled=1 gpgcheck=0 EOFHTTP内网仓库(企业标准做法)# 在内网服务器上 mkdir -p /var/www/html/repo/centos7 # 用 reposync 同步公网仓库 reposync -p /var/www/html/repo --repoid=base --repoid=updates createrepo /var/www/html/repo/centos7/base # 客户端配置指向内网 baseurl=http://repo.internal/centos7/base打包工具下载(离线依赖收集)
yum install -y yum-utils yumdownloader --resolve --destdir=./rpms nginx # 下载包及全部依赖
3.6 SRPM自行构建
拿到源码包自己编译 , 适合需要定制编译参数或打补丁的场景:
# 来源:发行版源码仓库 / src.rpm / 官网源码
yum install -y rpm-build rpmdevtools
# 方法1:从 SRPM 构建
rpm -ivh nginx-1.24.0-1.el7.src.rpm # 解到 ~/rpmbuild
rpmbuild -ba ~/rpmbuild/SPECS/nginx.spec
# 方法2:用 mock 在干净环境构建(推荐,避免污染系统)
yum install -y mock
mock -r epel-7-x86_64 rebuild nginx-1.24.0-1.el7.src.rpm4. RPM包管理
rpm 是 Red Hat 系发行版底层的包管理命令行工具。它不自动解决依赖 , 但查询能力极强 , 是系统管理员日常排障、审计、验证的核心武器。
语法 :
rpm [选项] [包名或文件]
关键约定:
操作已安装的包 → 用包名(如
httpd, 不带版本号和.rpm后缀)操作未安装的
.rpm文件 → 加-p选项(如-qpi package.rpm)
4.1 安装
语法 :
rpm {-i|--install} [install-options] PACKAGE_FILE...参数
-v: 显示详细过程-h: 显示#进度条(50个#代表完成)
install-options--test: 测试安装 , 但不真正执行安装 , 即dry run模式--nodeps: 跳过依赖检查(危险!)--force: 强制安装(覆盖冲突文件)--oldpackage: 允许降级安装--replacepkgs: 重新安装已存在的包--nodigest: 不检查包完整性--nosignature: 不检查来源合法性--nopre:%pre, 不执行安装前脚本 ;--nopos:%post, 不执行安装后脚本 ;--nopreun:%preun, 不执行卸载前脚本 ;--nopostun:%postun,不执行卸载后脚本 ;--noscripts: 不执行程序包脚本 。 等价于执行上面四个脚本参数
示例:
批量安装
rpm -ivh *.rpm # 当前目录下所有 rpm
rpm -ivh --test *.rpm # 先检查全部,确认无冲突再真装其他
# 强制重装(文件丢失,想还原包原始文件)
rpm -ivh --force nginx-1.20.1-1.el7.x86_64.rpm
# 忽略依赖强制安装(测试环境临时用,生产禁止)
rpm -ivh --nodeps nginx-1.20.1-1.el7.x86_64.rpm4.2 升级
语法
rpm {-U|--upgrade} [install-options] PACKAGE_FILE... rpm {-F|--freshen} [install-options] PACKAGE_FILE...Upgrade: 表示已安装则升级 , 未安装则直接安装Freshen: 仅当已安装且版本更新时才处理
install-options--force: 强制安装(覆盖冲突文件)--oldpackage: 允许降级安装
注意 :
不要对内核做升级操作 ; Linux支持多内核版本并存 , 因此 , 对直接安装新版本内核 。
-U会删除旧内核 , 一旦新内核起不来 , 系统无法启动。如果原程序包的配置文件安装后曾被修改 , 升级时 , 新版本 的提供的同一个配置文件并不会直接覆盖老版本的配置文件 , 而 把新版本的文件重命名(
FILENAME.rpmnew)后保留
示例
# 升级包,不存在则直接安装
rpm -Uvh nginx-1.22.0-1.el7.x86_64.rpm
# 仅升级本机已存在的nginx;本机没有nginx则不执行
rpm -Fvh nginx-1.22.0-1.el7.x86_64.rpm4.3 卸载
语法 :
rpm {-e|--erase} [--allmatches] [--nodeps] [-noscripts] [--notriggers] [--test] PACKAGE_NAME ...
卸载时会检查其他包是否依赖当前包 ;有依赖则直接报错 , 不会自动删除依赖包
这个命令不同于安装和升级 , 它可以在任何目录运行 , 原理是去
/var/lib/rpm目录中的数据库 ( 如__db0) 中查找对应的软件包 ( 已经安装过的rpm包都在这些数据库中 ) ,然后卸载。
示例:
rpm -e httpd # 卸载(只写包名!)
rpm -e httpd --nodeps # 跳过依赖检查(危险:依赖它的程序会坏)
rpm -e --justdb httpd # 只从数据库删除记录,不删实际文件
rpm -e --noscripts httpd # 跳过卸载脚本(脚本写错导致无法卸载时的救命选项)卸载失败
# 报错:package httpd is needed by (installed) httpd-tools-2.4.x
# 说明 httpd-tools 依赖 httpd,必须先卸载 httpd-tools
rpm -e httpd-tools httpd # 一起卸载,或先卸依赖方4.4 RPM包查询
语法:
rpm {-q|--query} [select-options] [query-options]
[select-options]-a: 所有包-f: 查看指定的文件由哪个程序包安装生成-p rpmfile: 针对尚未安装的程序包文件做查询操作--whatprovides CAPABILITY: 查询指定的CAPABILITY由哪个包所提供--whatrequires CAPABILITY: 查询指定的CAPABILITY被 哪个包所依赖
[query-options]--changelog: 查询rpm包的changelog-c: 查询程序的配置文件-d: 查询程序的文档-i: 详细信息:版本、描述、打包者、安装时间、签名-l: 查看指定的程序包安装后生成的所有文件--scripts: 程序包自带的脚本--provides: 列出指定程序包所提供的CAPABILITY-R: 查询指定的程序包所依赖的CAPABILITY
rpm2cpio 包文件|cpio –itv: 预览包内文件
rpm2cpio 包文件|cpio –idv "*.conf": 释放包内文件
rpm2cpio tree-1.60-10.el7.x86_64.rpm |cpio -id ./usr/bin/tree指定生成的文件 至生出对应的文件目录
常见用法 :
-qi PACKAGE -qf FILE
-qc PACKAGE -ql PACKAGE
-qd PACKAGE -qpi PACKAGE_FILE
-qpl PACKAGE_FILE, ... -qa 示例 :
包详细信息
rpm -qi httpd # 详细信息:版本、描述、打包者、安装时间、签名
rpm -ql httpd # 列出该包安装的所有文件
rpm -qd httpd # 只列出文档文件(man、README)
rpm -qc httpd # 只列出配置文件
rpm -qR httpd # 列出依赖(Requires)
rpm -q --scripts httpd # 查看安装/卸载脚本内容
rpm -q --changelog httpd # 查看打包变更记录
rpm -q --triggers httpd # 查看触发器脚本反查文件归属
rpm -qf /usr/sbin/nginx # 这个文件属于哪个包
rpm -qf /etc/passwd # 系统文件归属
rpm -qf $(which python3) # 配合 which 查命令来源查询未安装的 rpm 文件
rpm -qpi package.rpm # 查看文件包的信息
rpm -qpl package.rpm # 查看文件包会装哪些文件
rpm -qpR package.rpm # 查看文件包的依赖
rpm -qpc package.rpm # 查看文件包的配置文件
rpm -qpd package.rpm # 查看文件包的文档依赖反向查询
rpm -q --whatrequires openssl # 谁依赖 openssl(已安装范围内)
rpm -q --whatprovides /usr/bin/perl # 谁提供这个文件/能力
rpm -q --whatprovides 'libssl.so.1.1()(64bit)'4.5 包校验
语法 :
rpm {-V|--verify} [select-options] [verify-options]
校验已经安装包
rpm -V httpd # 校验单个包
rpm -Va # 校验所有包(安全审计神器)
rpm -Va 2>/dev/null | grep -v '^..5' # 只看内容被改过的文件
#输出
S.5....T. c /etc/nginx/nginx.conf默认没有输出结果。如果校验有输出, 按照以下字符比较, 可以判断对应的配置文件改变的地方。
输出格式中c表示配置文件。其他参考以下内容。
c(config file) : 配置文件
d(documentation) : 普通文档
g(ghost file) : "鬼"文件, 很少见, 就是该文件不应该被这个RPM包包含
L(license file) : 授权文件
r(read me) : 描述文件示例 : 执行 rpm -V httpd 后, 无任何提示, 代表该文件没有被做任何修改
判断本地的
apache与官方给出的是否一致, 从而判断是否被人修改。修改文件
/etc/httpd/conf/httpd.conf,在注释行添加任意内容后, 再次执行 , 执行结果如下图所示

校验本身需要导入公钥信息
# 查看系统已导入的公钥
rpm -qa gpg-pubkey*
# 查看某公钥详情
rpm -qi gpg-pubkey-f4a80eb5-53a7ff4b
# 导入仓库公钥
rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
rpm --import https://nginx.org/keys/nginx_signing.key
# 删除公钥
rpm -e gpg-pubkey-f4a80eb5-53a7ff4b
rpm -qa “gpg-pubkey*”查询安装的公钥软件
4.6 RPM数据库重建
语法 :
rpm {--initdb|--rebuilddb}initdb: 初始化 如果事先不存在数据库 , 则新建之 否则 , 不执行任何操作rebuilddb: 重建已安装的包头的数据库索引目录
示例:
重建数据库 。适用场景: 索引文件损坏但 Packages 完好; 大量卸载后数据库膨胀; BDB → SQLite 格式转换
rpm --rebuilddb # 重建索引(从 Packages 主文件重新生成所有索引)
rpm --rebuilddb -v # 显示详细过程初始化空数据库。(空数据库意味着系统"忘记"了所有已安装的包。仅在极端排障场景使用。)
rpm --initdb # 创建全新的空数据库验证数据库的完整性
rpm --verifydb # 验证数据库内部一致性数据库损坏修复
# 第 0 步:备份
cp -a /var/lib/rpm /var/lib/rpm.backup.$(date +%s)
# 第 1 步:清理残留锁文件
rm -f /var/lib/rpm/__db.*
# 第 2 步:验证主文件
/usr/lib/rpm/rpmdb_verify /var/lib/rpm/Packages
# 第 3 步:若损坏,dump/load 修复
mv /var/lib/rpm/Packages /var/lib/rpm/Packages.orig
/usr/lib/rpm/rpmdb_dump Packages.orig | /usr/lib/rpm/rpmdb_load Packages
/usr/lib/rpm/rpmdb_verify Packages
# 第 4 步:重建索引
rpm --rebuilddb -v
# 第 5 步:验证
rpm -qa > /dev/null