【干貨】一次早期自動化構建的搭建過程


這是老王07年進入騰訊接手的第一個項目---自動化構建AutoBuild(06年就已經在上線運行),當年還不知道有Hudson,以及后來更名的Jenkins。做完這個項目之后再去反思傳統的軟件工程就有了很多新的感悟,只有從根源上提出解決方案,並配合最佳的實踐才能解決軟件交付的質量問題。

也因為騰訊web端項目基本上都是使用的CGI,所以花了不少時間寫整套的自動化編譯腳本(全部是perl寫的),當然里面對研發提出了編譯文件Makefile的規范(后面有原理)。

在后續的版本演進中,把自動化測試、代碼安全掃描、持續發布都加入了整體過程,真正的做到全過程持續交付,直到今天和客戶去講持續交付整體過程的時候,很多實踐和感悟都是來源於此。

*****建議在你們的項目中實踐持續集成,不要以為這不是運維的職責****

以下過程是我們早期完全自研構建持續集成的過程,僅供參考!

1.    編譯環境的搭建
1.1.   整體框圖


注:ARS是騰訊的Auto Release System,早期我也是作為運維主要需求方參與這個平台的構建和推廣,直到所有的業務頁面端發布都接入了這一平台。持續部署的過程也就真正成為現實。
說明:
1編譯機器支持每天自動編譯,以及手工觸發編譯兩種構建方式.
1.2.   SVN Server端的配置
每加入一個工程,需要找PM給自動化編譯用戶isd_webadmin授權只讀訪問該工程的權限。具體的申請方法:告訴對方工程和用戶即可。
1.3.   公共代碼配置
/data/auto_build/           // 主目錄
|-- bin                   // 公共程序目錄
|   |-- svntools.pl            // 拉取svn服務器中代碼文件,獲取最后更新信息的工具,編譯
|   |-- confgen.pl           // 根據qzone項目源碼根目錄中的makfile文件,生成構建腳本構造文件(make.conf)的工具
|   |-- mkgen.pl            // 根據構建腳本構造文件(make.conf)生成全構建腳本build.sh的工具,編譯環境的關鍵腳本
|   |-- postmessage.pl        // 發送郵件的工具(詳見后邊說明)
|   |-- readlog.pl            // 讀取編譯過程中的日志文件,生成編譯結果報告buildres.xml的工具,關鍵腳本
|   `-- writemail.pl          // 根據編譯結果報告build.sh生成通知郵件的工具
|-- config                   // 項目工程配置目錄
|   |-- abs_profile.conf       // 所有工程的配置
`-- mbox                    // 存放每天所有工程編譯結果的匯總郵件
 
1.4.   編譯機的配置
編譯機的這邊需要的軟件有:
l  Apache (版本沒有特殊要求) + PHP模塊的支持
l  PHP 4.4.2 (或者高版本) + DOM + ICONV
l  PERL 5.8 (或者高版本) + DOM + ENCODE + HASHINI
建議使用官方源碼包編譯安裝,編譯順序和選項請參考
 
編譯環境的目錄結構如下,我們以/data/項目_build做為編譯環境的主目錄,實際部署中可以修改腳本中的變量設置改變這個目錄,只要相應的分區空間足夠大,可以支持整個項目的全編譯即可.
 
