持續集成(二)持續集成在web端和app端的探索實踐

持續集成的前提條件:

  1. 一天屢次提交
  2. 建立全面的自動化測試套件
    • 單元測試和集成測試套件由開發人員準備
    • 系統測試套件由測試人員準備
  3. 保持較短的構建和測試過程
    測試一階段
    • 本機提交前的預編譯和單元測試和單元集成測試過程(DEV本機環境五分鐘以內)
    • 持續集成服務器提交前的預編譯和單元測試和單元集成測試過程(DEV本機環境五分鐘以內)
    測試二階段
    • 在持續集成服務器上運行SIT測試,UAT測試和性能測試
    • 經過高性能的多進程機器分佈式執行(將時間控制在半小時以內)
    • 將簡單的冒煙測試也加在提交階段
  4. 管理開發工做區
    • 在本地開發環境中應確保所使用的自動化過程和與持續集成環境中的一致,與測試環境中的也同樣。
    • 這個的先決條件是細心的配置管理,包括測試數據,數據庫腳本,構建腳本和部署腳本
    • 確保自動化測試能夠在開發機上運行

開發人員的最佳實踐

  1. 構建失敗以後不要提交新代碼
  2. 提交前在本地運行全部提交測試,活着讓持續集成服務器完成此事
  3. 等提交測試經過後再繼續工做
  4. 回家以前,構建必須處於成功狀態
  5. 時刻準備着回滾到前一個版本
  6. 在回滾以前要規定一個修復時間,若是規定時間(例如:10分鐘)不能修復就回滾到上個版本
  7. 不要將失敗的測試註釋掉

部署流水線

持續集成軟件

持續集成軟件包括兩個部分java

  • 一個一直運行的進程,每隔一段時間就會執行一個簡單的工做流程
  • 提供展示這個流程運行結果的視圖, 通知你構建和測試成功與否,讓你能夠找到測試報告,拿到生成的安裝文件(例如APP就是提供二維碼)
  • 除了上述幾本功能外,還能夠將構建狀態發送到外部設備中,或者在一個屏幕上顯示構建的狀態以及提交者的頭像。 
    創建在以上基礎上的進一步的優化擴展是在構建過程當中對源代碼進行一些分析工做,包括分析測試覆蓋率,重複代碼,是否符合編碼標準,圈複雜度,以及其餘一些健康指標

Docker和持續集成

經過部署本身私有的Docker鏡像registry,並創建本身的自動化構建,將Docker集成到持續集成工做流中。 
除了持續集成和持續部署以外的自動化測試部分,只須要從Jenkins創建一個hook來啓動自動化腳本並生成測試報告。 
關於本節須要作到git

  • 管道化部署介紹
  • 持續部署的技術思路
  • 效果展現
  • 配置Git和Jenkins聯動
  • 配置Jenkins自動更新代碼
  • 效果圖文詳解
  • FAQ

管道化視圖

經過Jenkins系統的Job觸發機制,咱們能夠方便的建立各類類型的集成Job用例。但缺少統一標準的Job用例使用方法,會致使項目Job用例使用的混亂,難於管理維護。這也讓開發團隊沒法充分利用好集成系統的優點,固然這也不是咱們指望的結果。因此,敏捷實踐方法提出了一個能夠持續交付的概念 DeploymentPipeline(管道部署)。經過Docker技術,咱們能夠很方便的理解並實施這個方法。 
Jenkins的管道部署把部署的流程形象化成爲一個長長的管道,每間隔一小段會有一個節點,也就是Job,完成這個Job工做後才能夠進入下一個環節。形式以下: 
正則表達式

開發同窗經過git push上傳代碼,經Git和Jenkins配合,自動完成程序部署、發佈,全程無需運維人員參與。 
這是一種真正的容器級的實現,這個帶來的好處,不只僅是效率的提高,更是一種變革: 
難者不會,會者不難。經過簡單的4個配置,便可優雅地實現持續部署。docker

