<
Linux下定制RPM软件包
>
上一篇

GlusterFS集群的一次生产配置实践
下一篇

Hello Jekyll

什么是RPM

RPM是RPM Package Manager的缩写,以前的缩写为Red-Hat Package Manager(RPM软件包管理器),这一文件格式名称虽然打上了RedHat的标志(其诞生时用于Red Hat Linux),但其开放的设计理念使其不仅被Linux诸多发行版所采用,还被其它操作系统平台引入,例如Novell Netware,AIX等

000

为什么要定制

定制RPM包一般来源于工程中的需要,例如某些软件只提供源码版本,每次部署都要copy一份以前编译好的版本到新的开发测试环境中去,这个过程费劲不说(尤其在网段之间是隔离的环境中),随着时间的推移,以前版本中做过的个性化配置与修改往往也被引入到了新的环境,不利于后续的开发测试工作,所以利用RPM把标准的软件包管理起来作为基线是自然而然的选择。

最近项目中使用了nginx,写此文时,Red Hat官方源中的版本到1.8.1,但在该红帽版本中却没有包含对”会话黏连”这样第三方模块的编译支持在内,项目开发中却又要使用该功能,所以基于社区版本制作RPM,将我们需要的第三方模块编译进去。

步骤纪要

这里写成纪要,有种奇怪的感觉,严重不符合工程思维,但第一时间没有记录步骤,所以用截图的方式作为纪要说明。

1. 准备rpm打包工具

使用yum安装rpmbuild工具,前提是确保有一个可用的yum源

# yum install rpm* rpm-build rpmdev*

001

002

2. 生产打包目录

# rpmdev-setuptree

root用户默认在根目录中生成(当然,如果你的环境比较重要,可以使用普通用户进行操作以减少风险,目录也可以配置文件macrofiles中设置)

003

查看目录结构

004

目录的简要描述如下

目录 Description
BUILD 源代码解压后的存放目录
RPMS 制作完成后的RPM包存放目录,里面有与平台相关的子目录
SOURCES 收集的源材料,补丁的存放位置
SPECS SPEC文件存放目录
SRMPS 存放SRMPS生成的目录
   

3. 准备打包源码及相关文件

上传nginx源码包(源码包来源 wget http://nginx.org/down/nginx-1.8.1.tar.gz)至SOURCES路径下

005

生成SPEC文件

wikipedia中用了一个非常形象的描述,将SPEC文件称作是制作RPM包的”食谱“,它是以.spec为后缀的文件,其中包含了包名、版本、RPM版本号、和build、install、clean的步骤以及修改日志等,并且可以支持从一个spec文件构建多个RPM包。

所以我们可以基于spec文件来灵活地定制我们需要的各类特性,这里先简述一个常规spec文件的大致内容,后面接着给出一个捷径,如何基于已有的RPM文件进行提取并修改spec,并给出spec文件结构中各部分含义。

制作常规spec文件
# rpmdev-newspec -o nginx-1.8.1.spec

006

修改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/.

4. build RPM

执行编译命令

# rpmbuild -bb nginx.1.8.1.spec

007

编译过程将会首先检查spec文件中BuildRequires字段中包含的软件包,如果未安装相关编译工具,会提示缺少软件包,安装后重新执行rpmbuild -bb nginx.1.8.1.spec。完成编译。

A SIMPLE WAY

从以上中可以看到从无到有编写一个健壮的spec文件需要考虑很多细节,从工程的角度而言,如果你的定制需求相比于上述过程是很小的一部分,那么可以基于现有的RPM包提取spec文件并基于此进行修改,已达到快速实现你的定制需求的目的。

1. 下载SRPM

上传src.rpm包至rpmbuild目录下的SOURCES路径下,src包来源官方网站:http://nginx.org/packages/rhel/7/SRPMS/

2. 提取src.rpm中文件

# 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阶段时安装这些配置文件

3.准备要加入编译的第三方模块

上传“会话粘连”模块的tar包至SOURCES目录下,并解压

解压

4. 修改SPEC文件

将nginx.spec移动至rpmbuild目录的SPECS路径下,后续将修改此SPEC文件,并基于修改后的SPEC文件重新打包rpm

修改SPEC文件,加入第三方模块进行编译,具体的修改处以及SPEC文件内容简述详见文末

5.rpmbuild

使用修改过的spec文件打包rpm

打包完成

在RPMS路径下,查看打包结果,三个文件分别为rpm包、debug包、debuginfo包

6. rpm安装测试、启动验证

rpm包拷贝至其它机器,测试安装

测试启动

进程验证

至此,就已经完成了rpm包的定制打包。

How SPEC works ?

以本文为例,简述一下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文件已在生产系统使用,并运行正常。

Top
Foot