/data/qzone_build/           // 主目錄
|-- admin                   // 編譯管理目錄(詳見后邊說明)
|   |-- bin                  // 編譯控制腳本的存放目錄
|   |-- cgi-bin               // qzone.build.isd.com 的cgi程序目錄
|   |-- htdocs                //qzone.build.isd.com 的頁面文件目錄
|-- source                   // 項目代碼,編譯結果的實際存放位置
|   |-- qzone_20060829       // 這些以日期作為后綴的子目錄,存放着相應日期參加日構建的源碼和編譯結果
|   `-- qzone_20060831       // 可以根據需要保留近幾天的歷史結果,太早的通過簡單腳本刪除或者打包備份
`-- temp                    // 存放一些臨時文件或者動態目錄
    |-- mbox                // 發送編譯結果通知郵件的信箱(詳見后邊說明)
    `-- src -> /data/qzone_build/source/qzone_20060831  // 一個到當前代碼存放目錄的軟連接, svntools默認會向這里
                                                 // 更新最新的代碼 (詳見后邊說明).
 
admin目錄下的文件有:
/data/qzone_build/admin/
|-- bin
|   |-- autobuild.sh         // 自動編譯的總控制腳本,可以直接寫到crontab中定時自動運行
|   |--buildall.sh           // 完整的一次編譯過程的控制腳本, 不包含更新代碼,發送郵件的過程
|   |-- buildres.xsl          // buildres.xml需要的xsl風格表單(詳見后邊說明)
|   |-- svntools -> svntools.pl   // 為方便使用做的一個軟連接
|   |-- svntools.conf          // svntools.pl的配制文件,它應該始終和svntools.pl放在同一個目錄下
|   |-- svntools.pl            // 拉取svn服務器中代碼文件,獲取最后更新信息的工具,編譯
|   |                      // 環境的關鍵控制腳本(詳見后邊說明)
|   |-- confgen.pl           // 根據qzone項目源碼根目錄中的makfile文件,生成構建腳本構造文件(make.conf)的工具
|   |-- crlf                 // 將單個文件中每行的結尾標志字符\n(UNIX習慣),替換為\r \n(WINDOWS習慣)的工具
|   |-- crlf.c                // crlf工具的源代碼
|   |-- make.conf.def        // 構建腳本構造文件(make.conf)的缺省設置文件,供confgengen.pl參考使用
|   |-- message.conf         // postmessages.pl的配制文件,它應該始終和postmessages.pl放在同一個目錄下
|   |-- mkgen.pl            // 根據構建腳本構造文件(make.conf)生成全構建腳本build.sh的工具,編譯環境的關鍵腳本
|   |-- postmessage.pl        // 發送郵件的工具(詳見后邊說明)
|   |-- readlog.pl            // 讀取編譯過程中的日志文件,生成編譯結果報告buildres.xml的工具,關鍵腳本
|   |-- setroot.sh            // 設置文件更新/編譯目錄連接的工具,關鍵腳本(詳見后邊說明)
|   |-- u2wlog.sh            // 批量轉換文件換行字符 \nà \r \n的工具 (內部循環調用crlf程序)
|   `-- writemail.pl          // 根據編譯結果報告build.sh生成通知郵件的工具
|-- cgi-bin
`-- htdocs
   |-- buildres.xsl ->/data/qzone_build/admin/bin/buildres.xsl  //xsl表單的軟連接,將原始文件放在bin中是為方便編輯
   |-- index.php             // build.qzone.isd.com的入口頁面
   |-- mainlist.php           // 生成目錄列表頁面的工具腳本
   |--slist.php              // 文件列表頁面
   `--test.php              // php測試頁面 (非必需)
 
需要的環境變量:
PATH_QZONE_PRJ="/usr/local/qzone_v3.0"
export PATH_QZONE_PRJ
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/c4a/bin:/usr/lib
 
PATH_SVNTOOLS="/data/qzone_build/admin/bin"
export PATH=$PATH:$PATH_SVNTOOLS
 
PATH_QZONE_PRJ是qzone編譯時必需的環境變量, PATH_SVNTOOLS加入路徑中是為了使用方便(非必要).
 
整個編譯環境中各個工具都可以普通用戶執行,比如user_*,但應該保證相應的源碼目錄有足夠的讀寫權限.
 
1.5.   編譯過程