1. 持續部署的技術思路

在本例中,假設咱們JAVA項目的名稱爲hello。簡要的技術思路以下。 
數據庫

本案例中假設代碼託管在git.oschina.com上,Jenkins和Docker Registry(相似於yum源)各運行在一個Docker容器中。JAVA項目本身也單獨運行在一個叫hello的容器中。 
本文采起的持續部署方案,是從私有的Docker Reistry拉取代碼。有些變通的方案,把代碼放在宿主機上,讓容器經過卷組映射來讀取。這種方法不建議的緣由是,將代碼拆分出容器,這違背了Docker的集裝箱原則: 
這也致使裝卸複雜度增長。從貨運工人角度考慮,總體纔是最經濟的。這樣,也才能實現真正意義的容器級遷移。 
或者說,容器時代,拋棄過去文件分發的思想,纔是正途。本文最後的問答環節對此有更多闡述。 
容器即進程。咱們採用上述方案作Docker持續部署的緣由和意義,也在於此。容器的生命週期,應該遠遠短於虛擬機,容器出現問題,應該是當即殺掉,而不是試圖恢復。安全

2. 效果展現

本文最後實現的效果,究竟有多驚豔呢?且看以下的演示。服務器

2.1 程序代碼更新前的效果

咱們以時間戳來簡潔、顯式的表述程序更新狀況。 
網絡

2.2 提交程序代碼更新

本例中,咱們把首頁的時間戳從201506181750,修改成201506191410(見以下)。 
app

2.3 上傳新代碼到Git

順序執行以下操做,輸入正確的git帳號密碼。 
運維

而後呢? 
而後什麼都不用作了。端杯茶(若是不喜歡咖啡的話),靜靜地等待自動部署的發生, 旁觀一系列被自動觸發的過程,機器人似的運轉起來(請容稍候再加以描述)。 
爲何須要3~5分鐘?只是由於本案例中的JAVA項目,須要從國外download Maven程序包,以供Jenkins調用和編譯JAVA。正式應用環境中,能夠把Maven源放在國內或機房。若是僅僅須要對PHP項目作持續部署,那就更快捷了。

2.4 查看代碼更新後的效果

在靜靜地等待幾分鐘後,新的代碼確實已經自動部署完畢。 

那麼,這一切怎麼實現的呢?要按照以下幾步,即可快速實現。

3. 配置Git和Jenkins聯動

這個過程也是難者不會,會者不難。主要分爲以下三步。

3.1 Jenkins配置Git源

Jenkins中新建項目java-app,並配置從Git拉取程序代碼。具體以下: 

3.2 Jenkins配置遠程構建

Jenkins中配置token,以供git遠程調用時使用。 

3.3 Git開啓鉤子

怎麼讓Git在接收到用戶更新的代碼後,把消息和任務傳遞給Jenkins呢?這藉助於Git的hook功能,配置起來也很是簡單,以下。 

4. 配置Jenkins自動更新代碼

Jekins在接收到Git傳遞過來的消息後,再觸發一個遠程構建(到目標服務器),按照預約義的任務列表,執行一系列的工做,重建容器等。詳見以下: 

咱們把其中最關鍵的Shell腳本內容摘抄出來。 

5. 效果圖文詳解

在2.3這個章節中,咱們當時的操做以下,這個目的是向Git提交更新代碼。 

當時並無細說後續發生的事情,既然上面已經說清楚了原理,那咱們就能夠接下來講說實際發生的事情啦。

5.1 上傳代碼到Git

這裏貌似整個過程已經完成並順利退出。其實,後臺的工做纔剛剛開始。 

這時會觸發Git服務器向相應的Jenkins服務器發出一個操做請求,此工做太過迅速,也沒啥好說的,咱們接下來看Jenkins都幹啥子了。

