Linux运维之教你如何定制RPM包

rpmbuild方式定制rpm包

rpmbuid是用于制作rpm格式包的工具。rpm 4.4.x版本之前,rpmbuid工具默认的工作车间为/usr/src/redhat,所以造成普通用户不能制作rpm包。rpm 4.5.x版本开始,将rpmbuid工具默认的工作车间为$HOME/rpmbuild(用户家目录),并且推荐用户尽量不用root账号制作rpm包。

1
2
3
4
5
6
7
8
9
10
11
12
#rpm版本查看方法:
[root@moban ~]# rpm -qa|grep rpm
redhat-rpm-config-9.1.0-88.el7.centos.noarch
rpm-sign-4.11.3-45.el7.x86_64
rpm-4.11.3-45.el7.x86_64
rpm-build-libs-4.11.3-45.el7.x86_64
python-srpm-macros-3-34.el7.noarch
perl-srpm-macros-1-8.el7.noarch
rpm-libs-4.11.3-45.el7.x86_64
rpm-python-4.11.3-45.el7.x86_64
rpmdevtools-8.3-8.el7_9.noarch
rpm-build-4.11.3-45.el7.x86_64

rpmbuild默认工作车间为/usr/lib/rpm/macros这个文件,具体由%_topdir宏变量进行定义。官方不建议在/usr/lib/rpm/macros目录中更改这个工作路径。如果需要则可以在用户家目录下建立一个.rpmmacros隐藏文件,在里面重新定义%_topdir,指向一个新的目录名。内容一般为:

1
2
[root@moban ~]# cat .rpmmacros
%_topdir %(echo $HOME)/rpmbuild

在%_topdir目录下一般需要有6个目录(实际操作的时候执行命令自动创建):
备注:执行rpmdev-setuptree命令会在当前用户的家目录下的rpmbuild目录(如果该目录不存在也会被自动创建)里自动建立上述目录。

目录名macros宏名说明
BUILD%_builddir编译rpm包的临时目录
BUILDROOT%_buildrootdir编译后生成的软件临时安装目录
RPMS%_rpmdir最终生成的可安装rpm包的所在目录
SOURCES%_sourcedir所有源代码和补丁文件的存放目录
SPECS%_specdir存放SPEC文件的目录(重要)
SRPMS%_srcrpmdir软件最终的rpm源码格式存放路径(暂时忽略掉,别挂在心上)

当上述目录建立好之后,将所有用于生成rpm包的源代码、shell脚本、配置文件都拷贝到SOURCES目录里,注意通常情况下源码的压缩格式都为*.tar.gz格式。然后将编辑好的SPEC文件,命名为“软件名-版本.spec”,将其拷贝到SPECS目录下。
最后切换SPEC目录下执行命令制作rpm包:

1
rpmbuild -bb rpmbuild/SPEC/软件名-版本.spec

SPEC文件是最核心的,在它里面定义了头部信息和一些“阶段”(%prep、%build、%install、%clean、%pre、%post、%preun和%postun),当rpmbuild执行时它首先会去解析SPEC文件,然后依次执行每个“阶段”里的指令。

接下来,我们来简单了解一下SPEC文件的头部。假如,我们的源码包名字是myapp-0.1.0.tar.gz,那么myapp-0.1.0.spec的头部一般如下的样子:

1
2
3
4
5
6
7
8
9
10
11
12
Name:                  myapp <===软件包的名字
Version: 0.1.0 <===软件包的版本
Release: 1%{?dist} <===发布序号(默认1开始)
Summary: my first rpm <===软件包描述信息
Group: <===软件包的安装分类,参见/usr/share/doc/rpm-4.x.x/GROUPS这个文件
License: GPL <===软件的授权方式
URL: <===这里本来写源码包的下载路径或者自己的博客地址或者公司网址之类
Source0: %{name}-%{version}.tar.gz <===源代码包的名称(默认时rpmbuild会到SOURCES目录中去找),这里的name和version就是前两行定义的值。如果有其他配置或脚本则依次用Source1、Source2等等往后增加即可。
BuildRoot: %{_topdir}/BUILDROOT <=== 这是make install时使用的“虚拟”根目录,最终制作rpm安装包的文件就来自这里。
BuildRequires: <=== 在本机编译rpm包时需要的辅助工具,以逗号分隔。假如,要求编译myapp时,gcc的版本至少为4.4.2,则可以写成gcc >=4.2.2。还有其他依赖的话则以逗号分别继续写道后面。
Requires: <=== 编译好的rpm软件在其他机器上安装时,需要依赖的其他软件包,也以逗号分隔,有版本需求的可以
%description <=== 软件包的详细说明信息,但最多只能有80个英文字符。

