1. 程式人生 > >linux之使用rpmbuild打rpm包

linux之使用rpmbuild打rpm包

login 就會 fpm ftw 安裝出錯 紅帽 ref 超過 說明

linux之使用rpmbuild打rpm包

前言:

已從事linux運維工作數年,感覺自己還是個小菜鳥,沒有大神那麽的鉆研的精神。只是單純熱愛,喜歡對著黑色的屏幕敲擊命令,喜歡這種感覺。為什麽要做RPM包呢?因為之前公司使用的是開源軟件環境,nginx,tomcat,java,等等等等,安裝時流程:編譯->標準化目錄->標準化參數->部署代碼。這樣純手操作的話需要一套部署文檔,當然根據個人理解和個人功力的不同,部署出來效果都千奇百怪。 所以通過一個星期的學習,大概掌握了寫spec,並且總結了自己的方法,雖然比較low,但是目前還算是有效。

原理:

其實rpm是針對centos和redhat,這兩種系統服務器份額占有率比較高,目前線上最常用的是 cetnos(redhat)6-x86_64和7,紅帽公司為了解決編譯繁瑣目錄不規範的問題才使用的rpm方案,說白了就是把文件封裝起來,類似壓縮,並將執行的腳本和依賴封裝到rpm中, 加上yum源的機制,大幅縮減安裝軟件的難度和速度。

記住一點就好了,"一切皆文件!"

制作原理:

這裏有5個文件夾,按照做菜原理可以理解為

SPEC:核心配置文件,菜譜

SOURCES:源文件存放,原料

BUILD,/var/tmp/foo-root/:生成編譯文件,模擬系統環境,炒鍋

RPMS:封裝完成的rpm包 ,裝盤

技術分享

規劃:

其實作為運維都知道,解決問題不算本事,能避免問題,把復雜的事做的簡單才是水平。你若想制作屬於自己的RPM,而且在本公司推下去一定回遵循以下幾點:

1、標準化, 軟件安裝目錄,輸出文件統一路徑,配置文件規範,你不可能軟件東一個,西一個,日誌輸出的到處都是吧,萬一哪天磁盤空間滿了,還得擔責任是不?

2、完整,盡量使功能完整,但不可把程序做的太死 比如一套Tomcat代碼,我就分成了3個包,環境包、代碼包、java包。

以下是lnmp架構的規劃目錄:

技術分享

幹貨:

重點就是SPEC的編輯,這裏我用了不同的方法,沒有使用rpmbuild的“鍋”,因為安裝軟件也只是生成文件罷了,只要自己在測試環境可以編譯安裝成功那為什麽還要扔給”鍋”再炒一下,筆者寫過多個spec也查過很多資料,在安裝某些文件特別多的軟件時,rpmbuild就會讀取失敗 而且還不報錯,所以自己判斷 它真的是一個”鍋”,不能背!

所以很佩服紅帽官方的大神,不知道他們怎麽實現的,也不想為此投入太多精力, 其實完全可以先在自己的測試環境把軟件裝好,打包成tar.gz格式,再加上一些軟件的配置文件 打包到rpm內,在安裝端解壓釋放執行,就完成了!

實例:

測試環境:

centos6_x86-64

php5.6

163.repo

1、rpmbuild打包環境準備

yum install -y rpm-build rpmdevtools redhat-rpm-config
#安裝打包環境
useradd dabao
#創建工作用戶,不建議使用root因為root有無限大權限,封包時會可能會影響自身系統
vim .rpmmacros
%_topdir /home/dabao/rpmbuild
#設置%_topdir宏,這個宏是定義打包目錄的路徑,默認是在/usr/src/redhat
mkdir -p rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
#創建工作目錄

2、在測試機中安裝php

yum install zlib-devel libxml2-devel libjpeg-devel libjpeg-turbo-devel freetype-devel libpng-devel gd-devel libcurl-devel libxslt-devel libxslt-devel libmcrypt-devel mhash mcrypt openssl-devel bzip2-devel
#php依賴要記下一會要寫到spec中