上邊是編譯的總體流程圖,圖中黃色圓形標注是編譯過程的順序,依次說明如下(各個控制腳本都放在admin/bin下):
1.      通過setroot.sh在source目錄下選取或建立一個日構建的代碼存放目錄,比如qzone_20060831,並且將它軟連接到/usr/local/qzone_v3.0(編譯代碼的目錄),/data/qzone_build/temp/src(svntools.pl更新代碼的目錄). (注:將代碼保存路徑,編譯目錄,更新目錄分開是為了支持歷史編譯結果備份和靈活更新)
2.      使用svntools.pl拉取遠程svn服務器上的項目代碼,更新到本地的/data/qzone_build/temp/src目錄. svntools.pl更新文件的時候會將文件的最后更新信息(時間,更新人,CC事件)寫到它所在的的目錄下的ccversion.xml中
3.      自動編譯系統一般是使用編譯配置文件make.conf (位於源代碼根目錄)生成全編譯腳本,但是如果項目代碼根目錄中有整體makefile文件,則可以使用confgen.pl讀取這個makefile生成編譯配制文件make.conf
4.      使用mkgen.pl讀取源代碼根目錄下邊的編譯配置文件make.conf (這個文件中定義了要參加編譯的子目錄,以及這些目錄間的依賴關系,即編譯順序,它可以通過makefile生成,也可以手工編寫),在源代碼根目錄下生成全編譯腳本build.sh
5.      上一步生成的build.sh是個可執行的bash腳本,直接運行就可以編譯整個qzone代碼,編譯過程中的提示信息會被寫入每個參加編譯的子目錄下,保存為build_***.log名字的文件,其中***代表build.sh的時間戳(詳見后邊說明)
6.      編譯結束后,使用readlog.pl讀取參加編譯的各個子目錄中的log文件,生成一份報告文件buildres.xml,記錄編譯結果(出錯/異常/警告信息等)
7.      編譯機同時兼做編譯結果的發布WEB站點,允許大家查看參加編譯的代碼目錄和各個log文件,因為UNIX環境下文本文件的換行符號\n與windows環境下的\r\n不一致,所以這些log在windows下查看時格式比較亂,使用u2wlog.sh可以對各個log文件做UNIXàWINDOWS的換行符替換
8.      writemail.pl可以讀取編譯結果報告文件builres.xml中的關鍵信息,生成一封發給qzone開發組的通知郵件build_***.mail(其中***是build.sh的時間戳),郵件會放在約定好的發件箱/data/qzone_build/temp/mbox中
9.      最后調用postmessage.pl,它會將發件箱中的所有郵件(*.mail)發送出去(成功發送后將刪除原始郵件).
 
注: admin/bin下邊的autobuild.sh中按照上邊的順序串聯了整個編譯過程, 可以當作總的控制腳本,直接寫到crontab中每天定時運行,實現自動編譯; 另一個工具buildall.sh是一次完整的編譯過程的控制腳本, 不包含更新代碼,發送郵件的過程
1.6.   build.qzone.isd.com
這是由幾個簡單的php頁面構成的編譯結果發布站點,需要在Apache的httpd.conf中作如下配置:
<VirtualHost *>
   DocumentRoot /data/qzone_build/admin/htdocs
   ServerName build.qzone.isd.com
   DirectoryIndex index.php
   ScriptAlias /cgi-bin/ "/data/qzone_build/admin/cgi-bin/"
   Alias /src/ "/data/qzone_build/source/"
   AddType text/plain .cpp .c .h .sh .js .vbs .css .conf .ini .log
   ErrorLog logs/build.qzone.isdcom-error_log