下面我们来看一下制作rpm包的几个关键阶段,以及所发生的事情:

阶段动作
%prep将%_sourcedir目录下的源代码解压到%_builddir目录下。如果有补丁的需要在这个阶段进行打补丁的操作
%post定义执行的脚本
%build在%_builddir目录下执行源码包的编译。一般是执行./configure和make指令
%install将需要打包到rpm软件包里的文件从%_builddir下拷贝%_buildrootdir目录下。当用户最终用rpm -ivh name-version.rpm安装软件包时,这些文件会安装到用户系统中相应的目录里
制作rpm包这个阶段是自动完成的,所以在SPEC文件里面是看不到的,这个阶段会将%_buildroot目录的相关文件制作成rpm软件包最终放到%_rpmdir目录里
%clean编译后的清理工作,这里可以执行make clean以及清空%_buildroot目录等

安装相关包和查看默认工作车间

1
2
3
4
5
6
7
8
9
[root@moban ~]# yum -y install rpm-build rpmdevtools
[root@moban ~]# rpmbuild --showrc | grep topdir
-14: _builddir %{_topdir}/BUILD
-14: _buildrootdir %{_topdir}/BUILDROOT
-14: _rpmdir %{_topdir}/RPMS
-14: _sourcedir %{_topdir}/SOURCES
-14: _specdir %{_topdir}/SPECS
-14: _srcrpmdir %{_topdir}/SRPMS
-14: _topdir %(echo $HOME)/rpmbuild

新增普通用户

1
[root@moban ~]# useradd -u 1111 build && echo '123456'|passwd --stdin build 

自动生成rpm打包所需目录

1
2
3
4
5
6
7
8
9
10
11
[build@moban ~]$ rpmdev-setuptree 
[build@moban ~]$ ls
rpmbuild
[build@moban ~]$ cd rpmbuild/
[build@moban rpmbuild]$ ll
total 0
drwxrwxr-x 2 build build 6 Sep 27 04:04 BUILD
drwxrwxr-x 2 build build 6 Sep 27 04:04 RPMS
drwxrwxr-x 2 build build 6 Sep 27 04:04 SOURCES
drwxrwxr-x 2 build build 6 Sep 27 04:04 SPECS
drwxrwxr-x 2 build build 6 Sep 27 04:04 SRPMS

将源码、配置文件等放入SOURCES目录下

1
2
3
4
5
cd SOURCES/
[build@moban SOURCES]$ wget http://nginx.org/download/nginx-1.20.0.tar.gz
[build@moban SOURCES]$ wget http://luajit.org/download/LuaJIT-2.0.5.tar.gz
[build@moban SOURCES]$ wget https://github.com/vision5/ngx_devel_kit/archive/refs/tags/v0.3.1.tar.gz
[build@moban SOURCES]$ wget https://github.com/openresty/lua-nginx-module/archive/refs/tags/v0.10.10.zip

创建SPEC模板文件熟悉

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
cd ../SPECS/
[build@moban SPECS]$ rpmdev-newspec -o nginx_waf-1.20.spec
[build@moban SPECS]$ cat nginx_waf-1.20.spec
Name: nginx_waf-1.20
Version:
Release: 1%{?dist}
Summary:
License:
URL:
Source0:
BuildRequires:
Requires:
%description

%prep
%setup -q
#这里要特别注意,如果压缩包和解压出来的文件名不相同,则用%setup -n 解压后目录名
%build
%configure
make %{?_smp_mflags}

%install
rm -rf $RPM_BUILD_ROOT
%make_install

%files
%doc

%changelog