mkdir -p /data/app/
tar xf libiconv-1.14.tar.gz
cd libiconv-1.14
./configure --prefix=/data/app/libiconv11
make && make install
#安裝
./configure --prefix=/data/app/php53 --with-config-file-path=/data/app/php53/etc --with-config-file-scan-dir=/data/app/php53/etc/php.d --with-mysql=mysqlnd --with-iconv-dir=/data/app/libiconv11 --with-freetype-dir --with-jpeg-dir --with-png-dir --with-zlib --with-bz2 --with-libxml-dir=/usr --enable-xml --disable-rpath --enable-safe-mode --enable-bcmath --enable-shmop --enable-sysvsem --enable-inline-optimization --with-curl --with-curlwrappers --enable-mbregex --enable-fpm --enable-mbstring --with-mcrypt --with-gd --enable-gd-native-ttf --with-openssl --with-mhash --enable-pcntl --enable-sockets --with-xmlrpc --enable-zip --enable-soap --enable-short-tags --enable-zend-multibyte --enable-static --with-xsl --with-fpm-user=www --with-fpm-group=www --enable-ftp
 
make
make install

useradd www -s /sbin/nologin -M
mkdir -p /data/logs/
#創建php用戶及log目錄

  軟件調優,可根據環境調試:

#配置文件
cp /root/tools/php-5.5.29/php.ini-production /etc/php.ini 
sed -i ‘910s#;date.timezone = #date.timezone = "Asia/Shanghai"#g‘ /etc/php.ini
#901行修改 date.timezone = "Asia/Shanghai"
cp /data/app/php55/etc/php-fpm.conf.default /data/app/php55/etc/php-fpm.conf

sed -i ‘32s#;error_log = log/php-fpm.log#error_log = /data/logs/php-fpm56.log#g‘ /data/app/php56/etc/php-fpm.conf
sed -i ‘50s#;log_level = notice#log_level = error#g‘ /data/app/php56/etc/php-fpm.conf
sed -i ‘458s#;rlimit_files = 1024#rlimit_files = 32768#g‘ /data/app/php56/etc/php-fpm.conf
sed -i ‘164s#listen = 127.0.0.1:9000#listen = 127.0.0.1:9056#g‘ /data/app/php56/etc/php-fpm.conf
sed -i ‘235s#pm.max_children = 5#pm.max_children = 1024#g‘ /data/app/php56/etc/php-fpm.conf
sed -i ‘240s#pm.start_servers = 2#pm.start_servers = 16#g‘ /data/app/php56/etc/php-fpm.conf
sed -i ‘245s#pm.min_spare_servers = 1#pm.min_spare_servers = 5#g‘ /data/app/php56/etc/php-fpm.conf
sed -i ‘250s#pm.max_spare_servers = 3#pm.max_spare_servers = 20#g‘ /data/app/php56/etc/php-fpm.conf
sed -i ‘255s#;pm.process_idle_timeout = 10s;#pm.process_idle_timeout = 15s;#g‘ /data/app/php56/etc/php-fpm.conf
sed -i ‘261s#;pm.max_requests = 500#pm.max_requests = 2048#g‘ /data/app/php56/etc/php-fpm.conf
sed -i ‘441s#;slowlog = log/$pool.log.slow#slowlog = /data/logs/$pool56.log.slow#g‘ /data/app/php56/etc/php-fpm.conf

