一、rpmbuild及rpm
rpm优点:
二、rpmbuild安装
$ yum install rpmbuild
如果上述方法无法找到该系统对应的rpmbuild版本导致安装失败,可使用下面方法
$ yum list |grep rpm-build 查找合适的rpm-build包
$ yum install -y rpm-build.x86_64
然后还需要安装rpmdevtools
$ yum install rpmdevtools
$ rpmdev-setuptree
此时rpmbuild就安装完毕了,可以查看rpmbuild工作目录
$ rpmbuild --showrc | grep topdir
目录名 | 作用 |
BUILD | 你要打包的文件将会在这里编译(编译rpm包的临时目录) |
BUILDROOT | 在虚拟安装(make install)的目录(编译后生成的软件临时安装目录) |
RPMS | 存放生成的二进制的rpm包(生成的可安装的rpm安装包所在目录) |
SOURCES | 你要编译的源码包会被copy到这里(所有源代码和补丁文件的存在目录) |
SPECS | 你执行的spec文件会被copy到这里(存放SOEC文件的目录) |
SRPMS | 软件最终的rpm源码格式存放路径 |
三、rpmbuild详解
-bp 只作准备 (解压与打补丁)-bs 只做成*.src.rpm
更具体的用法说明
Build options with [ | |
*rpmbuild的其他使用项
--buildroot=DIRECTORY override build root
*确定以root目录建立包
--clean remove build tree when done
*完成打包后清除BUILD下的文件目录
--nobuild do not execute any stages of the build
*不进行BUILD的阶段
--nodeps do not verify build dependencies
*不检查建立包时的关联文件
--nodirtokens
generate package header(s) compatible with (legacy) rpm[23] packaging
--rmsource remove sources when done
*完成打包后清除sources
--rmspec remove specfile when done
*完成打包后清除specfile
--short-circuit skip straight to specified stage (only for c,i)
*跳过
--target=CPU-VENDOR-OS override target platform
*确定包的最终使用平台
四、spec文件详解
生成rpm除了源码外,最重要的就是懂得编写.spec脚本。rpm建包的原理其实并不复杂,可以理解为按照标准的格式整理一些信息,包括:软件基础信息,以及安装、卸载前后执行的脚本,对源码包解压、打补丁、编译,安装路径和文件等。
########################## 关键字 ##############################
Summary: ELK(elasticsearch+logstash+kibana+filebeat) Server
#软件包的内容概要
Name: elk #软件包的名称,后面可使用%{name}的方式引用
Version: 1.0.0 #版本号
Release: 1 #发布序列号,也就是第几次制作rpm后面可使用%{release}引用
License: GPL #许可,GPL还是BSD等(一般为GPL)
Packager: RPMBuild #打包者的信息
Group: Applications/System #软件分组,建议使用标准分组
BuildRoot: / #这个是安装或编译时使用的“虚拟目录”,该参数非常重要,因为在生成rpm的过程中,执行make install时就会把软件安装到上述的路径中,在打包的时候,同样依赖“虚拟目录”为“根目录”进行操作(即%files段)。后面可使用$RPM_BUILD_ROOT 方式引用。
BuildRequires: gcc,make #制作过程中用到的软件包
URL: #软件的主页
PATCH #补丁源码,可使用Patch1、Patch2等标识多个补丁,使用%patch0或%{patch0}引用
Provides: src #指明本软件一些特定的功能,以便其他rpm识别
Prefix: %{_prefix} #这个主要是为了解决今后安装rpm包时,并不一定把软件安装到rpm中打包的目录的情况。这样,必须在这里定义该标识,并在编写%install脚本的时候引用,才能实现rpm安装时重新指定位置的功能
Prefix: %{_sysconfdir} #这个原因和上面的一样,但由于%{_prefix}指/usr,而对于其他的文件,例如/etc下的配置文件,则需要用%{_sysconfdir}标识
Build Arch: #指编译的目标处理器架构,noarch标识不指定,但通常都是以/usr/lib/rpm/marcros中的内容为默认值
Requires: /bin/sh /usr/bin/getent /usr/sbin/useradd /usr/sbin/userdel
#该rpm包所依赖的软件包名称,可以用>=或<=表示大于或小于某一特定版本
Source0: %{name}-%{version}.tar.gz
#定义用到的source,也就是你的源码,如果没有源码,则不需要声明词宏变量
%define _rpmfilename %%{NAME}-%%{VERSION}.%%{ARCH}.rpm
########################## spec脚本主体 ##############################
%prep #预处理脚本
%setup -n %{name}-%{version} #把源码包解压并放好,通常是从/usr/src/asianux/SOURCES里的包解压到/usr/src/asianux/BUILD/%{name}-%{version}中。一般用%setup -c就可以了,但有两种情况:一就是同时编译多个源码包,二就是源码的tar包的名称与解压出来的目录不一致,此时,就需要使用-n参数指定一下了。
%patch #打补丁, 通常补丁都会一起在源码tar.gz包中,或放到SOURCES目录下。一般参数为:%patch -p1 使用前面定义的Patch补丁进行,-p1是忽略patch的第一层目录%Patch2 -p1 -b xxx.patch 打上指定的补丁,-b是指生成备份文件#将需要需要打包的文件从BUILD 文件夹中拷贝到BUILDROOT文件夹下。
◎补充一下
引用
%setup 不加任何选项,仅将软件包打开。
%setup -n newdir 将软件包解压在newdir目录。
%setup -c 解压缩之前先产生目录。
%setup -b num 将第num个source文件解压缩。
%setup -T 不使用default的解压缩操作。
%setup -T -b 0 将第0个源代码文件解压缩。
%setup -c -n newdir 指定目录名称newdir,并在此目录产生rpm套件。
%patch 最简单的补丁方式,自动指定patch level。
%patch 0 使用第0个补丁文件,相当于%patch ?p 0。
%patch -s 不显示打补丁时的信息。
%patch -T 将所有打补丁时产生的输出文件删除。
%configure #这个不是关键字,而是rpm定义的标准宏命令。意思是执行源代码的configure配置
在/usr/src/asianux/BUILD/%{name}-%{version}目录中进行 ,使用标准写法,会引用/usr/lib/rpm/marcros中定义的参数。
另一种不标准的写法是,可参考源码中的参数自定义,例如:
引用
CFLAGS="$RPM_OPT_FLAGS" CXXFLAGS="$RPM_OPT_FLAGS" ./configure --prefix=%{_prefix}
%build #开始构建包
在/usr/src/asianux/BUILD/%{name}-%{version}目录中进行make的工作 ,常见写法:
引用
make %{?_smp_mflags} OPTIMIZE="%{optflags}"
都是一些优化参数,定义在/usr/lib/rpm/marcros中
%install #开始把软件安装到虚拟的根目录中
在/usr/src/asianux/BUILD/%{name}-%{version}目录中进行make install的操作。这个很重要,因为如果这里的路径不对的话,则下面%file中寻找文件的时候就会失败。 常见内容有:
%makeinstall 这不是关键字,而是rpm定义的标准宏命令。也可以使用非标准写法:
引用
make DESTDIR=$RPM_BUILD_ROOT install
或
引用
make prefix=$RPM_BUILD_ROOT install
需要说明的是,这里的%install主要就是为了后面的%file服务的。所以,还可以使用常规的系统命令:
引用
install -d $RPM_BUILD_ROOT/
cp -a * $RPM_BUILD_ROOT/
%clean #清理临时文件
通常内容为:
引用
[ "$RPM_BUILD_ROOT" != "/" ] && rm -rf "$RPM_BUILD_ROOT"
rm -rf $RPM_BUILD_DIR/%{name}-%{version}
※注意区分$RPM_BUILD_ROOT和$RPM_BUILD_DIR:
$RPM_BUILD_ROOT是指开头定义的BuildRoot,而$RPM_BUILD_DIR通常就是指/usr/src/asianux/BUILD,其中,前面的才是%file需要的。
%pre #rpm安装前执行的脚本
%post #rpm安装后执行的脚本
%preun #rpm卸载前执行的脚本
%postun #rpm卸载后执行的脚本
%files #定义那些文件或目录会放入rpm中
这里会在虚拟根目录下进行,千万不要写绝对路径,而应用宏或变量表示相对路径。 如果描述为目录,表示目录中除%exclude外的所有文件。
%defattr (-,root,root) 指定包装文件的属性,分别是(mode,owner,group),-表示默认值,对文本文件是0644,可执行文件是0755
%exclude #列出不想打包到rpm中的文件
※小心,如果%exclude指定的文件不存在,也会出错的。
%changelog #变更日志
注:关于上述的spec详解参(chao)考(xi)了前辈的血汗之作 https://www.cnblogs.com/SQL888/p/5776442.html 膜拜!!!!
五、spec实例
下面是我在实战中编写的.spec , 上述中的大部分其实并没有用到 , 整体来讲比较简单,如果有错误的地方望大佬不吝赐教.
大概思路就是:将ELKF的四个rpm包整合为一个rpm包,并且覆盖一些初始配置文件,在卸载@postrun中卸载四个rpm包并且删除相关数据目录.
Summary: ELK(elasticsearch+logstash+kibana+filebeat) Server
Name: ELK
Version: 1.0.0
Release: 1
License: GPL
Packager: RPMBuild
Group: Applications/System
BuildRoot: /
Provides: src
Requires: /bin/sh /usr/bin/getent /usr/sbin/useradd /usr/sbin/userdel
AutoReqProv: no
%define _rpmfilename %%{NAME}-%%{VERSION}.%%{ARCH}.rpm
%description
Boog ELK Log analysis system.
%post #rpm安装后执行的脚本
echo "after rpm install(update)..."
install_elasticsearch(){
echo "########### begin installing elasticsearch ###########"
rm -f /var/lib/rpm/.rpm.lock
es=`rpm -qa | grep elasticsearch`
if [ `rpm -qa | grep elasticsearch |wc -l` -ne 0 ];then
echo -e "ERROR: elasticsearch has been installed on this server,the packet_list: $es"
else
# install begin
rpm -ivh /home/elk_install_temp/rpms/elasticsearch-6.1.1.rpm
# 设置elasticsearch java环境变量配置
sed -i "s%\#JAVA_HOME=%JAVA_HOME=$JAVA_HOME%g" /etc/sysconfig/elasticsearch
# 更改数据目录
cp -f /home/elk_install_temp/template/elasticsearch.yml /etc/elasticsearch/
chown -R elasticsearch:elasticsearch /etc/elasticsearch/elasticsearch.yml
chown -R elasticsearch:elasticsearch /data/log
chown -R elasticsearch:elasticsearch /data/lib
#设置开机自启动
/sbin/chkconfig --add elasticsearch
fi
echo "Run 'service elasticsearch start' to start the elasticsearch service"
echo "###########If the elasticsearch startup failed,Please read '/etc/elasticsearch/remark.txt' for help!!###########"
}
install_kibana(){
echo "############## begin installing kibana ###############"
kb=`rpm -qa | grep kibana`
if [ `rpm -qa | grep kibana |wc -l` -ne 0 ];then
echo -e "ERROR: kibana has been installed on this server,the packet_list: $kb"
else
# install begin
rpm -ivh /home/elk_install_temp/rpms/kibana-6.1.1-x86_64.rpm
cp -f /home/elk_install_temp/template/kibana.yml /etc/kibana/
#设置开机自启动
/sbin/chkconfig --add kibana
fi
echo "Run 'service kibana start' to start the kibana service"
}
install_filebeat(){
echo "############# begin installing filebeat ##############"
fb=`rpm -qa | grep filebeat`
if [ `rpm -qa | grep filebeat |wc -l` -ne 0 ];then
echo -e "ERROR: filebeat has been installed on this server,the packet_list: $fb"
else
# install begin
rpm -ivh /home/elk_install_temp/rpms/filebeat-6.1.1-x86_64.rpm
cp -f /home/elk_install_temp/template/filebeat.yml /etc/filebeat/
#设置开机自启动
/sbin/chkconfig --add filebeat
fi
echo "Run 'service filebeat start' to start the filebeat service"
}
install_logstash(){
echo "############## begin installing logstash #############"
lt=`rpm -qa | grep logstash`
if [ `rpm -qa | grep logstash |wc -l` -ne 0 ];then
echo -e "ERROR: logstash has been installed on this server,the packet_list: $lt"
else
# install begin
rpm -ivh /home/elk_install_temp/rpms/logstash-6.1.1.rpm
#覆盖配置文件
cp -f /home/elk_install_temp/template/logstash-simple.conf /etc/logstash/conf.d/
#生成logstash启动脚本
/usr/share/logstash/bin/system-install /etc/logstash/startup.options sysv
#设置开机自启动
/sbin/chkconfig --add logstash
fi
#服务启动
/etc/init.d/logstash start
initctl stop logstash
echo "Run 'initctl start logstash' to start the logstash service"
}
#执行安装
install_elasticsearch
install_kibana
install_filebeat
install_logstash
################### remove elk install temp ####################
rm -rf /home/elk_install_temp
rm -rf /var/elk_install_temp
%clean
rm -rf %{BuildRoot}
%preun
%postun #rpm安装后执行的脚本
if [ $1 = 0 ]; then
rm -f /var/lib/rpm/.rpm.lock
##################### begin uninstall elasticsearch ######################
echo "begin uninstall elk"
es=`rpm -qa elasticsearch`
if [ $es ];then
service elasticsearch stop
rpm -e $es
rm -rf /data/lib/elasticsearch
rm -rf /data/log/elasticsearch
rm -rf /usr/share/elasticsearch
fi
echo 'elasticsearch has been uninstall!'
######################## begin uninstall logstash ########################
ls=`rpm -qa logstash`
if [ $ls ];then
echo $ls
/etc/init.d/logstash stop
#防止logstash 未被成功关闭导致用户无法删除以至于logstash卸载失败
lsid=`ps aux | grep logstash | grep -v grep| awk '{print $2}'`
if [ ! $lsid ]; then
echo "logstash is stop!"
else
kill -9 $lsid
echo 'logstash is about to be closed.....'
fi
rpm -e $ls
rm -rf /etc/init.d/logstash /etc/rc.d/init.d/logstash /etc/logstash /etc/default/logstash
rm -rf /var/log/logstash /var/log/logstash-std* /var/lib/logstash
rm -rf /usr/share/logstash
fi
echo 'logstash has been uninstall!'
######################### begin uninstall filebeat #######################
fb=`rpm -qa filebeat`
if [ $fb ];then
echo $fb
service filebeat stop
rpm -e $fb
fi
echo 'filebeat has been uninstall!'
######################### begin uninstall kibana #########################
ki=`rpm -qa kibana`
if [ $ki ];then
echo $ki
service kibana stop
rpm -e $ki
fi
echo 'kibana has been uninstall!'
###################### remove elk install temp ###########################
#rm -rf /home/elk_install_temp
#rm -rf /var/elk_install_temp
fi
%pre
echo $JAVA_HOME
if [ ! $JAVA_HOME ];then
echo 'ERROR:请先安装java并配置java相关环境'
exit 0
fi
mkdir -p /data/lib/elasticsearch /data/log/elasticsearch
%files #定义那些文件或目录会放入rpm中(这里是BUILDOROOT/name-version/下的源码和配置文件)
/home/elk_install_temp/.elk-release
/home/elk_install_temp/rpms/*
/home/elk_install_temp/template/*
/etc/elasticsearch/remark.txt
%defattr(-,root,root)