完整的SPEC

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
[root@moban rpmbuild]# cat SPECS/nginx_waf-1.20.spec                                       
%define nginx_user nginx
%define nginx_group nginx
%define nginx_dir /application/nginx-1.20/
Name: nginx
Version: 1.20.0
Release: 1%{?dist}
Summary: install nginx web.

License: GPL
URL: www.boysec.cn
Source0: nginx-1.20.0.tar.gz

BuildRequires: gcc, gcc-c++, pcre, pcre-devel, openssl, openssl-devel
Requires: gcc, gcc-c++, pcre, pcre-devel, openssl, openssl-devel

%description
install nginx web server...

%pre
grep %nginx_user /etc/passwd > /dev/null
if [ $? != 0 ]
then useradd %{nginx_user} -M -s /sbin/nologin
fi
[ -d %{nginx_dir} ] && mkdir -p %{nginx_dir} || rm -rf %{nginx_dir}

%prep
%setup -q

%build
./configure --user=%{nginx_user} --group=%{nginx_group} --prefix=%{nginx_dir} --with-http_stub_status_module --with-http_ssl_module --with-http_sub_module --with-http_gzip_static_module
make %{?_smp_mflags}


%install
rm -rf %{buildroot}
make install DESTDIR=%{buildroot}

%files
%doc
%{nginx_dir}
%{nginx_dir}/*

用rpmbuild命令制作rpm包,rpmbuild命令会根据spec文件来生成rpm包

1
2
3
4
5
6
7
8
rpmbuild  
-ba 既生成src.rpm又生成二进制rpm
-bs 只生成src的rpm
-bb 只生二进制的rpm
-bp 执行到pre
-bc 执行到 build段
-bi 执行install段
-bl 检测有文件没包含

RPM包制作拓展

下面我们来拓展一下,比如:我们想为tengine增加控制脚本,可以通过 start|stop控制,我们还想更换一下默认的首页index.html,默认的fastcgi_params是不能直接连接php的,所以我们替换 为新的配置文件,我们也可以用设置好的nginx.conf替换原来的nginx.conf。基于上述步骤下面继续

1.把修改后的首页文件index.html,控制脚本init.nginx,fastCGI配置文件fastcgi_params,Nginx配置文件nginx.conf 放到SOURCES中 。

1
2
 ls SOURCES/ 
fastcgi_params index.html init.nginx nginx.conf tengine-2.1.2.tar.gz

编辑tengine.spec,修改

2.1 介绍区域的SOURCE0下增加如下

1
2
3
4
5
1. Source0:    %{name}-%{version}.tar.gz 
2. Source1: index.html
3. Source2: init.nginx
4. Source3: fastcgi_params
5. Source4: nginx.conf

安装区域增加如下

1
2
3
4
5
1. make install DESTDIR=%{buildroot} 
2. %{__install} -p -D %{SOURCE1} %{buildroot}/usr/html/index.html #%{__install}这个宏代表install命令
3. %{__install} -p -D -m 0755 %{SOURCE2} %{buildroot}/etc/rc.d/init.d/nginx
4. %{__install} -p -D %{SOURCE3} %{buildroot}/etc/nginx/fastcgi_params
5. %{__install} -p -D %{SOURCE4} %{buildroot}/etc/nginx/nginx.conf

2.3 脚本区域增加如下

1
2
3
4
1. %post 
2. if [ $1 == 1 ];then
3. /sbin/chkconfig --add nginx
4. fi

2.4 %file区域增加如下

1
2
3
4
5
6
7
8
9
1. %files 
2. %defattr (-,root,root,0755)
3. /etc/
4. /usr/
5. /var/
6. %config(noreplace) /etc/nginx/nginx.conf #%config表明这是个配置文件noplace表明不能替换
7. %config(noreplace) /etc/nginx/fastcgi_params
8. %doc /usr/html/index.html #%doc表明这个是文档
9. %attr(0755,root,root) /etc/rc.d/init.d/nginx #%attr后面的是权限,属主,属组

3.生成rpm文件测试

  1. rpmbuild -ba tengine.spec

  2. 安装测试

到此RPM包制作完毕,你可以根据你的需求制作RPM包吧。