#啟動文件
cat /etc/init.d/php-fpm56
#! /bin/sh
### BEGIN INIT INFO
# Provides:          php-fpm
# Required-Start:    $remote_fs $network
# Required-Stop:     $remote_fs $network
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: starts php-fpm
# Description:       starts the PHP FastCGI Process Manager daemon
### END INIT INFO
prefix=/data/app/php56
exec_prefix=${prefix}
php_fpm_BIN=${exec_prefix}/sbin/php-fpm
php_fpm_CONF=${prefix}/etc/php-fpm.conf
php_fpm_PID=${prefix}/var/run/php-fpm.pid
php_opts="--fpm-config $php_fpm_CONF --pid $php_fpm_PID"
wait_for_pid () {
        try=0
        while test $try -lt 35 ; do
                case "$1" in
                        ‘created‘)
                        if [ -f "$2" ] ; then
                                try=‘‘
                                break
                        fi
                        ;;
                        ‘removed‘)
                        if [ ! -f "$2" ] ; then
                                try=‘‘
                                break
                        fi
                        ;;
                esac
                echo -n .
                try=`expr $try + 1`
                sleep 1
        done
}
case "$1" in
        start)
                echo -n "Starting php-fpm "
                $php_fpm_BIN --daemonize $php_opts
                if [ "$?" != 0 ] ; then
                        echo " failed"
                        exit 1
                fi
                wait_for_pid created $php_fpm_PID
                if [ -n "$try" ] ; then
                        echo " failed"
                        exit 1
                else
                        echo " done"
                fi
        ;;
        stop)
                echo -n "Gracefully shutting down php-fpm "
                if [ ! -r $php_fpm_PID ] ; then
                        echo "warning, no pid file found - php-fpm is not running ?"
                        exit 1
                fi
                kill -QUIT `cat $php_fpm_PID`
                wait_for_pid removed $php_fpm_PID
                if [ -n "$try" ] ; then
                        echo " failed. Use force-quit"
                        exit 1
                else
                        echo " done"
                fi
        ;;
        status)
                if [ ! -r $php_fpm_PID ] ; then
                        echo "php-fpm is stopped"
                        exit 0
                fi
                PID=`cat $php_fpm_PID`
                if ps -p $PID | grep -q $PID; then
                        echo "php-fpm (pid $PID) is running..."
                else
                        echo "php-fpm dead but pid file exists"
                fi
        ;;
        force-quit)
                echo -n "Terminating php-fpm "
                if [ ! -r $php_fpm_PID ] ; then
                        echo "warning, no pid file found - php-fpm is not running ?"
                        exit 1
                fi
                kill -TERM `cat $php_fpm_PID`
                wait_for_pid removed $php_fpm_PID
                if [ -n "$try" ] ; then
                        echo " failed"
                        exit 1
                else
                        echo " done"
                fi
        ;;
        restart)
                $0 stop
                $0 start
        ;;
        reload)
                echo -n "Reload service php-fpm "
                if [ ! -r $php_fpm_PID ] ; then
                        echo "warning, no pid file found - php-fpm is not running ?"
                        exit 1
                fi
                kill -USR2 `cat $php_fpm_PID`
                echo " done"
        ;;
        *)
                echo "Usage: $0 {start|stop|force-quit|restart|reload|status}"
                exit 1
        ;;
esac

  完成之後你就可以啟動下你的php試試了,啟動測試成功後,請關閉服務正式開始我們打RPM包

2、開始制作rpm包

cd /data/app
tar zcvf php56.tar.gz php56
tar zcvf libiconv11.tar.gz libiconv11
cp php56.tar.gz /home/dabao/rpmbuild/SOURCES
cp libiconv11.tar.gz /home/dabao/rpmbuild/SOURCES
cp /etc/init.d/php-fpm56 /home/dabao/rpmbuild/SOURCES
#把原料準備好

  編寫spec文件

vim /home/dabao/rpmbuid/SPECS/php56.spec
%define name t-php
%define version 5.6.30
%define _prefile /app

Summary:        t-php
Name:           %{name}
Version:        %{version}
Release:        2
Group:          System Environment/Daemons
License:        GPL
URL:            www.php.org

Packager:       tajZhang
Vendor:         tajZhang

Source0:        php56.tar.gz
Source1:        php-fpm56
Source2:        libiconv11.tar.gz
BuildRoot:      %{_tmppath}/%{name}-%{version}-root

#BuildRequires: 
Requires:       zlib-devel libxml2-devel libjpeg-devel libjpeg-turbo-devel freetype-devel libpng-devel gd-devel libcurl-devel libxslt-devel libxslt-devel libmcrypt-devel mhash mcrypt open
ssl-devel bzip2-devel

%description
php5.6.30 copy install.
basedir /data/app/php56 /data/app/php56/etc

%prep
#%setup -q


