利用Jenkins+Gitlab搭建持續集成(CI)環境
這次實習的任務之一就是搭建一個持續集成(Continuous Integration)環境。
我們選擇Jenkins作為持續集成工具,其優點是提供web GUI配置界面,方便配置,還可以安裝很多第三方插件(plugin)進行定制與擴展,功能強大。
其次選擇Gitlab作為git server。Gitlab的功能和Github差不多,但是是開源的,可以用來搭建私有git server,也提供非常強大的web GUI,比如開發者互相review源代碼的時候就會很方便。
本文首先介紹整個系統的結構,然后再一一敘述各個組件的安裝及使用方法。
1.系統概覽
系統結構如下圖所示:

系統的工作流程大概分為以下幾步:
1> 開發者將新版本push到git server (Gitlab)。
2> Gitlab隨后觸發jenkins master結點進行一次build。(通過web hook或者定時檢測)
3> jenkins master結點將這個build任務分配給若干個注冊的slave結點中的一個,這個slave結點根據一個事先設置好的腳本進行build。這個腳本可以做的事情很多,比如編譯,測試,生成測試報告等等。這些原本需要手動完成的任務都可以交給jenkins來做。
4> 我們在build中要進行編譯,這里使用了分布式編譯器distcc來加快編譯速度。
notes
jenkins的工作原理是先將源代碼從gitlab中拷貝一份到本地,然后根據設置的腳本進行build。我們可以看出,整個系統的關鍵就是那個build腳本,用來告訴jenkins在一次集成中需要執行的任務。
2.Jenkins的安裝與配置
1> 安裝Jenkins
首先說如何安裝 jenkins ,一定要安裝最新版本才不會出各種奇怪的問題,參考官網wiki, Installing Jenkins on Ubuntu 上的指示,
$ wget -q -O - http://pkg.jenkins-ci.org/debian/jenkins-ci.org.key | sudo apt-key add -
$ sudo sh -c 'echo deb http://pkg.jenkins-ci.org/debian binary/ > /etc/apt/sources.list.d/jenkins.list' $ sudo apt-get update $ sudo apt-get install jenkins
即可以得到最新版的jenkins。
Jenkins安裝完畢后,可以通過瀏覽器訪問其Dashboard,例如192.168.16.183:8080,IP地址即為Jenkins所在機器的IP地址。
2> Jenkins插件安裝
Jenkins其實沒有什么需要特別配置的,由於這次任務中需要利用Jenkins與git,gitlab協作,所以需要安裝一些插件。在主面板上點擊Manage Jenkins -> Manage Plugins。
由於公司使用代理連接外網,首先需要為Jenkins插件安裝配置proxy。點擊Advanced標簽即進入proxy設置頁面。
Aailable標簽下就是可以安裝的插件。
要讓Jenkins可以自動build git repo中的代碼,需要安裝GIT Client Plugin和GIT Plugin。
要想Jenkins可以收到Gitlab發來的hook從而自動build,需要安裝 Gitlab Hook Plugin。
要讓Jenkins可以在build完成之后根據TAP(test anything protocol)文件生成graph,需要安裝 TAP Plugin。
3> Jenkins Job
我們嘗試新建一個Jenkins Job,必須填的內容不是很多,而且每一項后面都有意一個問號,點擊后會有關於這項的一些提示。
(1)首先是Project name;
(2)然后在Source Code Management 中選擇Git,我們只需要提供Repository URL即可,這個URL可以是Jenkins機器上的一個本地repo,例如/home/woody/repo;也可以是一個遠程機器上的repo,例如Gitlab上通過ssh連接的repo: git@192.168.16.194:user/test_gitlab_repo.git
注意,我們需要在Jenkins機器上設置Git username 和 email,不然后面會build不成功。
(3)下面需要在Build中選擇Add build step,這里以最熟悉的shell為例,選擇Execute shell。Jenkins的工作原理很簡單,就是從剛才的Repository URL里clone到當前的一個workspace中並切換到最新的branch然后執行Execute shell中的command,如果每條command都返回0則build成功,否則則算失敗。 所以我們的shell command可以是簡單的編譯指令例如:
#!/bin/sh
make
(這需要你的git repo中有一個makfile)
也可以執行repo中的另一個腳本,例如
#!/bin/sh
perl test.pl
甚至可以什么都不做,或者是只輸入一些字符。
(4)接下來我們需要設置一個觸發選項,在Build Triggers中,Jenkins提供三個選擇
Build after other projects are built 顧名思義
Build periodically 周期性地build
Poll SCM 周期性的檢測SCM(如Git)中是否有新的提交,如果有則build
選擇后面兩項我們都需要在Schedule中設置周期,點擊后面的問號可以查看的設置周期的語法。
到這一步結束后我們就可以Save配置了,可以在面板中點擊Build Now看看是否可以正常工作。在下面的Build History中有該Job的所有build歷史,點擊任意一條進去后可以進行查看,特別說明可以在Console Output中看到執行這次build時控制台的輸出信息。
(5)如果安裝了TAP Plugin,我們還可以配置Job在build完成后根據TAP result生成一副Graph例如下圖:

這幅圖顯示了每次build中成功與失敗次數的走勢。
想要得到這張圖的話,需要在Configure的Post-build Action中選擇Add post-build action -> Publish TAP result。 然后在test result 中輸入你的TAP result文件的路徑,例如tap.tap指的就是當前文件下的tap.tap文件。也就是說在你的Execute Shell中,你需要在編譯完成后根據結果自己生成一個TAP文件,TAP的語法可以參考Jenkins TAP Plugin的說明。
4> 搭建Jenkins Master - Slaves 架構
我們在配置Jenkins時,有一個# of executors 選項,這項代表了Jenkins可以同時處理的Job的數量。
Jenkins還支持將Job分給Slave處理的功能。這就需要我們為Jenkins配置一些Slaves。
在Dashboard中點擊 Mamage Jenkins -> Manage Nodes -> New Node
然后輸入Node name 並選擇Dumb Slave 點擊OK后進入配置頁面。需要填的內容如下圖所示:

# of executors指的是該slave上允許同時處理的job數量; 其他選項也都顧名思義, 我們這里選擇用SSH的方式進行連接,Host即為Slave的IP地址。
Slave上不需要安裝Jenkins,只需要安裝java環境和git即可:
$ sudo aptitude install default-jre
$ sudo aptitude install git
還需要為slave的jenkins用戶配置git user.name & user.email
這里需要說明一個地方,Jenkins在工作時是利用一個名為jenkins的用戶登入機器的。
在master節點上,安裝Jenkins時自動為系統添加了一個名為jenkins的用戶,由於slave機器上不需要安裝jenkins,所以我們需要在slave機器上手動添加一個名為jenkins的用戶。而且Jenkins master只能通過不用輸入密碼的SSH方式連接slave,需要在master上用jenkins用戶生成一對ssh密鑰,並把公鑰加入slave機器上jenkins用戶的用戶目錄里.ssh/authorized_keys中。
注意,沒有密碼的用戶在ubuntu下可能切換不成功,我們用下面的方法:
$ sudo su jenkins
$ bash
3.Gitlab的安裝與配置
Gitlab的功能和Github差不多,都是作為git server。
Gitlab是開源的,我們可以利用Gitlab搭建自己私有的git server。
我們可以在bitnami上下載 Gitlab 。
公司有現成的Gitlab,所以我沒有嘗試Gitlab的安裝,看上去成功安裝並不容易。
為了測試,還是在虛擬機環境下配置了Gitlab,直接下載了Virtual Machine鏡像,由於鏡像是Vmware的,還需要將其轉為Virtual Box鏡像,方法參見http://wiki.bitnami.com/Virtual_Appliances_Quick_Start_Guide。
在虛擬機上跑起來后,發現是一個沒有GUI的ubuntu。。。系統用戶名和密碼都是bitnami。
我們還可以通過訪問其IP地址登入Gitlab,初始用戶名為user,密碼為bitnami,看上去和github很象。
由於在這次任務中Jenkins需要從Gitlab中獲取文件並build,所以我們需要在Gitlab的工程中設置一些東西。
首先是settings -> Deploy Keys, 這里需要加入Jenkins所在機器jenkins用戶的公鑰。
如果Jenkins中使用slave,還需要將slave的公鑰加入deloy keys中。 因為slave的工作原理是收到master的指示直接clone repository。
然后是一個叫Web Hooks的東東。還記得我們在Jenkins中安裝過Gitlab Hook Plugin么,如果設置了Web Hooks,Gitlab就會在每次push上來后發送一條消息到指定的地址(即hook的地址),Jenkins Gitlab Hook Plugin收到消息后立即build。
不過我按照Gitlab Hook Plugin的說明設置里hooks后並沒有什么作用,可能是那個插件的bug吧。。
后來大哥告訴我一個巧妙的辦法,就是將Jenkins Job里的build now連接作為hook地址,例如http://192.168.16.183:8080/job/test_gitlab/build?delay=0sec
這樣每次Gitlab收到push后就會促使Jenkins立即build。
4.distcc的安裝與配置
distcc是一個分布式的編譯器,他可以將編譯任務分配給多個其他機器上的destccd-daemon,從而加速編譯過程。
1> 安裝
ubuntu下distcc很容易安裝
$ sudo aptitude install distcc
2> 配置
distcc分為前端和守護進程,前端的用法和gcc差不多,用來編譯源代碼文件。
守護進程即distcc-daemon,需要一些配置。
守護進程的配置文件在 /etc/default/distcc 中,
$ sudo vim /etc/default/distcc
STARTDISTCC="true" //這項允許distccd啟動 ALLOWEDNETS=“192.168.16.0/24” //這項指出里允許那些IP的distcc連接上來, /24指的是子網掩碼前24位為1,后面為0,即代表192.168.16.0 ~ 192.168.16.255 LISTENER=“192.168.16.183” //這項應該填本機的IP地址,即需要監聽的IP地址 ZEROCONF = “false” //這項指出不開啟zeroconf,我們先講不開啟zeroconf,后面再討論使用它的情況
這樣一個distccd就配置完成了。
通過以下命令可以開啟和停止distccd
$ sudo service distcc start
$ sudo service distcc stop
在進行編譯前,因為distccd都沒有開啟zeroconf,所以distcc無法知道有哪些host可供使用,所以這里需要在環境變量中加入,例如
export DISTCC_HOSTS="192.168.16.183 192.168.16.198"
使用下面的命令可以查看hosts是否配置成功。
$ distcc --show-hosts
然后就可以使用distcc進行分布式編譯,例如編譯linux kernel,
$ make CC=distcc
下面講當我們為distccd開啟ZEROCONF時即配置
ZEROCONF=“true”
這就說明distcc可以不需要手動配置hosts地址即可以發現可用的hosts,具體原理不是很清楚,反正用命令
$ distcc --show-hosts
可以看到distccd的地址。
但是這里貌似對IPv6的解析上有一個bug,百度里一下說需要關閉avahi的IPv6
編輯 /etc/avahi/avahi-daemon.conf
修改以下內容
use-ipv6=no
即可。
然后還需要在調用distcc的用戶的環境變量中加入
export DISTCC_HOSTS="+zeroconf"
我們還可以在調用distcc的用戶中用以下命令查看編譯的進度
$ distccmom-text 5