今天的話題是,持續(xù)集成和“云”,主要部分是我之前兩年的工作和我的一些個(gè)人思考。
這個(gè)話題我之前在中國的ruby大會上講過,slides在這里 ,供參考,不過但是現(xiàn)在講的內(nèi)容根據(jù)最近多半年的工作進(jìn)展又有所變化。
先自我介紹一下,我是軟件工程師,從業(yè)13年,主要從事的領(lǐng)域都是應(yīng)用系統(tǒng)開發(fā),涉及
OA、電信網(wǎng)管/增值業(yè)務(wù)、互聯(lián)網(wǎng)等領(lǐng)域。
2009年底加入阿里,2015年4月離職,主要做的事情:廣告應(yīng)用系統(tǒng) -> 運(yùn)維自動(dòng)化平臺 -> 持續(xù)集成服務(wù)平臺。
最后的持續(xù)集成服務(wù)平臺是來自于實(shí)踐需要,我最先在做廣告業(yè)務(wù)系統(tǒng)的研發(fā)工作,廣告系統(tǒng)雖然復(fù)雜,但是其中的應(yīng)用系統(tǒng)從軟件架構(gòu)上看并沒有什么特別的地方,所以希望將精力投在可以改進(jìn)團(tuán)隊(duì)工作水平的地方。
一開始是一個(gè)運(yùn)維自動(dòng)化平臺,由于團(tuán)隊(duì)人手有限,我基本是一個(gè)人做的,發(fā)現(xiàn)開發(fā)效率很好,軟件質(zhì)量也不錯(cuò),所以在工作中總結(jié)了一些質(zhì)量改進(jìn)的實(shí)踐,在團(tuán)隊(duì)中推廣,這是我從研發(fā)進(jìn)入QA的起點(diǎn)。
經(jīng)過一段時(shí)間摸索,我們發(fā)現(xiàn)測試自動(dòng)化搞不起來的原因之一是成本太高。
我之前習(xí)慣用ruby或者rails,所有的測試都可以單機(jī)完成,用cucumber這樣的工具可以做BDD,用vagrant可以避免環(huán)境污染,所以自動(dòng)化沒問題。而java就沒有這些條件了,數(shù)據(jù)庫掌握在DBA手里,測試的linux是大家公用的,很容易引起沖突。
于是我和主管商量,決定搞一個(gè)平臺,通過它降低研發(fā)成本,在本團(tuán)隊(duì)開展一段時(shí)間以后,又帶著系統(tǒng)轉(zhuǎn)到技術(shù)質(zhì)量部,把CISE做大,測試部門成立了專門的團(tuán)隊(duì),離職前已經(jīng)開始在各bu和研發(fā)團(tuán)隊(duì)廣泛運(yùn)用。
對CI的理解
持續(xù)集成平臺究竟解決什么問題呢?
簡單說,就是兩個(gè)自動(dòng)化:
· 構(gòu)建自動(dòng)化
· 測試自動(dòng)化
測試自動(dòng)化好理解,構(gòu)建自動(dòng)化比想象中要復(fù)雜一些,我一般用下面這張圖來解釋。
我們手里的軟件,總是可以進(jìn)行不斷地分解,從系統(tǒng)到模塊,最后到類和方法。由于整體和部分的功能不能完全劃等號,所以測試需要在各個(gè)層面上進(jìn)行,但是這些測試的成本和收益有所不同。
如圖,我之前感到j(luò)ava開發(fā)的痛苦,就源于工程師手中沒有更上層的“武器”,所以只能在單測上用力。
所以,如果我們能做好更大尺度系統(tǒng)的自動(dòng)化的構(gòu)建,那么研發(fā)人員也就有機(jī)會使用“高層”的自動(dòng)化測試,而避免在細(xì)節(jié)上寫太多的用例。
但這個(gè)并不容易,我們的努力也只是起到了一部分作用。
平臺介紹
下面說一下這個(gè)平臺本身,由于涉及到阿里巴巴內(nèi)部系統(tǒng),有些是不能說的,不過還好,核心部分并沒啥技術(shù)含量 :-)
很多人對CI的了解是基于jenkins,當(dāng)然也有些人接觸過travis CI或者circle CI,我們的系統(tǒng)更像后者,當(dāng)然功能上要更強(qiáng)些。
平臺的起點(diǎn)是公司的gitlab和svn服務(wù),通過自動(dòng)監(jiān)控或者h(yuǎn)ook觸發(fā),每一次代碼提交都會觸發(fā)一個(gè)自動(dòng)化過程,在這個(gè)過程中,平臺負(fù)責(zé)分配虛擬機(jī)、數(shù)據(jù)庫等必要資源,然后將代碼編譯打包構(gòu)建運(yùn)行。
編譯打包構(gòu)建運(yùn)行看起來是一個(gè)自動(dòng)化過程,但每個(gè)環(huán)節(jié)實(shí)際上都可以有驗(yàn)證——這其實(shí)就是各種測試。
· 編譯前可以做代碼掃描(有的語言是編譯后做代碼掃描)
· 編譯之后可以做單測
· 打包運(yùn)行后可以做集成測試
和travis不同的是,如果目標(biāo)涉及多個(gè)應(yīng)用,之間存在服務(wù)調(diào)用,那么我們還會自動(dòng)的將相關(guān)應(yīng)用也部署好,然后在一個(gè)機(jī)器群里面做更接近真實(shí)場景的功能測試。
做過類似工作的同學(xué)一定知道這一點(diǎn)的代價(jià)有多大,但這樣會有很大好處——我們可以在一次commit后自動(dòng)進(jìn)行所有層面的測試——從單測到系統(tǒng)交付測試。
當(dāng)然這是理論上的,實(shí)際中可以根據(jù)研發(fā)團(tuán)隊(duì)需要進(jìn)行選擇。
總結(jié)一下,我們認(rèn)為,CI平臺應(yīng)該能進(jìn)行所有粒度的測試,最小針對函數(shù),最大可以針對分布式系統(tǒng)。作為前提,CI平臺需要支持整個(gè)系統(tǒng)的自動(dòng)化構(gòu)建。
這個(gè)大概是和travis CI之間最大的不同,下面再列幾個(gè)不是很重要的區(qū)別。
使用云平臺解決虛機(jī)問題,身在阿里巴巴,所以我們使用阿里云的ECS,需要資源是隨時(shí)申請,用過以后立即釋放重置。
這樣可以解決環(huán)境污染的問題(即使是java應(yīng)用,有些團(tuán)隊(duì)也會留下本地文件操作,這些東西會導(dǎo)致測試不可重復(fù))。
數(shù)據(jù)庫自動(dòng)分配,我們構(gòu)建了mysql集群,不過不是一般意義上的那種協(xié)作集群,而是一個(gè)數(shù)據(jù)庫池,讓數(shù)據(jù)庫和虛機(jī)一樣隨用隨取,用后重置。
這樣做是為了讓java程序員也可以像rails的db migration一樣可以用到干凈的數(shù)據(jù)庫。
對這個(gè)平臺的介紹就這些,下面討論一些經(jīng)驗(yàn)教訓(xùn)。
經(jīng)驗(yàn)教訓(xùn)
UI應(yīng)該盡量輕
這個(gè)話題要和jenkins/hudson做對比,這兩個(gè)系統(tǒng)我其實(shí)不是很熟,不過也知道它們都是很強(qiáng)大的自動(dòng)化系統(tǒng)。但是,jenkins/hudson的最大問題是,它們的UI做的太多了,用戶可以在UI上做很多事——很多和CI沒關(guān)系的事情。
舉個(gè)例子:
jenkins的任務(wù)是可以排隊(duì)調(diào)度的,而對于CI來說,排隊(duì)是什么意思呢?研發(fā)工程師養(yǎng)成持續(xù)小步提交代碼這個(gè)好習(xí)慣以后,又硬生生由于資源不足而被迫等待,最終可能會放棄這個(gè)好習(xí)慣,實(shí)在是不劃算。
我們的辦法是——敞開供應(yīng),只要有代碼提交就分配機(jī)器,當(dāng)然有人會質(zhì)疑,因?yàn)檫@會導(dǎo)致需要一個(gè)很大的資源后備池,不過這可能正是“云”時(shí)代的不同思考方式——在“云”的時(shí)代,資源的使用毛刺應(yīng)該通過大規(guī)模后備池來抹平。
當(dāng)然,濫用資源還是要避免的,只是我們認(rèn)為需要“后置懲罰”,比如通過審計(jì),找出資源消耗大戶,打他的板子。
當(dāng)我們把所有的額外功能都剝掉以后,發(fā)現(xiàn)UI其實(shí)就一個(gè)作用——展現(xiàn),因?yàn)镃I需要的是完全的自動(dòng)化,人工本來就不需要介入,只要最后被notify一下,或者偶爾過來在web上看看報(bào)表趨勢什么的就夠了。
CI是服務(wù)加最佳實(shí)踐
我們理解的第二個(gè)經(jīng)驗(yàn)就是,搞CI,是服務(wù)加最佳實(shí)踐,所以一定要指導(dǎo)研發(fā)團(tuán)隊(duì),而不能完全任由研發(fā)團(tuán)隊(duì)提要求,很多團(tuán)隊(duì)的工程師良莠不齊,對各種編程api比較熟悉,但是可能缺乏做事的好習(xí)慣,這時(shí)需要指導(dǎo)他們,當(dāng)然前提是你也要對開發(fā)很了解才行,否則會被鄙視的。
對CI來說,最大的常見麻煩是不寫測試,這個(gè)一般是通過管理教育,比較簡單。
另外一個(gè)隱藏的比較深——開發(fā)人員對系統(tǒng)的運(yùn)行并不了解,比如開發(fā)的系統(tǒng)運(yùn)行在linux上,但是基本的命令都不會。
這個(gè)問題我們遇到了挑戰(zhàn),有人認(rèn)為這涉及到分工,研發(fā)工程師不應(yīng)該了解線上,但是這個(gè)觀點(diǎn)是有問題的。
因?yàn)楹芏郻ug和環(huán)境相關(guān),如果開發(fā)人員不能在”真“的環(huán)境中嘗試,一旦系統(tǒng)報(bào)錯(cuò),很難不發(fā)生扯皮——這個(gè)扯皮可能發(fā)生在開發(fā)和測試之間,更可怕的是發(fā)生在線上,光定位就需要N多人參與,成本極大。
插件
最后是插件的問題,這個(gè)說來簡單——插件能解決一些問題,不過插件設(shè)計(jì)之初實(shí)際上就限制了其使用,所以我總結(jié)的教訓(xùn)就是:先別急著做插件,想好了設(shè)計(jì)再動(dòng)手。
更進(jìn)一步
先進(jìn)一步談?wù)剬I平臺職責(zé)的理解,然后結(jié)合這些理解最后說說“云”和docker的作用
CI平臺的職責(zé)
關(guān)于CI平臺的職責(zé),我上次已經(jīng)提過,基本上就是這些:
構(gòu)建自動(dòng)化:提供環(huán)境
測試自動(dòng)化:提供平臺
先說構(gòu)建
構(gòu)建工作主要產(chǎn)出兩個(gè)東西:最終輸出的軟件包和待測的應(yīng)用系統(tǒng)(有時(shí)后者會包含前者),這兩個(gè)產(chǎn)出的核心要點(diǎn)有所不同。
最終輸出的軟件包大多數(shù)公司都會做的,重點(diǎn)是構(gòu)建過程環(huán)境無關(guān)而且可重復(fù),因此需要提供配管服務(wù),比如最好有yum、npm、gem等軟件包服務(wù)。
但是這里有個(gè)問題——間接依賴的軟件包如何鎖定的問題,ruby的bundle機(jī)制很不錯(cuò),通過Gemfile.lock讓依賴包都有明確的版本(而不是“最新版本”這種含糊的說法),但是maven就沒有這樣的支持,目前沒有很好地辦法,只能讓構(gòu)建號和軟件包號建立關(guān)聯(lián),便于回溯。
而待測的應(yīng)用系統(tǒng)是比較難的地方,它也需要配管系統(tǒng)支持,同時(shí)還需要資源的就緒能力,一個(gè)關(guān)鍵要點(diǎn)是——資源必須是隔離的,否則很難避免測試時(shí)互相干擾。
這個(gè)隔離應(yīng)該做到什么程度呢?舉個(gè)例子,我們?yōu)榱诉M(jìn)行系統(tǒng)聯(lián)調(diào),自動(dòng)構(gòu)建了一套涉及N個(gè)系統(tǒng)的集群,這個(gè)集群是為了進(jìn)行自動(dòng)的聯(lián)調(diào)測試。而理論上我們?nèi)绻枰,CI平臺應(yīng)該可以再構(gòu)建另一個(gè)集群,各種架構(gòu)細(xì)節(jié)和前一個(gè)集群完全相同,但這兩個(gè)集群進(jìn)行工作時(shí)應(yīng)該互不影響。
這要求應(yīng)用需要符合一些最佳實(shí)踐的要求,比如12 factor里面說的不要硬編碼ip地址等等
為什么要這樣?因?yàn)槌掷m(xù)集成是不斷前進(jìn)的工作節(jié)奏,一個(gè)人的工作有了階段性結(jié)果后,需要進(jìn)行驗(yàn)證,這種驗(yàn)證應(yīng)該是獨(dú)立的,如果和其他人共享測試環(huán)境,要么測試結(jié)果不穩(wěn)定,要么變成我上次說到的排隊(duì),那就降低了效率。
這兩張圖說的就是這個(gè)意思,同一團(tuán)隊(duì)的兩個(gè)程序員公用數(shù)據(jù)庫進(jìn)行測試,測試結(jié)果就會不穩(wěn)定,同樣,如果他們的應(yīng)用依賴了另一個(gè)公共服務(wù),那么測試依然不能穩(wěn)定。
不知道第二種情況會不會難以理解,簡單說就是那個(gè)公共服務(wù)也是有存儲的,所以那個(gè)數(shù)據(jù)庫里面的數(shù)據(jù)會造成干擾。
構(gòu)建自動(dòng)化比較復(fù)雜,而測試自動(dòng)化相對來說簡單一些,不過這里的重點(diǎn)是對各種測試的抽象和區(qū)分。
根據(jù)上次分享的反饋,發(fā)現(xiàn)有相當(dāng)多的人不太理解這張圖。
我們把測試分為UT/FT/IT/ST等等,但其實(shí)它們可以抽象成一個(gè)東西——都是對某個(gè)軟件單元的驗(yàn)證,區(qū)別在于單元的粒度
補(bǔ)充說明一下上面說的一些名詞:
· UT:單元測試
· FT:功能測試
· IT:集成測試
· ST:系統(tǒng)測試
所謂的“上層用例變化慢“,是相對的,因?yàn)閼?yīng)用系統(tǒng)常常是需求一變,整個(gè)推翻,所以上層需求用例的變化常常帶來下層大量用例的變化,而反之則未必.
考慮到需求和測試用例直接聯(lián)系很緊密,我們可以認(rèn)為需求用例的變動(dòng)頻率和測試用例的變動(dòng)正相關(guān)。
當(dāng)然,測試自動(dòng)化還有一個(gè)要做的工作是對結(jié)果的分析匯總,主要是各種測試手段的輸出千差萬別,需要進(jìn)行數(shù)據(jù)匯總,這個(gè)和普通的數(shù)據(jù)處理沒啥區(qū)別,我也不是這方面的專家,就不獻(xiàn)丑了。
但是,作為CI平臺,對結(jié)果數(shù)據(jù)的分析匯總要建立在測試階段的界定上,簡單說就是要明確區(qū)分UT、IT等環(huán)節(jié)階段,這是后續(xù)報(bào)表很重要的信息,不能小看。
CI職責(zé)講完了,我下面想說一下自己對“云”在CI方面價(jià)值的理解——簡單說就是標(biāo)準(zhǔn)化。
CI的自動(dòng)化測試和普通測試一樣,有天生就要面對的問題:
· bug確認(rèn)(可重現(xiàn))
· 代碼覆蓋
· 測試的真實(shí)性
先說bug確認(rèn)的困難,在測試團(tuán)隊(duì)待過的人一般都能理解問題確認(rèn)有多麻煩,很多的bug是辛辛苦苦發(fā)現(xiàn)的,結(jié)果被開發(fā)同學(xué)一句“環(huán)境不一樣”就打發(fā)了。
所以測試非常需要標(biāo)準(zhǔn)的環(huán)境,而這正是“云”可以提供的,要是進(jìn)一步考慮自動(dòng)化測試,那是比普通測試更需要標(biāo)準(zhǔn)環(huán)境的場合,因?yàn)樗菬o人值守的,對意外的適應(yīng)能力更弱。
代碼覆蓋也是測試的一個(gè)重要指標(biāo),幾乎所有的開發(fā)語言和框架都有不止一個(gè)代碼測試覆蓋率統(tǒng)計(jì)工具,而代碼覆蓋其實(shí)是涉及到測試層次的,在上層測試一個(gè)系統(tǒng),往往能夠覆蓋不少下層用例,如果能從多個(gè)層次測試系統(tǒng),可以讓工作事半功倍。
最后再說一下測試的真實(shí)性,這里是指對mock技術(shù)的使用。我們很多時(shí)候使用mock技術(shù)只有一個(gè)原因——對方系統(tǒng)太難打交道了,所以做個(gè)mock先繞開(有時(shí)需要模擬對端錯(cuò)誤,這種情況還是需要mock的)。
但是真實(shí)情況下我們訪問的不是白板方法,這么做的有風(fēng)險(xiǎn),最后還是要聯(lián)調(diào),所以這種情況是把測試推后了,是轉(zhuǎn)移矛盾而不是解決矛盾。
我之前做的CI平臺,正是想通過云技術(shù),可以相對低成本的構(gòu)建“全部系統(tǒng)”,因?yàn)?借助我們的平臺)有時(shí)候這個(gè)做法比mock要簡單,更重要的是,這種做法肯定比mock要真實(shí)。
以上都是云的價(jià)值,也是docker的價(jià)值,不過docker有個(gè)獨(dú)特的價(jià)值,就是有可能將測試甚至運(yùn)維工作變成服務(wù)。
這里說的服務(wù)不是那種在公司里某個(gè)部門為其它團(tuán)隊(duì)提供的服務(wù)平臺,那很容易模糊邊界(比如開發(fā)要求測試幫忙等等)。
這里的服務(wù)是指成立公司,把這些工作變成business的東西。
當(dāng)然,這塊其實(shí)不稀奇,我之前說過的Traivs CI、shippable、coding應(yīng)該都在做,docker創(chuàng)業(yè)團(tuán)隊(duì)大多都在做這個(gè),不過我想說的是——為什么這事變得可行了?
這是由于標(biāo)準(zhǔn)化,一個(gè)應(yīng)用應(yīng)該是個(gè)什么樣子?在docker的語境中是比較一致的,這為用戶和服務(wù)平臺提供了相對簡單的協(xié)作邊界。
舉個(gè)例子,這是我們平臺自己的一個(gè)模塊在進(jìn)行自動(dòng)化構(gòu)建時(shí)寫到描述文件(相當(dāng)于 .tavis.yml)中的內(nèi)容:
這么一大坨,我不相信會有人能受得了,但是如果在docker中呢?
這樣還符合我之前說的原則——開發(fā)人員自己管理環(huán)境
在這種變化下,我覺得我們做的東西可以大幅度簡化,以至于變?yōu)橐粋(gè)對外服務(wù)的business,根據(jù)這個(gè)想法,我自己做了一點(diǎn)簡單的嘗試,不過是用青云做的,錄了兩段很短的視頻,在這里:
http://v.youku.com/v_show/id_XODAzNzgyMjUy.html
http://v.youku.com/v_show/id_XODAzNzgxOTky.html
我要講的基本上就這些,今天應(yīng)該沒超時(shí),最后關(guān)于docker上的CI再多說兩句,提個(gè)想法——docker應(yīng)該依靠但不依賴IAAS。
借助SDN,避免通過Docker來劃分安全域:我看了一點(diǎn)最近docker大會的介紹,老實(shí)說,有一種觀點(diǎn)是把vm廢掉,我是不以為然的,所謂vm所帶來的成本其實(shí)正是我們獲得安全隔離的原因,這兩者是一體的,我們直接拿來用vm做安全隔離最好,讓docker解決安全問題應(yīng)該是一條歧路。
深度依賴compose機(jī)制,建立聯(lián)調(diào)/系統(tǒng)測試的構(gòu)建標(biāo)準(zhǔn):應(yīng)該會有很多人和我想的一樣——將compose.yml作為重要信息來源,外部的系統(tǒng)通過它理解應(yīng)用間的聯(lián)系,即使不使用 docker compose 這個(gè)軟件,也應(yīng)該遵循 compose.yml 的規(guī)范,這樣我們不但能讓單兵(容器)的外部邊界清晰,還能讓戰(zhàn)陣(分布式系統(tǒng))也能被管控系統(tǒng)理解和支撐。
深度依賴compose需要讓compose.yml目的變得純粹些,我知道compose描述的內(nèi)容很容易變成“不同環(huán)境”,其實(shí)這個(gè)想法也許不正確,我認(rèn)為一個(gè)git分支就對應(yīng)一種場景——比如某些分支是用來開發(fā)局部功能的,它不需要系統(tǒng)測試和聯(lián)調(diào),而master必然要聯(lián)調(diào)——所以不用在代碼中留下多份 compose_xxx.yml,而應(yīng)該在不同分支上編寫不同的 compose.yml,其內(nèi)容由分支維護(hù)者負(fù)責(zé)。
分享人:李建業(yè),前阿里巴巴員工(花名:李福),2002年本科畢業(yè),之后一直從事軟件開發(fā),涉及辦公自動(dòng)化、電信網(wǎng)管/增值業(yè)務(wù)系統(tǒng)以及互聯(lián)網(wǎng);2009年12月加入淘寶的廣告應(yīng)用開發(fā)團(tuán)隊(duì);從2011年底開始,關(guān)注軟件研發(fā)本身,主要工作包括運(yùn)維自動(dòng)化系統(tǒng)和持續(xù)集成服務(wù)平臺。
核心關(guān)注:拓步ERP系統(tǒng)平臺是覆蓋了眾多的業(yè)務(wù)領(lǐng)域、行業(yè)應(yīng)用,蘊(yùn)涵了豐富的ERP管理思想,集成了ERP軟件業(yè)務(wù)管理理念,功能涉及供應(yīng)鏈、成本、制造、CRM、HR等眾多業(yè)務(wù)領(lǐng)域的管理,全面涵蓋了企業(yè)關(guān)注ERP管理系統(tǒng)的核心領(lǐng)域,是眾多中小企業(yè)信息化建設(shè)首選的ERP管理軟件信賴品牌。
轉(zhuǎn)載請注明出處:拓步ERP資訊網(wǎng)http://www.ezxoed.cn/
本文標(biāo)題:前阿里員工技術(shù)分享:持續(xù)集成和“云”
本文網(wǎng)址:http://www.ezxoed.cn/html/news/10515318339.html