%build
#mkdir -p %{buildroot}/usr/java/jdk1.6.0_22
#cp -r * /usr/java/jdk1.6.0_22

%install
rm -rf %{buildroot}
mkdir -p %{buildroot}/data/app
mkdir -p %{buildroot}/etc/init.d
cp -i %{SOURCE0} %{buildroot}/data/app
cp -i %{SOURCE2} %{buildroot}/data/app
cp -i %{SOURCE1} %{buildroot}/etc/init.d
#cp -i %{SOURCE1} %{buildroot}/etc/init.d/ && chmod +x %{buildroot}/etc/init.d/mysqld
#cp -i %{SOURCE2} %{buildroot}/etc/

%pre
#if [ $1 == 1 ];then
#fi
%post
if [ $1 == 1 ];then
tar xf /data/app/php56.tar.gz -C /data/app/
tar xf /data/app/libiconv11.tar.gz -C /data/app/
rm -f /data/app/php56.tar.gz /data/app/libiconv11.tar.gz
mkdir -p /data/logs
useradd www -s /sbin/nologin -M
chmod +x /etc/init.d/php-fpm56
/etc/init.d/php-fpm56 start
chkconfig php-fpm56 on
echo "install over"
fi
%preun
if [ $1 == 0 ];then
/etc/init.d/php-fpm56 stop
rm -rf /data/app/php56
rm -f /etc/init.d/php-fpm56
echo "remove over"
fi
%postun
%clean
rm -rf "%{buildroot}"
rm -rf %_topdir/BUILD/%{name}-%{version}

%files
%defattr (-,root,root,0755)
/etc/init.d/php-fpm56
/data/app/php56.tar.gz
/data/app/libiconv11.tar.gz

  執行打包命令

rpmbuild -ba php56.spec
#到SPECS目錄下執行,如果沒有報錯會在RPMS/x86_64/目錄下生成你打好的包
cd /home/dabao/rpmbuild/RPMS/x86_64/
   t-php-5.6.30-2.x86_64.rpm

  到此你的第一個rpm包制作完成,拿到測試機上裝下試試吧!

分析:

什麽?稀裏糊塗的根本不懂SPEC裏寫的什麽,其實它只是個模板,摘錄一段各位看了一目了然:

----------------------------------分割線---------------------------------------------------------------------------------

