jenkins是一個ci工具。它可以持續編譯,運作你的代碼;運作ut或內建測試;将運作結果發送至郵件,或展示成報告。。。
這樣做的最終目的是:
讓項目保持健康的狀态。如果任何checkin break了build,每個人都會在最短的時間内通知到,然後問題被fix。接下來的開發将建立在一個健康正确的基礎上,而不是任由問題累積,最後失控。
最後,你的項目随時可以被deliver給使用者,因為,你的項目每一天都在健康,茁壯的生長。這就是ci的意義所在。
jenkin和cruisecontrol
jenkins和cruisecontrol都是ci工具,二者在ci中發揮的作用完全一緻。
而jenkins作為新一代的ci工具,漸漸開始取代cruisecontrol。二者都是java程式,但:
1,jenkins提供更為友好的使用者界面,而cruisecontrol在界面方面糟糕的幾乎等于沒有。
2,jenkins内置的功能提供了極大的便利,不論是建立一個build,還是日常使用,你需要做的大部分時候僅僅是在使用者界面上點選而已。
在cruisecontrol建立build是通過建立config.xml來完成的。它僅僅提供非常有限的功能,很多時候你會發現,需要自己完成很多工作。
3,jenkins作為一個欣欣向榮的開源項目,有大批的plugin。當你發現需要一個jenkins本身并不提供的功能是,搜尋一下plugin,總會有收獲。非常多的流行工具如jbehave,cobertura都提供jenkins插件。
而針對cruisecontrol的plugin卻很少。
4,jenkins友好的使用者界面讓學習成本很少,你可以在最短的時間内開始你的工作。
事實上,jenkins是我見過的最好的開源項目之一,它簡潔實用的使用者界面設計,完善的文檔,豐富的插件。當你開始使用它,你就會愛上它。
當你需要一個build工具時,jenkins幾乎是當下的不二選擇。
jenkins和hudson
jenkins起源于hudson。hudson在商業軟體的路上繼續前行,而jenkins則作為開源軟體,從hudson分支出來。
是以現在的jenkins和hudson非常類似,但是随着二者各自的發展,已經有了一些不同。
要想更多的了解jenkins,當然最好是通路它的官方網站。也可以參考我的下一篇文章:
jenkins(二) http://blog.csdn.net/onlyqi/article/details/7076915
至少和官網比起來,它是中文的~
官網:https://wiki.jenkins-ci.org/display/jenkins/meet+jenkins
我的這篇文章僅僅是簡單的根據上文,介紹jenkins提供了哪些功能。具體大家還是要自己學習啦~
官網首頁就提供了windows版本的jenkins安裝包。我們可以下載下傳一個用于學習。安裝後自動打開http://localhost:8080,你就能看見jenkins的界面了。
其他也需要安裝的是:
1,jenkins是java程式,是以需要安裝jdk。
2,同時運作job需要提供repository,也就是存放jenkins定期poll源代碼的地方。我們可以去github免費注冊一個。
3,如果想在jenkins中使用ant,maven等,則還需要單獨安裝。但不是必須的。
啟動jenkins
jenkins天生支援unix-like system。
直接運作
好吧,jenkins是一個java程式,是以要運作它,隻需要:
$ java -jar jenkins.war
我們也可以使用nohup指令,讓jenkins在背景運作。
之後打開url http://myserver:8080 就可以友善的操作jenkins了
官網給了一個sh的例子,用于啟動jenkins。可以參考一下。
在servlet container中運作
alternatively, if you have a servlet container that supports servlet 2.4/jsp 2.0, such as glassfish v2, tomcat 5 (or any later versions), then you can run them as services, and deployjenkins.war as you would any other war file.
for example,
you could simply place the jenkins.war file in tomcat’s webapps directory. 此時使用的url預設就變成:
http://localhost:8080/jenkins
同時jenkins提供一些預設不會啟動的特殊的功能,參考下面的link來enable它們。
https://wiki.jenkins-ci.org/display/jenkins/features+controlled+by+system+properties
jenkins的目錄結構
和cruisecontroler一樣,jenkins需要一個目錄來存儲相關檔案:jenkins_home。預設為 ~/.jenkins。即為user的home目錄下的一個隐藏目錄。我們也可以更改jenkins_home,指向我們希望的地方。
(注意因為是隐藏目錄,是以需要使用ls -al 才能看到)
jenkins_home
+- config.xml (jenkins root configuration)
+- *.xml (other site-wide configuration files)
+- usercontent (files in this directory will be served under your http://server/usercontent/)
+- fingerprints (stores fingerprint records)
+- plugins (stores plugins)
+- jobs
+- [jobname] (sub directory for each job)
+- config.xml (job configuration file)
+- workspace (working directory for the version control system)
+- latest (symbolic link to the last successful build)
+- builds
+- [build_id] (for each build)
+- build.xml (build result summary)
+- log (log file)
+- changelog.xml (change log)
如果有權限管理,則在home目錄下還會有users目錄。
從目錄結構來看,和cruisecontroller非常相似。其中config.xml是jenkins重要的配置檔案。我們都知道jenkins用于monitor多個build,而jobs這個目錄無疑就是存儲每個build相關資訊的地方。
總的來說,jenkins目錄結構非常直白,簡潔。
備份和恢複
備份和恢複非常簡單,就是簡單的copy jenkins的目錄就好了:
all the settings, build logs, artifact archives are stored under the jenkins_home directory. simply archive this directory to make a back up. similarly, restoring the data is just replacing the contents of the jenkins_home directory from a back up.
移動/拷貝/重命名 job
由于每個jobs都有自己單獨的目錄,我們可以很容易的:
1,move a job from one installation of jenkins to another by simply copying the corresponding job directory.
,2,make a copy of an existing job by making a clone of a job directory by a different name.
3,rename an existing job by renaming a directory.
修改後執行下面的指令重新整理:
http://[jenkins-server]/[command]
在這裡[command]可以是:exit 退出,restart 重新開機, reload 重載。
建立一個project
因為jenkins可以用于運作各種ci,測試,批處理任務等等,是以在jenkins中将這些任務統稱為“free-style software project”.
jenkins也提供了其他類型的jobs,例如:
1,如果項目是maven,jenkins還提供了一種僅用于maven project的job。但其實free-style software projec仍然可以用于建立maven項目,隻不過這種更适合maven項目,結合的更好而已。
2,也可以建立一個"monitor an external job“用于監控外部程序。
3,或者一個matrix project,也就是multi-configuration project。
我不确定是否僅有這4種job,也許使用插件可以建立更多類型的job,大家自己看資料吧。
下面是如何建立一個最常見的“free-style software project"的過程:
go to jenkins top page, select "new job", then choose "build a free-style software project". this job type consists of the following elements:
optional scm, such as cvs or subversion where your source code resides. 指定源代碼在哪。
note: in software engineering, software configuration management (scm) is the task of tracking and controlling changes in the software.
optional triggers to control when jenkins will perform builds. 指定jenkins何時觸發一次build。
some sort of build script that performs the build (ant, maven, shell script, batch file, etc.) where the real work happens 觸發build時,使用的腳本檔案,例如ant。在這個腳本檔案中,我們可以從svn下載下傳最新代碼,删除上次build的臨時檔案,建立必要目錄,編譯源代碼,運作,打包等一系列工作。
optional steps to collect information out of the build, such as archiving the artifacts and/or recording javadoc and test results. 收集log資訊。
optional steps to notify other people/systems with the build result, such as sending e-mails, ims, updating issue tracker, etc. 通知相關人員build的結果。
例如我們使用的build script就是ant,在jenkins中運作ant。在腳本檔案中,可以直接使用jenkins提供的一些變量。
同時,每個job可以有多個step。例如:将運作程式定義為step1,運作單元測試定義為step2,生成coverage報告定義為step3。
同時還可以定義post-build action。例如:生成javadoc,或清理程式運作的臨時檔案目錄等。
自動運作build
觸發一個build有三種方式:
builds in jenkins can be triggered periodically (on a schedule, specified in configuration) 這裡定義schedule的文法是unix常見的cron文法。
or when source changes in the project have been detected
可以設定jenkins定時檢查svn是否發生了變化,也可以手動檢查:http://yourhost/jenkins/job/projectname/pollong。也可以設定jenkins為post-commit,這個方式尤其适用于那些檢查是否代碼改變會花費很長時間的情況。
or they can be automatically triggered by requesting the url:
http://yourhost/jenkins/job/projectname/build
distributed builds
jenkins supports the "master/slave" mode, where the workload of building projects are delegated to multiple "slave" nodes, allowing single jenkins installation to host a large number of projects, or provide different environments needed for builds/tests.
在現實中需要使用distributed builds情況很多,例如:一個web application的build,需要分别驗證firefox和ie的行為,那麼就需要到windows機器上運作ie。
或因為性能問題,将build分布到多個slave節點去。
到jenkins的管理界面,就可以友善的添加節點。配置節點時,需要提供節點所在的機器,登陸使用者名密碼,使用的目錄等。
但是slave并不需要再安裝jenkins。jenkins會自動啟用slave agent,将build需要tools考到遠端機器上。
需要注意的是:the build results and artifacts will always end up on the master server. 是以不需要跑到各個節點去檢視build産生的檔案,log等。
其實在slave節點,會建立一個本地的workspace,并在運作時使用這個workspace。因為畢竟build運作在slave節點上,是以這個節點肯定要有運作build需要的所有因素。
總之添加節點并遠端運作build真是太友善了~
添加節點後,在master jenkins home目錄下會出現關于該節點的配置檔案。
jenkins将自動決定在哪個節點上運作build,根據下列政策:
some slaves are faster, while others are slow. some slaves are closer (network wise) to a master, others are far away. so doing a good build distribution is a challenge. currently, jenkins employs the following strategy:
if a project is configured to stick to one computer, that's always honored.
jenkins tries to build a project on the same computer that it was previously built.
jenkins tries to move long builds to slaves, because the amount of network interaction between a master and a slave tends to be logarithmic to the duration of a build (iow, even if project a takes twice as long to build as project b, it won't require double network transfer.) so this strategy reduces the network overhead.
jenkins通過運作slave agents來完成分布式build。最常見的情況是:slave agent運作在各個slave 節點。master通過ssh遠端啟動/停止slave agent,進而控制各個節點的行為。
一共有下列4種方式啟動slave agent:
•the master starts the slave agents via ssh
• starting the slave agent manually using java web start
• installing the slave agent as a window service
• starting the slave agent directly from the command line on the slave machine from the command line
需要注意的是這4種方式适用于不同的情況,例如slave節點在防火牆後,導緻master無法通過ssh啟停slave agent。此時隻能用後三種方式,但是往往有一些弊端,比如master無法自動停止/重新開機 slave agent.
一旦添加node成功,你就可以在job中指定這個job在哪個node運作:
restrict where this project can be run (如果不指定則由jenkins自行決定,即可以在slave節點運作,也可以在master節點運作,甚至在一次build中就可以自行來回切換)。
配置jenkins,讓它收集更多的log
https://wiki.jenkins-ci.org/display/jenkins/logging
我想這對于初學jenkins的人,用來判斷問題所在太有用了。
在流行持續內建的今天,我們在各個環境:alpha,beta和production 都部署了唯一的jenkins伺服器。
jenkins伺服器統一負責該環境内所有元件的持續內建。也就是說,一個jenkins伺服器會有很多個build。是以有時會用到上面提到的”monitor an external job“。
但不是distributed builds。
同時由于jenkins會進入每個環境,包括production,是以會使用auto deployment的方式,自動完成jenkins在各個環境的部署。
使用者管理
毫無疑問jenkins中需要有使用者管理的功能,因為除開發人員外,有多種角色的人需要檢視build的結果。
在jenkins中的系統管理中,可以設定“任何使用者可以做任何事” 或 “登入使用者可以做任何事”。
是以前一個選項意味着,任何浏覽jenkinsurl的使用者都可以修改jenkins。或隻有登入使用者才能做修改。
是以我把jenkins中的使用者劃分為兩類:可登入使用者和不可登入使用者。
1,隻要是修改過repository,即對build産生過影響的使用者,都會被jenkins記錄在本地的database中。這類使用者我們可以在jenkins界面->檢視使用者中浏覽。
但這類使用者不是正式的jenkins使用者,也不能登入jenkins。這類使用者的權限由上面說的系統管理中的配置決定。通常隻有檢視build的權限,沒有修改權限。
2,隻有在jenkins中明确注冊的使用者,才能夠登入jenkins,并且有權限控制。同時注冊過的使用者,在jenkins_home目錄下的users目錄下,都有一個單獨的目錄來存儲相關資訊。我不太清楚是否能夠通過copy/paste将使用者部署到其他地方去,回頭測試一下。
既然要滿足各種人對jenkins使用的各種需求,是以權限管理遠沒有這麼簡單。具體大家還得自己去看啊~
jenkins script console
jenkins提供了一個script console groovy script which allows to run arbitrary scripts on the jenkins server or on slave nodes. this feature can be accessed from the "manage jenkins" link。
也可以通過url直接通路:http://myserver:8080/hudson/script
可惜隻能用groovy 反證我不懂。
在使用jenkins的過程中,當然也會遇到一些問題。在這裡我把我遇到的,比較奇怪的問題列出來,供大家參考。
環境變量
我在一個slave node上運作job時發現,被啟動的程式顯示找不到環境變量。
原來,當jenkins在slave上啟動一次build時,不會應用目前使用者的profile。是以我們得自己解決這個問題。
解決方式有很多:
1,在建立slave node時,可以指定要傳遞的環境變量。這種方法不好的地方就是,相當于hard code,當實際的環境變量改變時,也需要手工修改slave node的配置。
2,想辦法自己應用:運作shell前運作:. /usr/usr_account/.profile (注意第一個點後面有空格),這個是最好的方法,因為所有的環境變量都會生效,而不是僅僅某一個。
或者在調用的ant中,或ksh script中指定某個具體的環境變量。
程序被kill
需求是這樣的:在jenkins中一個job運作完畢時,可以配置它觸發下一個job運作。這種情況很常見,例如一個job中啟動一個程式并運作了ut,當運作完畢時,我們可能會希望一個內建測試的job被觸發。這裡隐含的意思就是,我們希望程式能一直運作,直到所有的測試結束,最後再顯式的停止這個程式。
然而在實施的過程中,我遇到了一個大問題:在第一個job運作結束後,程式就被殺掉了。第二個job沒有運作測試的時間。
來看看這個人遇到的類似的問題:
i am trying to run a shell script to stop/start the jboss instance, but when the hudson job completes, the jboss instance shutdowns. does anybody have any recommendations on how we can spawn an instance of jboss from a hudson job without using the daemonize script?
由于現實中事情的複雜性(在jenkins中調用了ant,ant調用了ksh,ksh最終啟動了程式),我繞了很大一圈才懷疑到jenkins上。在這之前,我嘗試在ant中使用<parallel>,在調用ksh時使用nohup,但是問題依舊。
而問題的根本在于是jenkins使用processtreekiller殺掉了所有子程序,而且這是jenkins的預設行為。其實回頭來看這個問題,就發現jenkins的做法非常合理。當一次build異常結束,或被人終止時,必然需要結束所有這次build啟動的子程序。下面的link提供了更多細節,以及解決方法。
https://wiki.jenkins-ci.org/display/jenkins/processtreekiller
jenkins home目錄下的tools目錄沒有被同步到slave node
在jenkins的home目錄下,有兩個自動生成的目錄: tools and usercontent。
當我在使用slave node時,我注意到在每個slave node的上,jenkins自動建了一個tools目錄。是以我想當然的以為,tools目錄是用來存放使用者自己需要的第三方工具的。
例如,我在project中需要使用ant 1.8.2。而tools中則存放了ant 1.8.2,同時在建立slave node時,jenkins自動将ant1.8.2拷貝到了slave node的tools下。
然而在之後的使用中,我發現在master node的tools中放置其他的第三方工具後,slave node的tools中并沒有增加。是以slave node上的project并不能使用對應的第三方工具。
事實真相是,我應該使用usercontent目錄,而不是直接使用tools目錄。
當使用者需要某個第三方工具時,正确的做法是将安裝包放到usercontent目錄。然後在jenkins system management中要求安裝這個工具。
usercontent目錄的說明:
you can use this directory to place your own custom content onto your jenkins server. you can access files in this directory at http://myserver/hudson/usercontent (if you are running
jenkins on an application server) or http://myserver/usercontent (if you are running in standalone mode).
之後jenkins會自動将該工具安裝到tools目錄下,同時也會同步到slave node的tools下。像我這樣直接扔在master node的tools下,是不會自動同步的。
還有一種解決方案:
jenkins 并沒有機制自動将master node上的tools目錄下的内容同步到slave node上。這意味着如果在slave node上運作project需要某些特殊工具(或jar包),隻能事先在slave node所在的box上安裝好(或準備好)。
但是在某些極端條件下,slave node并沒有準備好這些工具。
例如,我們使用jenkins來自動deployment最新的release到production,而安裝release意味着很多附加功能,例如環境檢查,安裝程式,自動啟停程式,啟動cluster等複雜操作。
我們使用ant script來完成這些操作。但ant在production環境沒有安裝。
是以我希望将ant相關的jar放到master jenkins根目錄的tools目錄,然後将tools同步到slave node的tools目錄下,之後在slave node上運作ant就可以使用這些jar包了。
但是目前我們隻能通過使用一個工具rsync來将tools下的内容同步到slave node:
on master, i have a little shell script that uses rsync to synchronize master's/var/jenkins to slaves (except/var/jenkins/workspace) i use this to replicate tools on all slaves.
如何取得slave node上的jenkins home
我在腳本裡,或ant中使用環境變量jenkins_home的時候發現一個問題: 盡管限制了job在slave node上運作,但是這個變量的值還是master node的jenkins_home。而不是在slave node的配置中配置的“remote fs root”
一個解決方案是,在建立slave node時,在配置頁面下方的node properties中添加一個環境變量:slave_home=上面配置的“remote fs root”目錄。這樣就可以在slave node上使用這個變量了。
you can also specify environment variables. these will be passed into your build jobs, and can be a good way to allow your build jobs to behave differently depending on where they are being executed.
比如在ant中,加入:
<property environment="env"/> 來擷取所有的環境變量。
之後用<echo message="home is ${env.slave_home}"/>就可以了。
這裡順便提一下,有一個plugin可以顯示每次build時,jenkins自動生成的環境變量。在shell, ant中都可以友善的使用這些變量。
在所有的projects中傳遞參數
一個需求:有3個projects,run.program, run.ut, run.integration.test
它們使用在一個project完成後自動trigger另外一個的方式,形成了一個chain。同時第一個project是parameterized- project,即build時需要提供輸入參數。其中一個輸入參數是,boolean ifrunut,是否運作ut。
現在,如果在第一個project中選擇不運作ut,則skip後面的那個project,之後繼續運作第三個project,也就是內建測試。
解決方法是安裝這個plugin:https://wiki.jenkins-ci.org/display/jenkins/parameterized+trigger+plugin
同時将後面的run.ut改為parameterized-project,同時有唯一的一個輸入參數ifrunut。
上面的plugin可以将第一個project的輸入參數傳遞到它觸發的下一個project。這樣當後面的run.ut發現ifrunut=false時,就自動傳回successful,之後該project繼續觸發之後的run.integration.test。
聽上去有點無聊,但是試想一下,如果有兩個關于ut的project:run.ut.1 run.ut.2。上面的方法就可以一次配置,skip掉兩個projects,而不需要配置多次。
更重要的是,這種做法使得整個chain的配置都集中在一個地方,而不是分散在各個project中。每次build都需要去多個projects配置參數是很讓人崩潰的。