RPM是RPM Package Manager的缩写,以前的缩写为Red-Hat Package Manager(RPM软件包管理器),这一文件格式名称虽然打上了RedHat的标志(其诞生时用于Red Hat Linux),但其开放的设计理念使其不仅被Linux诸多发行版所采用,还被其它操作系统平台引入,例如Novell Netware,AIX等 。
定制RPM包一般来源于工程中的需要,例如某些软件只提供源码版本,每次部署都要copy一份以前编译好的版本到新的开发测试环境中去,这个过程费劲不说(尤其在网段之间是隔离的环境中),随着时间的推移,以前版本中做过的个性化配置与修改往往也被引入到了新的环境,不利于后续的开发测试工作,所以利用RPM把标准的软件包管理起来作为基线是自然而然的选择。
最近项目中使用了nginx,写此文时,Red Hat官方源中的版本到1.8.1,但在该红帽版本中却没有包含对”会话黏连”这样第三方模块的编译支持在内,项目开发中却又要使用该功能,所以基于社区版本制作RPM,将我们需要的第三方模块编译进去。
这里写成纪要,有种奇怪的感觉,严重不符合工程思维,但第一时间没有记录步骤,所以用截图的方式作为纪要说明。
使用yum安装rpmbuild工具,前提是确保有一个可用的yum源
# yum install rpm* rpm-build rpmdev*
# rpmdev-setuptree
root用户默认在根目录中生成(当然,如果你的环境比较重要,可以使用普通用户进行操作以减少风险,目录也可以配置文件macrofiles中设置)
查看目录结构
目录的简要描述如下
目录 | Description |
---|---|
BUILD | 源代码解压后的存放目录 |
RPMS | 制作完成后的RPM包存放目录,里面有与平台相关的子目录 |
SOURCES | 收集的源材料,补丁的存放位置 |
SPECS | SPEC文件存放目录 |
SRMPS | 存放SRMPS生成的目录 |
上传nginx源码包(源码包来源 wget http://nginx.org/down/nginx-1.8.1.tar.gz
)至SOURCES路径下
wikipedia中用了一个非常形象的描述,将SPEC文件称作是制作RPM包的”食谱“,它是以.spec
为后缀的文件,其中包含了包名、版本、RPM版本号、和build、install、clean的步骤以及修改日志等,并且可以支持从一个spec文件构建多个RPM包。
所以我们可以基于spec文件来灵活地定制我们需要的各类特性,这里先简述一个常规spec文件的大致内容,后面接着给出一个捷径,如何基于已有的RPM文件进行提取并修改spec,并给出spec文件结构中各部分含义。
# rpmdev-newspec -o nginx-1.8.1.spec
修改spec
Name: nginx
Version: 1.8.1
Release: 1%{?dist}
Summary: This version of Nginx is build for POP
License: GPL
URL: http://nginx.org/download/nginx-1.8.1.tar.gz
Packager: jcchen_awesome
Source0: %{name}-%{version}.tar.gz
Source1: nginx.conf[u1]
BuildRoot: %{_topdir}/BUILDROOT
BuildRequires: gcc >= 4.8.3,gcc-c++,perl-ExtUtils-Embed,perl,perl-devel
[u1]此处为自定义的配置文件,如果需要增加其他配置文件,可继续添加Source2、Source3… 文件路径为编译路径下的SOURCES目录下
%description
Add sticky module in this RPM
%prep
%setup -q
%build
./configure –prefix=/opt/%{name}-%{version}/ –pid-path=/opt/%{name}-%{version}/nginx.pid –lock-path=/opt/%{name}-%{version}/nginx.lock –user=pop –group=pop –error-log-path=/opt/%{name}-%{version}/logs/error.log –http-log-path=/opt/%{name}-%{version}/logs/access.log –with-http_ssl_module –with-http_stub_status_module –with-http_gzip_static_module –with-http_gunzip_module –with-file-aio –with-http_realip_module –with-http_perl_module –with-http_ssl_module –with-http_spdy_module –without-poll_module –without-select_module –without-http_ssi_module –without-http_userid_module –without-http_memcached_module –without-mail_pop3_module –without-mail_imap_module –without-mail_smtp_module –without-http_uwsgi_module –without-http_scgi_module –http-client-body-temp-path=/opt/%{name}-%{version}/client_body_temp –http-proxy-temp-path=/opt/%{name}-%{version}/proxy_temp –http-fastcgi-temp-path=/opt/%{name}-%{version}/fastcgi_temp
–with-pcre=$RPM_SOURCE_DIR/pcre-8.38[u2]
–with-openssl=$RPM_SOURCE_DIR/openssl-1.0.2f
–with-zlib=$RPM_SOURCE_DIR/zlib-1.2.8
–with-pcre-jit –add-module=$RPM_SOURCE_DIR/nginx-sticky-module-ng [u3] –with-ld-opt=-Wl,-E
make %{?_smp_mflags}
%install
rm -rf $RPM_BUILD_ROOT
make install DESTDIR=$RPM_BUILD_ROOT
#install configure file
install -p -D -m 0644 %{SOURCE1} %{buildroot}/opt/%{name}-%{version}/conf/nginx.conf[u4]
%clean
rm -rf $RPM_BUILD_ROOT
%files
%defattr(-,root,root,-)
/opt/%{name}-%{version}/
%config(noreplace) /opt/%{name}-%{version}/conf/nginx.conf
/usr/lib64/perl5/perllocal.pod
/usr/local/lib64/perl5/auto/nginx/.packlist
/usr/local/lib64/perl5/auto/nginx/nginx.bs
/usr/local/lib64/perl5/auto/nginx/nginx.so
/usr/local/lib64/perl5/nginx.pm
/usr/local/share/man/man3/nginx.3pm
[u5]
%changelog
configure parameter which used in this version is copied from system-environment
[u2]Pcre库提前下载好,并解压至编译路径下的SOURCES文件夹
[u3]同上
[u4]将之前添加的自定义配置文件安装,并设置权限
[u5]第一次编译打包后失败,提示该类文件被安装但未被打包,将此部分添加至此处,重新rpmbuild通过
上述spec文件中%configure中制定了相关库的路径
–with-pcre=
–with-openssl=
–with-zlib=
–add-module=
编译前需要将以上文件解压缩至相应路径,在上述配置中,应该解压至~/rpmbuild/SOURCES/.
执行编译命令
# rpmbuild -bb nginx.1.8.1.spec
编译过程将会首先检查spec文件中BuildRequires字段中包含的软件包,如果未安装相关编译工具,会提示缺少软件包,安装后重新执行rpmbuild -bb nginx.1.8.1.spec。完成编译。
从以上中可以看到从无到有编写一个健壮的spec文件需要考虑很多细节,从工程的角度而言,如果你的定制需求相比于上述过程是很小的一部分,那么可以基于现有的RPM包提取spec文件并基于此进行修改,已达到快速实现你的定制需求的目的。
上传src.rpm包至rpmbuild目录下的SOURCES路径下,src包来源官方网站:http://nginx.org/packages/rhel/7/SRPMS/
# rpm2cpio nginx-1.8.1-1.el7.ngx.src.rpm | cpio -idv
使用rpm2cpio命令提取src.rpm中文件至当前目录,可以看到提取出的文件分为三类:(1)源码包:nginx-1.8.1.tar.gz ,该包与官方下载网址nginx.org/packages/rhel/7/x86_64/RPMS中对应版本的包相同;(2)SPEC文件:nginx.spec,该文件为rpm打包的脚本文件,其中规定了打包的各项流程和操作;(3)其它配置文件:make_install阶段时安装这些配置文件
上传“会话粘连”模块的tar包至SOURCES目录下,并解压
解压
将nginx.spec移动至rpmbuild目录的SPECS路径下,后续将修改此SPEC文件,并基于修改后的SPEC文件重新打包rpm
修改SPEC文件,加入第三方模块进行编译,具体的修改处以及SPEC文件内容简述详见文末
使用修改过的spec文件打包rpm
打包完成
在RPMS路径下,查看打包结果,三个文件分别为rpm包、debug包、debuginfo包
rpm包拷贝至其它机器,测试安装
测试启动
进程验证
至此,就已经完成了rpm包的定制打包。
以本文为例,简述一下spec文件的各阶段含义
文件开始宏定义了nginx_home路径、用户、组等
对于不同的系统版本,定义安装依赖与编译依赖,这里openssl库以依赖的方式引入,不需要在configure里单独加入库路径,编译时会先检查编译依赖BuildRequires中的包与版本,如果缺失或版本不符会中断并提示缺失的依赖,使用yum安装对应包即可
RPM描述:简介、名称、版本、发行版本、厂商、URL地址等
源文件定义:在该处使用Source字段定义源文件,也就是在第2小节中,在src.rpm中提取出的若干文件
添加编译依赖:zlib-devel、pcre-devel库也以编译依赖的方式定义,无需再configure中添加库路径;这里增加了gcc等编译依赖
编译分为各个阶段
%preq阶段为编译前的准备操作,%setup为定义的宏,用于对源码包进行解压
%build阶段为编译选项配置和make过程,官方spec文件中进行了两遍配置与make操作,第一遍为debug包的编译如上图所示,第二遍为常规安装包的编译如下图所示。这里在两个configure配置中均做了修改:(1)添加会话粘连模块。路径为在第3小节中模块解压的路径(2)添加pcre-jit,因项目中原系统环境的nginx上使用了该编译参数,增加pcre正则库的jit编译支持
%install阶段 安装各类文件,包括使用Source定义的各类源文件也在此过程install
%clean阶段 清理build文件
%files阶段 打包各类文件,可以使用%config指定哪些文件为配置文件,%attr指定文件属性
%pre定义安装前的操作,如添加用户
%post为安装后的操作,注册服务、打印欢迎信息、创建error.log、access.log等文件
%preun 和 %postun 阶段
分别定义了卸载前和卸载后的操作 例如注销服务
%changelog
记录修改信息,这里注释掉了以前的change信息,否则编译时会出现“bogus date”的错误
经该方法制作的rpm文件已在生产系统使用,并运行正常。