SPEC配置文件講解 #/** 定義宏段 **/ %define name nginx <==定義name宏偉nginx,後面可以調用這個宏%{name} %define version 1.2.4 <==定義version宏為1.2.4 %define _prefix /application/nginx #/** 簡介段 **/ Summary: information <==軟件包的概要信息,不要超過50個字符 Name: %{name} <==軟件包的名稱,調用上面的宏 Version: %{version} <==軟件包的版本,調用上面的宏 Release: 1 <==軟件包發布序列號,表明第幾次打包 License: GPL <==軟件授權方式,通常是GPL Group: System Environment/Daemons <==軟件包分組,屬於哪個組包建議使用標準分組,查看/usr/share/doc/<wiz_tmp_highlight_tag>rpm-4.4.2.3/GROUPS URL: http://nginx.org/ <==源代碼軟件包的官方地址或源碼包下載地址 Packager: coral <[email protected]> <==軟件包的作者及聯系方式 Vendor: coral <==軟件包開發者的名字 Source0: %{name}-%{version}.tar.gz <==源代碼軟件包的名字,如nginx-1.2.4-tar.gz Source1: nginx.init <==如果需要需要安裝多個源碼軟件包,可指定多個Source 比如Source0 Sourcel Source100等,數字可以不連續,後面使用%{Source0}來調用 Patch1: httpd-2.2.22-pcre830.patch <==指定補丁文件 Patch2: httpd-2.2.21-mod_proxy-change-state.patch BuildRoot: %{_tmppath}/%{name}-%{version}-root <==這是make install 使用的虛擬目錄,安裝後打包,就將該目錄下打,通常是/var/tmp/軟件名-版本號-發布序列號,該虛擬目錄是自動創建的 說明:引用buildRoot這個宏時,可以寫成$<wiz_tmp_highlight_tag>RPM_BUILD_ROOT,也可以鞋廠%{buildroot}方式來引用 BuildRequires: gcc,make <==制作<wiz_tmp_highlight_tag>RPM包過程所依賴的軟件包,多個包依賴用逗號分隔 Requires: pcre,pcre-devel,openssl,openssl-devel,zlib,zlib-devel,chkconfig <==安裝過程中所依賴的軟件包 提示:可以使用>=或<=表示大於或小於某一特定版本,如:libpng-devel >= 1.0.20 zlib不同的軟件名使用空格分塊 提示:還有PreReq、Requires(pre)、Requires(post)、Requires(preun)、Requires(postun)、BuildRequires等都是針對不同階段的依賴包指定 %description <==軟件包詳細描述信息,一行不要超過50個字符,回車換行,尅使用多行 This is an open-source software,bulk distribution ... - 強制換行 #/** 準備段 **/ %prep <==安裝前的準備工作,一般用於解壓源碼包 %setup -q <==%setup是宏命令,可自動完成解包工作 說明:預處理一般是將源碼包解壓,有兩種情況:一就是同事編譯多個源碼包,二就是源碼的tar包的名稱於解壓出來的目錄不一致,此時需要-n參數指定一下,如:%setup -q -n %{Source0},有時候解壓出來的tar.gz與包名不符合,這時候需要指定-n參數,如%setup -q -n nagios,後面不加版本號 %path1 <==打補丁 #/** 編譯段 **/ %build <==源碼編譯,如: ./configure && make 命令 ./confingure \ --prefix=%{_prefix} \ --user=nginx \ --group=nginx \ --with-http_stub_status_module \ --with-http_ssl_module \ --with-pcre make #make %{?_smp_mflags} <==使用多核CPU加速編譯過程,相當於命令行中的make -j #/** 安裝段 **/ %install <==源碼安裝,如:make install 命令 rm -rf %{buildroot} <==在此處設置刪除buildroot虛擬根目錄是為方式以前打包留下的文件,防止安裝出錯,才刪除該目錄 make install DESTDIR="%{buildroot}" <==指定編譯安裝的路徑到buildroot,而不是安裝到系統中 %{__install} -p -d -m 0755 %{buildroot}/var/log/nginx <==在虛擬根目錄下創建目錄,並授予權限 %{__install} -p -D -m 0755 %{SOURCE1} %{buildroot}/etc/init.d/nginx <==安裝啟動腳本到init.d目錄 註意:無論上面定義的SOURCE1是不是大寫,這裏調用必須為大寫 說明:%prep %build %install段,除了可以執行<wiz_tmp_highlight_tag>rpm所定義的宏命令(以%開頭),還可以換行執行shell命令,比如直接寫tar -zxf xxx.tar.gz命令,而不使用%setup -q宏 #/** 腳本段 **/ %pre <==<wiz_tmp_highlight_tag>rpm安裝前執行的腳本,比如創建用戶,設置變量等等操作 if [ $1 == 1 ];then /usr/sbin/groupadd nginx 2>/dev/null /usr/sbin/useradd -g nginx -s /sbin/nologin -M nginx 2>/dev/null fi 說明:$1等於1就是安裝 %post <==<wiz_tmp_highlight_tag>rpm安裝完成後執行的腳本,比如加載ldconfig函數庫,加入開機自動啟動等等 if [ $1 == 1 ];then echo "/usr/local/lib" >>/etc/ld.so.conf.d/nginx.conf <==如果安裝 lib庫到/usr/local/lib中,需要配置該段 /sbin/ldconfig 2>/dev/null chkconfig --add %{name} fi 說明 :$1等於1就是安裝 %preun <==<wiz_tmp_highlight_tag>rpm 卸載前執行的腳本 if [ $1 ==0 ];then /sbin/service %{name} stop >/dev/null 2>&1 /sbin/chkconfig -del %{name} fi 說明: $1等於0就是卸載 %postun <==<wiz_tmp_highlight_tag>rpm卸載完成後執行的腳本 說明%preun在升級的時候會執行,%postun在升級<wiz_tmp_highlight_tag>rpm包的時候不會執行 <wiz_tmp_highlight_tag>rpm還提供了一種信號機制:不同的操作會返回不同的信息,並放到默認變量$1中 信號 說明 0 卸載 1 安裝 2 升級 #/** 清理段 **/ %clean <==清理臨時文件,通常為如下 rm -rf "%{buildroot}" <==刪除虛擬目錄 rm -rf %_topdir/BUILD/%{name}-%{version} <==將解壓的源碼包刪除掉 #/** 文件段 **/ %file <==定義哪些文件或目錄放入到<wiz_tmp_highlight_tag>rpm中 /usr/sbin/nginx <==指定包含的文件目錄 /etc/nginx/ <==指定包含的目錄(文件後面有個/表示目錄,目錄裏的所有文件) %dir /var/run/nginx <==指定包含的文件,如果前面是%dir ,那麽該nginx是一個空目錄 說明:用於定義軟件包所包含的文件,分為三類:說明文檔(doc),配置文件(conf),一級執行程序(sbin) 註意:%files這裏會在虛擬根目錄下進行,千萬不要寫絕對路徑,應該使用宏或變量表示相對路徑 %doc LICENSE CHANGES README <==要打包的文檔文件,如果不知道路徑,默認是/usr/share下 %defattr (-,root,root,0755) <==定義默認權限 %{_prefix} <==調用上面的定義宏,使用%defattr對/application/nginx目錄設置安裝文件的屬性,第一個“-”表示默認文件權限(文件0644,目錄0755),第二個"root"表示屬主,第三個“root”表示屬組,第四個“0755”設置的權限 說明:%defattr和%attr宏作用基本一樣,%defattr可以對目錄進行遞歸授權,%attr針對單個文件 它倆的區別參考資料:http://stackoverflow.com/questions/6952384/what-the-defattr-means-in-<wiz_tmp_highlight_tag>rpm-spec-files %config(noreplace) %{_prefix}/conf/nginx.conf <==nginx.conf配置文件放置到/application/nginx/conf目錄下,config的文件為配置文件,noreplace表示升級<wiz_tmp_highlight_tag>rpm包的時候不替換該文件 %config(noreplace) %{_prefix}/conf/fastcgi.conf <==fastcgi.conf 配置文件放置到/application/nginx/conf 目錄下 %config(noreplace) %{_prefix}/conf/fastcgi_params %attr(0755,root,root) /etc.init.d/nginx <==對單個文件授權,權限為"-"表示保留原有屬性 註意:如果%exclude指定的文件不存在,也會報錯 #/** 改變日誌段 **/ %changelog <==把<wiz_tmp_highlight_tag>rpm包軟件的每次修改記錄到這裏,保存到發布的<wiz_tmp_highlight_tag>rpm包中一般減號開始,以便查詢 * Wed Apr 11 2012 coral <919953500> -1.2.4-1 <==以*開頭,什麽時間改的,什麽人改的 - Initial version <==以-開頭,幹了什麽事(初始版本) 註意:此地方用中文會報錯 特別註意:%install 宏使用的是絕對路徑,而%file部分使用相對路徑 ----------------------------------分割線---------------------------------------------------------------------------------

總結與啟發:

各位看到php的spec根本就沒有經過解壓與編譯,而是直接將tar.gz復制到系統中,執行安裝完成後命令。

執行結束後為什麽執行一次echo呢?因為這樣才能讓if的$?返回0,如果最後一條不是成功執行的命令,rpm就會安裝報錯。

rpm機制是在系統子bsah下執行,不是當前bash,設置系統環境變量的重新登錄才生效。

%file段至關重要,因為這裏記錄了你要裝盤的文件。

通過rpm的學習,覺得它可以做很多事,可以讓小弟不在為安裝文檔抓頭,而且可以配合yum機制定制自己的軟件倉庫,實現快速部署。甚至可以用rpm做代碼包版本控制,當足夠了解自己公司的業務也可以將程序打在一套軟件組內,這樣是不是更像docker呢?

linux之使用rpmbuild打rpm包