5.2 Jenkins進行的精彩互動
  1. Jenkins會自動冒出來一個構建任務。 

  2. 咱們點進來,看看具體操做日誌。是的,正在接受來自Git的任務。 

  3. 下載Maven相關的軟件包(就是這個過程慢)。 

  4. 下載完成後,就開始利用maven BUILD 新的hello項目包。

  5. 而後重建Maven容器,構建新的Image並Push到Docker私有庫中。 

  6. 最後,從新把Docker容器run起來。這樣,又新生了。 

6. FAQ

問題1:採用這麼相對複雜的辦法(而不是把更新代碼放在宿主機而後卷組映射),是由於項目基於JAVA麼;是否PHP項目就能夠採用更新代碼放在宿主機而後卷組映射這種方式? 
回答1:將代碼拆分出容器,違背了集裝箱原則。致使裝卸複雜度增長。從貨運工人角度考慮,總體纔是最經濟的。一切版本化。拋棄過去的文件分發。這是正途。至於文件大小,大的war包也就50M或100M,在現有網絡下不成問題,性能問題最好優化。另外建議關注docker 2 docker,p2p傳輸。

問題2:若是總體代碼超過500m或者1g以上,總體集裝箱是否就不太好了?若是容器與代碼分離,鏡像就100m左右(2層,base+服務),而後代碼的話,是放到共享存儲裏,每一個代碼有更新,好比svn的代碼,能夠直接在共享存儲裏進行svn update就能夠控制版本 
回答2:若是你的代碼500M,說明就須要精簡了。

使用Jenkins搭建iOS/Android持續集成打包平臺

1. 背景描述

根據項目需求,現要在團隊內部搭建一個統一的打包平臺,實現對iOS和Android項目的打包。並且爲了方便團隊內部的測試包分發,但願在打包完成後能生成一個二維碼,體驗用戶(產品、運營、測試等人員)經過手機掃描二維碼後就能直接安裝測試包。 
該需求具備必定的廣泛性,基本上全部開發APP的團隊均可能會用到,所以我將整個需求實現的過程整理後造成此文,而且真正地作到了零基礎上手,到手即飛、開箱即用,但願能對你們有所幫助。 
首先,先給你們展現下平臺建設完成後的總體效果: 
該平臺主要實現的功能有3點:

  • 按期對GitHub倉庫進行檢測,如有更新則自動執行構建打包;
  • 構建成功後根據ipa/apk生成二維碼,並可在歷史構建列表中展現各個版本的二維碼,經過手機掃描二維碼可直接安裝對應版本;
  • 在構建結果頁面中展現當次構建的成果物(Artifact,如.ipa、.app、.apk、info.plist等文件),供有須要的用戶進行下載。 
    接下來,本文就開始對平臺建設的完整實現過程進行詳細介紹。
2. 安裝Jenkins

Jenkins依賴於Java運行環境,所以須要首先安裝Java。 
安裝Jenkins的方式有多種,能夠運行對應系統類型的安裝包,能夠經過docker獲取鏡像,也能夠直接運行war包。 
我我的傾向於直接運行war包的形式,只需下載jenkins.war後,運行以下命令便可啓動Jenkins。 
$ nohup java -jar jenkins_located_path/jenkins.war --httpPort=88 & 
若是不指定httpPort,Jenkins的默認端口爲8080。

3. Jenkins插件

Jenkins有很是多的插件,能夠實現各類功能的擴展。 
針對搭建的iOS/Android持續集成打包平臺,我使用到了以下幾個插件。

  • GIT plugin
  • SSH Credentials Plugin
  • Git Changelog Plugin: 獲取倉庫提交的commit log
  • build-name-setter:用於修改Build名稱
  • description setter plugin:用於在修改Build描述信息,在描述信息中增長顯示QRCode(二維碼)
  • Post-Build Script Plug-in:在編譯完成後經過執行腳本實現一些額外功能
  • Xcode integration: iOS專用(可選)
  • Gradle plugin: Android專用(可選) 
    安裝方式也比較簡單,直接在Jenkins的插件管理頁面搜索上述插件,點擊安裝便可。
