RPM之(1)基础使用
RPM之(1)基础使用
Author: Once Day Date: 2025年5月26日
一位热衷于Linux学习和开发的菜鸟,试图谱写一场冒险之旅,也许终点只是一场白日梦…
漫漫长路,有人对你微笑过嘛…
全系列文章可参考专栏: Linux实践记录_Once-Day的博客-CSDN博客
参考文章:
- Linux安装及管理工具(rpm和yum)_yam源-CSDN博客
- linux下RPM工具的使用:RPM安装/查询/查看/卸载/升级软件包 - 人生的哲理 - 博客园
- Linux软件管理-RPM工具 - 知乎
- Linux rpm命令 | 菜鸟教程
- rpm.org - Home
文章目录
- RPM之(1)基础使用
- 1. 概述
- 1.1 背景
- 1.2 RPM包命名格式
- 1.3 常见RPM命令
- 2. 实践
- 2.1 构建RPM包
- 2.2 安装RPM包
- 2.3 RPM优化(压缩速度)
1. 概述
1.1 背景
RPM(Red Hat Package Manager)的发展历程可以追溯到1997年。当时Linux发行版的软件包管理比较混乱,Red Hat公司为了解决这个问题,开发了RPM包管理系统。
最初RPM是专门为Red Hat Linux设计的,但由于其优秀的特性,很快被其他Linux发行版采用。SUSE、OpenSUSE、CentOS等知名发行版都将RPM作为默认的包管理系统。
RPM的主要创新在于:
- 引入了软件包依赖关系管理,解决了软件安装时的依赖问题。
- 支持数字签名验证,提高了软件分发的安全性。
- 实现了软件包数据库,方便系统管理和维护。
- 支持软件包升级和回滚,降低了系统维护风险。
RPM的核心特性:
-
数据库管理:维护着已安装软件的完整数据库,存储在/var/lib/rpm目录下,记录文件属性,依赖关系等信息。
-
依赖解析:自动处理软件包之间的依赖关系,防止删除被其他包依赖的包,支持版本号限定的依赖关系。
-
文件完整性验证:使用MD5等算法验证包完整性,支持GPG签名验证,防止软件包被篡改。
-
软件包制作:支持从源码构建RPM包,使用spec文件描述构建过程,可以创建源码包(SRPM)。
RPM的高级特性:
-
并行安装:支持同一软件的多个版本共存,通过不同的包名实现。
-
事务性操作:安装过程是原子的,失败时自动回滚。
-
脚本支持:pre/post install脚本,pre/post uninstall脚本,trigger脚本。
-
虚拟包:提供功能而不是实际文件,用于处理替代包。
经过多年发展,RPM已经成为Linux世界的重要标准之一。目前最新的RPM 4.x版本增加了很多现代特性,比如并行安装支持、更强的依赖分析等。作为一个成熟的包管理工具,RPM为Linux系统的软件管理带来了规范化和便利性,是Linux系统管理中不可或缺的工具。
1.2 RPM包命名格式
RPM包命名格式如下:
name-version-release.architecture.rpm
name(名称):软件的名称,如nginx、httpd、mysql等,通常使用小写字母,可以包含数字和下划线,示例:nginx、postgresql、mariadb-server。
version(版本号):原始软件的版本号,通常由主版本号.次版本号.修订号组成,遵循软件原始发布版本,示例:1.20.1、2.4.6、5.7.38。
release(发布号):该版本的RPM包的修订号,通常包含发行版标识,格式:修订号.发行版标识,示例:9.el8(第9次构建,适用于RHEL 8),1.fc35(第1次构建,适用于Fedora 35),2.el7_9(第2次构建,适用于RHEL 7.9)。
architecture(架构):表示软件包支持的硬件平台,常见架构类型:x86_64:64位x86架构,i386/i686:32位x86架构,aarch64:64位ARM架构,noarch:与架构无关的包,ppc64le:IBM POWER架构,s390x:IBM System z架构。
特殊情况说明:
epoch(纪元号):当需要处理版本号冲突时使用,格式:epoch:name-version-release.architecture.rpm,示例:1:nginx-1.20.1-9.el8.x86_64.rpm。
debuginfo包:用于调试的符号表信息,命名格式:name-debuginfo-version-release.architecture.rpm,示例:nginx-debuginfo-1.20.1-9.el8.x86_64.rpm。
源码包(SRPM):扩展名为.src.rpm,架构通常为src,示例:nginx-1.20.1-9.el8.src.rpm。
版本比较规则:首先比较epoch(如果存在),然后比较version,最后比较release。
1.3 常见RPM命令
安装软件包:
rpm -ivh package.rpm
升级软件包:
rpm -Uvh package.rpm
卸载软件包:
rpm -e package
查询已安装的包:
rpm -qa | grep nginx
查看包信息:
rpm -qi nginx
查看包中的文件列表:
rpm -ql nginx
查询文件属于哪个包:
rpm -qf /etc/nginx/nginx.conf
一个完整的安装示例:
# 下载nginx RPM包
wget http://nginx.org/packages/rhel/8/x86_64/RPMS/nginx-1.20.1-1.el8.ngx.x86_64.rpm# 查看包信息
rpm -qip nginx-1.20.1-1.el8.ngx.x86_64.rpm# 安装包
rpm -ivh nginx-1.20.1-1.el8.ngx.x86_64.rpm# 确认安装
rpm -q nginx# 查看安装的文件
rpm -ql nginx# 启动服务
systemctl start nginx
2. 实践
2.1 构建RPM包
首先需要安装必要工具:
# 安装必要的RPM工具
sudo apt update
sudo apt install rpm
sudo apt install rpmbuild
sudo apt install rpmdevtools
sudo apt install alien# 安装构建工具
sudo apt install build-essential
创建RPM构建目录:
# 创建标准RPM目录结构
rpmdev-setuptree# 确认目录结构
ls -l ~/rpmbuild/
使用下面的脚本创建SPEC文件:
#!/bin/bash
###
# SPDX-License-Identifier: BSD-3-Clause
#
# Copyright (c) 2025 Once Day <once_day@qq.com>, All rights reserved.
## @FilePath: /devops/scripts/rpm_build.sh
# @Author: Once Day <once_day@qq.com>.
# @Date: 2025-05-22 15:00
# @info: Encoder=utf-8,Tabsize=4,Eol=\n.
#
# @Description:
# 构建RPM包
#
#### 开启shell调试
# set -x# 当前目录路径
export SOURCE_DIR=${SOURCE_DIR:-$(pwd)}# Shell 日志函数
# log "file" "line" "INFO" "This is a info message"
log() {local timestamp=$(date +"%Y-%m-%d %H:%M:%S")local script_name=$(basename "$1")local line_number=$2local level=$3local message=$4# 输出日志echo -e "[$timestamp] [$script_name:$line_number] [$3] $4"
}# 封装四个日志级别函数接口
# BASH_SOURCE[1] 表示调用者的文件名
# BASH_LINENO 表示调用者的行号
INFO() {log ${BASH_SOURCE[1]} $BASH_LINENO "INFO" "$1"
}WARN() {log ${BASH_SOURCE[1]} $BASH_LINENO "WARN" "$1"
}ERROR() {log ${BASH_SOURCE[1]} $BASH_LINENO "ERROR" "$1"
}DEBUG() {log ${BASH_SOURCE[1]} $BASH_LINENO "DEBUG" "$1"
}# 第一个参数是软件信息
if [ -n "$1" ]; thenSOFTNAME=$1# valgrind-3.21.0# SOURCE_NAME=valgrind# SOURCE_VERSION=3.21.0# 取出版本号SOURCE_VERSION=${SOFTNAME##*-}# 取出软件包名称SOURCE_NAME=${SOFTNAME%-*}
elseERROR "No sortware name specified, please specify it as the first argument."exit 1
fi
INFO "SOURCE_DIR: [$SOURCE_DIR]"
INFO "SOURCE_NAME: [$SOURCE_NAME]"
INFO "SOURCE_VERSION: [$SOURCE_VERSION]"# 第二个参数是构建产物目录
if [ -n "$2" ]; thenTARGET_DIR=$2# 使用绝对路径TARGET_DIR=$(realpath $TARGET_DIR)
elseERROR "No build target directory specified, please specify it as the first argument."exit 1
fi
INFO "TARGET_DIR: [$TARGET_DIR]"# 创建RPM包目录
RPM_DIR=${SOURCE_DIR}/rpmbuild
if [ ! -d "$RPM_DIR" ]; thenmkdir -p $RPM_DIR
fi
INFO "RPM_DIR: [$RPM_DIR]"# 创建RPM包目录结构
RPM_BUILD_DIR=${RPM_DIR}/BUILD
if [ ! -d "$RPM_BUILD_DIR" ]; thenmkdir -p $RPM_BUILD_DIR
fi
INFO "RPM_BUILD_DIR: [$RPM_BUILD_DIR]"RPM_RPMS_DIR=${RPM_DIR}/RPMS
if [ ! -d "$RPM_RPMS_DIR" ]; thenmkdir -p $RPM_RPMS_DIR
fi
INFO "RPM_RPMS_DIR: [$RPM_RPMS_DIR]"RPM_SRCS_DIR=${RPM_DIR}/SOURCES
if [ ! -d "$RPM_SRCS_DIR" ]; thenmkdir -p $RPM_SRCS_DIR
fi
INFO "RPM_SRCS_DIR: [$RPM_SRCS_DIR]"RPM_SPECS_DIR=${RPM_DIR}/SPECS
if [ ! -d "$RPM_SPECS_DIR" ]; thenmkdir -p $RPM_SPECS_DIR
fi
INFO "RPM_SPECS_DIR: [$RPM_SPECS_DIR]"RPM_SRCS_DIR=${RPM_DIR}/SOURCES
if [ ! -d "$RPM_SRCS_DIR" ]; thenmkdir -p $RPM_SRCS_DIR
fi
INFO "RPM_SRCS_DIR: [$RPM_SRCS_DIR]"# 编写RPM spec文件
SPEC_FILE=${RPM_SPECS_DIR}/${SOURCE_NAME}.spec
rm -f $SPEC_FILE
INFO "Delete Old SPEC_FILE: [$SPEC_FILE]"# 创建RPM spec文件
if [ ! -f "$SPEC_FILE" ]; thencat <<EOF > $SPEC_FILE
Name: $SOURCE_NAME
Version: $SOURCE_VERSION
Release: 1%{?dist}
Summary: $SOURCE_NAME RPM package
Group: Applications/System
BuildArch: x86_64License: (Unknown)
URL: (Unknown)%description
This package contains a pre-built binary of the $SOURCE_NAME program.%build
# No build needed%install
# Copy all extracted files into buildroot
cp -av $TARGET_DIR/* %{buildroot}/%files
%defattr(-,root,root,-)
%dir /
/*%changelog
* $(date +"%a %b %d %Y") Once Day <once_day@qq.com> - $SOURCE_VERSION-1
- Initial RPM package from pre-built filesEOF
fiINFO "SPEC_FILE: [$SPEC_FILE]"
运行该脚本,并且查看输出结果(SPEC文件):
SPEC文件用于打包 valgrind 程序的文件,其字段含义如下:
-
基本信息部分:软件包名称是 valgrind,版本号为 3.21.0,Release 版本号为 1,是一个系统工具类软件包,仅支持 x86_64 架构,License 和 URL 信息未指定。
-
功能描述:这个 RPM 包含预编译好的 valgrind 程序文件。
-
构建和安装:不需要编译构建步骤,安装时会将
/root/workspace/packages/build/release-x86_64-local/valgrind-3.21.0/
目录下的所有文件复制到最终安装目录。 -
文件部分:包含根目录(/)及其下所有文件,所有文件的属主和属组都设置为 root。
-
更新日志:2025年5月26日由 Once Day 创建的初始版本,这是首次将预编译文件打包成 RPM。
这是一个相对简单的 spec 文件,主要用于将已编译好的 valgrind 程序打包成 RPM 格式以便于分发安装。
最后,执行实际打包操作:
rpmbuild -bb rpmbuild/SPECS/valgrind.spec
最终生成文件在~/rpmbuild/RPMS/
目录下:
root@de92817fb2e7:~/workspace/packages# ll /root/rpmbuild/RPMS/x86_64/
total 18876
drwxr-xr-x 2 root root 4096 May 22 10:45 ./
drwxr-xr-x 3 root root 4096 May 22 10:45 ../
-rw-r--r-- 1 root root 19317648 May 26 23:31 valgrind-3.21.0-1.x86_64.rpm
2.2 安装RPM包
使用下面的命令安装上述软件:
rpm --nodeps --notriggers -ivh --force valgrind-3.21.0-1.x86_64.rpm
主要选项含义:
-i
: install 的缩写,表示安装操作。-v
: verbose 的缩写,显示详细的安装过程信息。-h
: hash 的缩写,显示安装进度条。--nodeps
: 忽略包的依赖关系检查,强制安装即使缺少依赖包。--notriggers
: 忽略安装过程中的触发器脚本执行。--force
: 强制安装,即使覆盖现有文件。
这是一个比较"野蛮"的安装方式,忽略了依赖检查,可能导致程序无法正常运行,也跳过了触发器脚本,可能影响某些配置的自动化设置,并且强制覆盖现有文件,可能破坏系统中的其他程序。
这种安装方式通常用于特殊情况,需要覆盖安装或降级安装,所以对于日常开发调试来说,非常合适。
一般情况下推荐使用 rpm -ivh
。
2.3 RPM优化(压缩速度)
新版本的RPM与旧版本buildroot配合时,可能会出现Error: Empty %files file
的报错问题,这是由于这部分文件不会被预先安装,但是RPM会提前检查,从而出现冲突,添加--define "__spec_install_pre /bin/true"
选项,这样就可以兼容旧版本buildroot了。
通常情况下,RPM使用gzip进行压缩,只能单线程工作,在打包文件较大时,效率非常低,需要几十秒的时间。
RPM包的压缩涉及几个主要方面:
-
常用压缩格式:gzip (.gz):传统格式,压缩比一般,速度快;bzip2 (.bz2):较好压缩比,速度较慢;xz (.xz):最佳压缩比,CPU占用较高;zstd (.zst):新格式,在速度和压缩比间较好平衡。
-
压缩级别:gzip: 1-9级,默认6;bzip2: 1-9级,默认9;xz: 0-9级,默认6;zstd: 1-19级,默认3。
常用命令选项:
# 使用gzip压缩
--define "_binary_payload w9.gzdio"# 使用bzip2压缩
--define "_binary_payload w9.bzdio"# 使用xz压缩(带线程数)
--define "_binary_payload w6T8.xzdio"# 使用zstd压缩(带线程数)
--define "_binary_payload w3T8.zstdio"
性能特点:gzip: 速度最快,压缩比最低;bzip2: 速度和压缩比均中等;xz: 最高压缩比,速度最慢;zstd: 较好压缩比,速度接近gzip。小型包:使用gzip即可。大型包:考虑xz或zstd。需要快速部署:选择gzip或zstd。注重存储空间:选择xz。
对于大型的rpm包,通常可以使用下面的选项参数:
--define "_binary_payload w0T24.xzdio"
参数组成:
w
: 表示写入方式0
: 存储文件的格式(0代表标准格式)T
: 表示使用新的标头格式24
: 指定并行压缩的线程数(这里是24线程).xzdio
: 使用 xz 压缩算法进行压缩
通过指定 24 线程进行并行压缩,显著提高压缩速度,使用 xz 压缩算法,提供较好的压缩比。