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 壓縮算法,提供較好的壓縮比。