4. 建立項目(Job)

在Jenkins中,構建項目以Job的形式存在,所以須要針對每一個項目建立一個Job。有時候,一個項目中可能有多個分支同時在進行開發,爲了分別進行構建,也能夠針對每一個分支建立一個Job。 
建立Job的方式有多種,本次只須要建立Freestyle project類型的便可。 
Main page -> New Item -> Freestyle project 
對於一個持續集成打包平臺,每次打包都由4步組成:觸發構建、拉取代碼、執行構建、構建後處理。對應的,在每一個Job中也對應了這幾項的配置。

5. 配置Git代碼倉庫

要對項目進行構建,配置項目的代碼倉庫是必不可少的。因爲當前咱們的項目託管在GitHub私有倉庫中,所以在此須要對Git進行配置。 
在【Source Code Management】配置欄目下,若是以前GIT plugin安裝成功,則會出現Git選項。 
配置Git代碼倉庫時,有三項是必須配置的:倉庫URL地址(Repository URL)、倉庫權限校驗方式(Credentials),以及當前Job須要構建的代碼分支(Branches to build)。 
在配置Repository URL時,選擇HTTPS URL或SSH URL都可。不過須要注意的是,Credentials要和Repository URL對應,也就是說:

  • 若是Repository URL是HTTPS URL形式的,那麼Credentials就要採用GitHub用戶名密碼的校驗方式;並且,若是在GitHub中開啓了2FA(two-factor authentication),那麼還須要在GitHub中建立一個Personal access token,輸入密碼時將這個Personal access token做爲密碼進行輸入。
  • 若是Repository URL是SSH URL形式的,那麼就須要先在Jenkins所在的服務器上建立一個SSH祕鑰對,並將公鑰添加到GitHub的SSH keys中,而後在填寫Credentials時,選擇SSH Username with private key的校驗方式,填入GitHub Username、SSH私鑰、以及建立SSH祕鑰對時設置的Passphrase。 
    若是對Git權限校驗的概念還比較模糊,能夠參考《深刻淺出Git權限校驗》。 
    在配置Branches to build時,能夠採用多種形式,包括分支名稱(branchName)、tagName、commitId等。其中分支名稱的形式用的最多,例如,如果構建master分支,則填寫refs/heads/master,如果構建develop分支,則填寫refs/heads/develop。 
    除了以上關於Git的必填配置項,有時根據項目的實際狀況,可能還須要對Jenkins的默認配置項進行修改。 
    比較常見的一種狀況就是對clone的配置進行修改。 
    在Jenkins的默認配置中,clone代碼時會拉取全部歷史版本的代碼,並且默認的超時時限只有10分鐘。這就形成在某些項目中,因爲代碼量自己就比較大,歷史版本也比較多,再加上網絡環境不是特別好,Jenkins根本無法在10分鐘以內拉取完全部代碼,超時後任務就會被自動終止了(錯誤狀態碼143)。 
    這種問題的解決方式也很簡單,無非就是兩種思路,要麼少拉取點代碼(不獲取歷史版本),要麼提升超時時限。對應的配置在Advanced clone behaviours中:
  • Shallow clone:勾選後不獲取歷史版本;
  • Timeout (in minutes) for clone and fetch operation:配置後覆蓋默認的超時時限。
6. 配置構建觸發器