</VirtualHost>
全部的頁面都放在/data/qzone_build/admin/htdocs下:
/data/qzone_build/admin/htdocs/
|-- buildres.xsl ->/data/qzone_build/admin/bin/buildres.xsl // xsl表單的軟連接,將原始文件放在bin中是為方便編輯
|-- index.php                //build.qzone.isd.com的入口頁面
|-- mainlist.php              //生成目錄列表頁面的工具腳本
|-- slist.php                  // 文件列表頁面
`-- test.php                  // php測試頁面 (非必需)
 

2 个解决方案

#1


發布頁面的入口如下:


這個頁面的信息主要來自/data/qzone_build/source下的每個目錄下的buildres.xml,
通過第一列各個日期的連接可以進入查看相應的編譯目錄,通過查看詳細信息,可以了解具體的編譯情況:

4

上圖頁面的信息主要來自各個目錄的ccversion.xml文件,ccversion.xml文件本身不會出現在列表中.


上圖頁面的信息來自相應的buildres.xml
 
注:由於源碼目錄下文件可能會被手工增刪或改動,有時有些信息文件無法正確讀取,這時php會發出警告,這些都是可以忽略的,可以通過/usr/local/lib/php.ini改變php的告警級別(僅顯示錯誤):
error_reporting  = E_ERROR
2.    關鍵工具的使用說明
2.1.   svntools.pl的用法
用途: 拉取svn工程源代碼的工具腳本.
配置文件:  svntools.conf, 需要和svntools.pl放在同一個目錄下, 其中設置遠程SVN服務器的連接信息(IP,USER,PASSWD等).
使用方法:  svntools [[-i|-u] local_directory|local_file]|[-e]|[-h]
   -i local_directory|local_file   顯示目錄或文件在遠程和本地的版本信息;
   -u local_directory|local_file   更新本地目錄或文件;
   -e                         查看或編輯配制文件;
   -h                         顯示幫助信息.
注意: 命令行中的目錄和文件參數支持相對和絕對路徑;路徑字符串中不支持通配符(*)和正則表達式.
 
其中srcroot定義了本地的源代碼更新位置和遠端svn地址, -i, -u選項后邊的文件路徑都應該在srcroot以內.
 
使用[svntools.pl -u 目錄名]更新時不會刪除服務器上不存在而在本地存在的目錄內部文件;但使用[svntools.pl -u 文件名]時會做刪除. 如果文件以及父目錄都在服務器上不存在,只會刪除文件而不會刪除父目錄.
 
cctool.pl –i 文件名可以比較本地文件和服務器上相應文件的CC信息,輸出內容分兩行顯示,分別以L和S開頭,L (local)代表本地文件信息,S (server)代表服務器端文件信息
 
2.2.   setroot.sh的用法
用途: 設置更新和(或)編譯目錄的軟連接
使用方法: setroot.sh[-b][-u][-d date|-p directory [-f]][-h]
           -b         set build source root
           -u         set update source root
           -ddate     use /data/qzone_build/source/qzone_$dateas base dir (fmt: YYYYMMDD)
           -pdir      use specified directory as basedir
           -f         use with -d or -p, force createdirectory if not exists
           -h         show help information
說明: 如果沒有(用-d或者-p)指定具體目錄,則會使用當天的日期當作-d的參數,即缺省采用–d + 當天日期
-f選項會在 –d或者-p指定的目錄不存在時創建目錄
-b會將指定的目錄軟連接到/usr/local/qzone_v3.0; -u會將指定的目錄軟連接到/data/qzone_build/temp/src
2.3.   confgen.pl的用法
用途: 根據makefile生成make.conf
使用方法:confgen.pl [-i original_makefile|-o outputfile_confile] [-h hint_file]
-i original_makefile, original makefile tobuild conf file;
-o outputfile_confile, name of output makeconfig file;
-f hint_file, a file in which includedefault conf values;
-h, print help messages.
說明: 缺省的輸入文件是/usr/local/qzone_v3.0/makefile, 但可以通過-i選項指定輸入文件;缺省的輸出文件是/usr/local/qzone_v3.0/make.conf, 但可以通過-o選項指定輸出文件; -f 用來指定缺省配置所在的文件,如果不指定的話,則會嘗試使用confgen.pl同一目錄下的make.conf.def,其中可以指定編譯目錄的依賴關系,以及包括,排除列表的缺省值,這些值會合並到最終生成的make.conf文件中(參見mkgen.pl的用法說明)
 
2.4.   mkgen.pl的用法
用途: 根據make.conf生成全構建腳本build.sh
使用方法:  mkgen.pl [-i include_list|-e exclude_list][-h] [-f hint_file] source_directory
-i include_list, ';' splited list forinclude sub_dirs;
-e exclude_list, ';' splited list forexclude sub_dirs;
-f hint_file, a file in which listinginclude/exclude sub_dirs;
-h, print help messages.
說明: 不一定要使用make.conf文件,(但是如果在沒有用-f 明確指定配制文件名,而/usr/local/qzone_v3.0/make.conf存在,則會嘗試使用它), 可以在命令行中通過 –i,-e指定參加構建的或者不參加構建的子目錄(如果-i,-e指定了同一個目錄,則以-e為准)
make.conf一個很重要的用途是用來指明編譯中的依賴關系,幫助確定編譯順序,下邊是一個例子:
[order]
platform/src/comm=16
comm=8
platform=4
main=2
[include]
portal/src/fcg
blog/src/blog
music/src/discuss/fcg
main/src/mall
izone/src/favor
其中order一節定義了不同目錄的優先級,數值越大越先編譯,(也就是說,越多的其他的代碼依賴於它).
優先級的設置使用目錄關鍵字=級別的形式定義,當目錄中包含關鍵字時(同一個關鍵字多次出現僅計算一次),會將相應的級別加到該目錄的總級別,最終的編譯腳本build.sh會按照各個目錄的級別由高到低依次編譯(級別相同的目錄意味着他們之間的編譯順序不影響結果,因此只按照目錄字母順序做簡單排序), 不含關鍵字的目錄級別為0, 比如:
platform/src/comm 級別 16
platform/src/c5a/c5atool 級別 4
main/src/comm 級別 10
blog/src/comm 級別 8
izone/src/favor 級別 0
music/src/comm 級別 8
建議使用2的冪做為級別的數字,以便拉開差距,防止低級別的目錄級別相加后超過更優先的級別.
 
mkgen.pl每次生成的build.sh都有一個不同的時間戳(選用當前系統時間),這個時間戳相當於build.sh的版本,不同版本的build.sh生成的log文件名不同,這些log的名稱格式是: build_***.log其中***就是它的時間戳
 
2.5.   writemail.pl,postmessage.pl的用法
用途: 這兩個工具腳本聯合起來完成郵件通知編譯結果的功能.它們應該放在同一個目錄下,並且還會在同一目錄下尋找message.conf文件,其中包含發送郵件配制信息,例如:
[server]
ip=192.168.?.?
user=qzonebuilder@tencent.com
port=25
[local]
msgbox=/data/qzone_build/temp/mbox
其中msgbox指定了發件箱的位置,writemail.pl缺省會將新建的郵件放進這里.
l  writemail的使用方法: writemail.pl [-i build resultfile] [-h] [-o output mail file]
    -i build result file's path & name
    -o output mail file's path & name
    -h  print help messages
說明: 如果沒有用-i 指定編譯結果文件,則嘗試使用/usr/local/qzone_v3.0/buildres.xml,如果沒有用-o指定生成的郵件的存放位置,則會根據build.sh的時間戳生成一封名為build_$timestamp.mail的文件放進message.conf中定義的msgbox中.
l  postmessage.pl的使用方法: postmessage.pl [-fmessage_box|message_file ]|[-a]|[-e]|[-h]
    -f message_box|message_file  指定郵箱路徑或者郵件文件名,郵件文件必須以.mail做為名稱后綴
    -a  自動發送缺省配置的郵箱內的所有郵件和消息;
    -e  查看或編輯配制文件;
-h  顯示幫助信息.
3.    crontab使用說明
3.1.   crontab腳本
工程編譯crontab腳本:


工程清理crontab腳本(保留一天的工程):


每天的譯結果匯總郵件:


至此整個過程結束!

#2


該回復於2016-08-12 11:32:59被管理員刪除

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com