代碼倉庫配置好了,意味着Jenkins具備了訪問GitHub代碼倉庫的權限,能夠成功地拉取代碼。 
那Jenkins何時執行構建呢? 
這就須要配置構建觸發策略,即構建觸發器,配置項位於【Build Triggers】欄目。 
觸發器支持多種類型,經常使用的有:

  • 按期進行構建(Build periodically)
  • 根據提交進行構建(Build when a change is pushed to GitHub)
  • 按期檢測代碼更新,若有更新則進行構建(Poll SCM) 
    構建觸發器的選擇爲複合選項,若選擇多種類型,則任一類型知足構建條件時就會執行構建工做。若是全部類型都不選擇,則該Jenkins Job不執行自動構建,但可經過手動點擊【Build Now】觸發構建。 
    關於定時器(Schedule)的格式,簡述以下: 
    MINUTE HOUR DOM MONTH DOW
  • MINUTE: Minutes within the hour (0-59)
  • HOUR: The hour of the day (0-23)
  • DOM: The day of the month (1-31)
  • MONTH: The month (1-12)
  • DOW: The day of the week (0-7) where 0 and 7 are Sunday. 
    一般狀況下須要指定多個值,這時能夠採用以下operator(優先級從上到下):
  • 適配全部有效的值,若不指定某一項,則以*佔位;
  • M-N適配值域範圍,例如7-9表明7/8/9均知足;
  • M-N/X或*/X:以X做爲間隔;
  • A,B,C:枚舉多個值。 
    另外,爲了不多個任務在同一時刻同時觸發構建,在指定時間段時能夠配合使用H字符。添加H字符後,Jenkins會在指定時間段內隨機選擇一個時間點做爲起始時刻,而後加上設定的時間間隔,計算獲得後續的時間點。直到下一個週期時,Jenkins又會從新隨機選擇一個時間點做爲起始時刻,依次類推。 
    爲了便於理解,列舉幾個示例:
  • H/15 * * * *:表明每隔15分鐘,而且開始時間不肯定,這個小時多是:07,:22,:37,:52,下一個小時就多是:03,:18,:33,:48;
  • H(0-29)/10 * * * *:表明前半小時內每隔10分鐘,而且開始時間不肯定,這個小時多是:04,:14,:24,下一個小時就多是:09,:19,:29;
  • H 23 * * 1-5:工做日每晚23:00至23:59之間的某一時刻;
7. 配置構建方式

觸發策略配置好以後,Jenkins就會按照設定的策略自動執行構建。但如何執行構建操做,這還須要咱們經過配置構建方式來進行設定。 
經常使用的構建方式是根據構建對象的具體類型,安裝對應的插件,而後採用相應的構建方式。例如,如果構建Android應用,安裝Gradle plugin以後,就能夠選擇Invoke Gradle script,而後採用Gradle進行構建;如果構建iOS應用,安裝Xcode integration插件以後,就能夠選擇Xcode,而後選擇Xcode進行構建。 
該種方式的優點是操做簡單,UI可視化,在場景不復雜的狀況下能夠快速知足需求。不過缺點就是依賴於插件已有的功能,若是場景較複雜時可能單個插件還沒法知足需求,須要再安裝其它插件。並且,有些插件可能還存在一些問題,例如對某些操做系統版本或XCode版本兼容不佳,出現問題時咱們就會比較被動。 
我我的更傾向於另一種方式,就是本身編寫打包腳本,在腳本中自定義實現全部的構建功能,而後在Execute Shell中執行。這種方式的靈活度更高,各類場景的構建需求都能知足,出現問題後也能自行快速修復。 
另外,對於iOS應用的構建,還有一個須要額外關注的點,就是開發者證書的配置。 
若是是採用Xcode integration插件進行構建,配置會比較複雜,須要在Jenkins中導入開發證書,並填寫多個配置項。不過,若是是採用打包腳本進行構建的話,狀況就會簡單許多。只要在Jenkins所運行的計算機中安裝好開發者證書,打包命令在Shell中能正常工做,那麼在Jenkins中執行打包腳本也不會有什麼問題。

8. 構建後處理

完成構建後,生成的編譯成果物(ipa/apk)會位於指定的目錄中。可是,若是要直接在手機中安裝ipa/apk文件還比較麻煩,不只在分發測試包時須要將好幾十兆的安裝包進行傳送,體驗用戶在安裝時也還須要經過數據線將手機與計算機進行鏈接,而後再使用PP助手或豌豆莢等工具進行安裝。 
當前比較優雅的一種方式是藉助蒲公英(pgyer)或http://fir.im等平臺,將ipa/apk文件上傳至平臺後由平臺生成二維碼,而後只須要對二維碼連接進行分發,體驗用戶經過手機掃描二維碼後便可實現快速安裝,效率獲得了極大的提高。

9. 上傳安裝包文件,生成二維碼

無論是蒲公英仍是http://fir.im,都有對應的Jenkins插件,安裝插件後能夠在Post-build中實現對安裝包的上傳。 
除了使用Jenkins插件,http://fir.im還支持命令上傳的方式,蒲公英還支持HTTP Post接口上傳的方式。 
我我的推薦採用命令或接口上傳的方法,並在構建腳本中進行調用。靈活是一方面,更大的好處是若是上傳失敗後還能進行重試,這在網絡環境不是很穩定的狀況下極其必要。 
Jenkins成功完成安裝包上傳後,pgyer/http://fir.im平臺會生成一個二維碼圖片,並在響應中將圖片的URL連接地址進行返回。

10. 展現二維碼圖片

二維碼圖片的URL連接有了,那要怎樣才能將二維碼圖片展現在Jenkins項目的歷史構建列表中呢? 
這裏須要用到另一個插件,description setter plugin。安裝該插件後,在【Post-build Actions】欄目中會多出description setter功能,能夠實現構建完成後設置當次build的描述信息。這個描述信息不只會顯示在build頁面中,同時也會顯示在歷史構建列表中。 
有了這個前提,要將二維碼圖片展現在歷史構建列表中貌似就能夠實現了,能直觀想到的方式就是採用HTML的img標籤,將寫入到build描述信息中。 
這個方法的思路是正確的,不過這麼作之後並不會實現咱們預期的效果。 
這是由於Jenkins出於安全的考慮,全部描述信息的Markup Formatter默認都是採用Plain text模式,在這種模式下是不會對build描述信息中的HTML編碼進行解析的。 
要改變也很容易,Manage Jenkins -> Configure Global Security,將Markup Formatter的設置更改成Safe HTML便可。 
更改配置後,咱們就能夠在build描述信息中採用HTML的img標籤插入圖片了。 
另外還須要補充一個點。若是是使用蒲公英(pyger)平臺,會發現每次上傳安裝包後返回的二維碼圖片是一個短連接,神奇的是這個短鏈接竟然是固定的(對同一個帳號而言)。這個短鏈接老是指向最近生成的二維碼圖片,可是對於二維碼圖片的惟一URL地址,平臺並無在響應中進行返回。在這種狀況下,咱們每次構建完成後保存二維碼圖片的URL連接就沒有意義了。 
應對的作法是,每次上傳完安裝包後,經過返回的二維碼圖片短連接將二維碼圖片下載並保存到本地,而後在build描述信息中引用該圖片的Jenkins地址便可。

11. 收集編譯成果物(Artifacts)

每次完成構建後,編譯生成的文件較多,可是並非全部的文件都是咱們須要的。 一般狀況下,咱們可能只須要其中的部分文件,例如.ipa/.app/.plist/.apk等,這時咱們能夠將這部分文件單獨收集起來,並在構建頁面中展現出來,以便在須要時進行下載。 要實現這樣一個功能,須要在【Post-build Actions】欄目中新增Archive the artifacts,而後在Files to archive中經過正則表達式指定成果物文件的路徑。 設置完畢後,每次構建完成後,Jenkins會在Console Output中採用設定的正則表達式進行搜索匹配,若是能成功匹配到文件,則會將文件收集起來。

相關文章
相關標籤/搜索