1. 程式人生 > >通聯數據是如何使用Docker+Rancher構建自動發布管道的?

通聯數據是如何使用Docker+Rancher構建自動發布管道的?

最簡 兩個 產品 分支模型 這樣的 com mat 5.0 指向

大家好,今天我將分享通聯數據使用Docker和Rancher構建自動化發布管道的經驗,我會介紹通聯數據自動化發布的流程及方案設計,我們從踩過的一些坑中總結出來的經驗,以及我們的自動化發布管道的系統運行現狀。

一、通聯數據的需求及選擇Rancher的原因


通聯數據是一家這幾年新崛起的金融科技公司,主要目標是致力於將大數據、雲計算、人工智能等技術和專業投資理念相結合,打造國際一流的、具有革命性意義的金融服務平臺。這裏面涉及到幾個關鍵詞:大數據、雲計算、人工智能,這些熱詞已經有很多企業提及過,因此我也不贅述了。

通聯數據作為一家創業公司,也會遇到很多創業公司都會遇到的問題,比如產品太多,而且每年很多產品都會推翻重來,就會遇到各種各樣的問題。比如,應用在開發時,涉及到需要多少CPU、需要用什麽語言去編程等問題,開發人員不會與後臺人員事先溝通,出來一個產品,直接讓運維人員上線。


基於這樣一個背景,我們迫切需要打通上線這條管道,因為在可預見的將來,通聯數據每年將會有大量的新應用出現,如何打通上線這條管道亟待解決。

我們做的第一件事,就是做持續集成。由於我們公司每年會有上百個新的項目產生,每個項目的語言、框架、部署方法都不盡相同,發布流程也是比較冗長低效的,部署應用占用了運維人員大量時間。

我們決定用容器解決這個問題,評估了多家供應商後選擇了Rancher,主要原因在於:

首先,Rancher的操作界面非常簡單,相信用過Rancher的人都會有這種感受,它不需要太多專業的知識,很容易上手;其次,Rancher在部署時也非常簡單,可以一鍵式部署,Rancher還提供了良好的API支持,方便集成。

二、自動化發布的流程

隨後,我們開始搭建自己的CI/CD。當時我們在流程方面遇到了很多困境,下圖已經是簡化制作後的了,實際上還有更多各種各樣的分杈和分枝:
技術分享圖片

就我們原來的流程來說,流程最開始的部分是研發;隨後進入QA環境部署,這時候就需要人去部署,通常是運維人員,但是運維一般不願意做這個事情;部署完成後,進入QA環境測試階段,通知開發和測試人員進行測試,過程中可能會出現延遲,因為測試人員可能正忙於其它的事情,不能馬上進行測試;QA環境測試通過後,進入STG環境部署;隨後再進行STG環境測試,這幾個過程可能會循環很多次。跟著進入安全測試階段;測試通過後,還有一個正式包的一個準備過程,最後才能上生產部署。即使是這個簡化後的流程也是非常復雜的,而且其中涉及到很多線下的溝通,效率不可能高得起來。


在使用Rancher之後,原本的流程大大簡化了,改進後的簡化流程如下圖:
技術分享圖片
流程的第一步即持續集成,意味著開發人員寫好代碼後可以直接通過CI,CI觸發自動編譯,隨後自動部署腳本,測試環境已經就緒。簡單來說,每次開發人員提交代碼之後,測試環境就始終處一個就緒的狀態,這時候就可以直接進入測試階段,整個過程都處於線下,不需要走任何流程,全部實現自動化了。

測試人員完成測試後,再進行STG環境測試,因為後臺已經跟Rancher完成對接並實現自動化,這賦予了QA環境測試從未有過的強大的自動化能力,意味著QA環境測試可以自動對接到STG環境測試。測試通過後,進入安全測試階段,這個階段是公司要求的,無法避免,安全測試通過後就進入到生產部署。以前繞不開的線下溝通那些步驟和一些部署就可以省去了,整個流程優化並且簡潔,效率也提升了。

CI/CD說起來可能很簡單,比如PUSH代碼、QA環境自動就緒。但是實際操作起來並非如此,仍然存在很多需要解決的問題。比如開發的分支模型就涉及到在開發代碼的時,要PUSH什麽分支才能部署,還是PUSH所有的分支都能部署?

三、開發分支模型


當時我們想到最好就是PUSH任意分支都能部署,這樣就非常方便。但隨後就發現這方法行不通,會造成混亂,而且難以管理。此前我們Git的一個The Successful Branch Modeling分支模型就類似於此,此模型規定了一個develop分支、一個feature類型的分支、一個release類型的分支、一個hotfixes類型的分支和一個master分支。
技術分享圖片
在平時開發時,開發人員常常會在develop分支上切出一個feature的分支,比如,開發一個包含很多功能的story,那麽所有人切一個story,這邊story有自己的ID,然後再去開發,把story開發完之後,再把它merge過來。最終,我們只選擇了一條線做CI,當代碼PUSH或者合並到develop分支時,我們幫你去做這個,而在這個feature分支的時候,我們另作處理。

feature分支意味著當用戶提交一個feature分支之後,我們會另外幫你部署一套,每一個feature分支部署一套,相當於每一個story都可以分開獨立去測試,最後把它合並到develop分支。那麽測試的時候,測試可以根據自己的需求來決定它到底在哪一條分支線上去測試。

比如,A測試中如果用戶只關心story A,那就在story A這個分支測試環境去測,這些story全部合並進來之後,再進行一次集中測試,測試通過後,在發布時把這個分支切到release 的一個分支上來,然後,在release上發布正式包,讓QA在STG環境繼續進行測試,就如前面看的那個流程圖。分支模型非常混亂,為了做CI,我們會跟開發人員定義好每一條分支,每個分支對應的每個不同行為也定義好,這在混亂的分支模型下非常有用。

四、版本號規則


為了做CI,版本號的規則必須一致,如果每個團隊版本號命名不一樣的話,匹配規則就會非常麻煩和混亂。後來,我們選擇了Semantic Versioning的一個版本號的規則,就是幾點幾點X,這是一種常見的版本號命名方法,此版本號包含標準的一個文檔,文檔描述了此版本號的具體定義,第一個叫MAJOR,第二個叫MINOR,第三個叫PATCH,後面還可以加各種自己的版本號。
技術分享圖片

五、CI觸發路徑


下面我將介紹我們的CI的觸發路徑——Git push,push到develop分支,Git push就會push到Gitlab的server上,隨後通過webhook去調用Jenkins,Jenkins會把這個包bulid出來。原本我們是想通過Jenkins調用Rancher的API,後來發現直接調用Rancher有差距,過程進行的也不那麽順利,為了解決Jenkins和Rancher之間的gap這一問題,我們在它們之間裝了一個Ponyes的軟件。
技術分享圖片
為什麽需要Ponyes這一中間層?它到底提供了哪些價值?

(1)動態修改版本號

首先,它可以解決動態修改版本號的問題,大家用Rancher的時候,發現Rancher的商店非常好用,我們可以在商店裏把一些東西定義好,接著QA只要填幾個參數,就可以把一個應用部署起來了,沒有Ponyes這一中間層之前,必須找運維人員去做,過程也比較復雜。

為了用起來Rancher應用商店,我們還定義了一個應用商店的模板,這樣我們就可以在每次PUSH代碼的時候,把這個模板生成一個真正可以部署的應用。但是,版本號還是存在一些問題,我們每次PUSH代碼的時候,到Jenkins,我們會根據閱覽數給Jenkins升級一次版本號,比如說1.0.1.0-1,第一次閱覽是-1,第二次閱覽即-2,Jenkins的版本號根據閱覽次數相應變化。這時候應用商店也要隨之而變。

因此,我們做了這樣一個模板,通過這樣一種方式,在Ponyes中,每個Jenkins可以獲得對應的版本號,然後把這個版本號通過變量把它註入進去:

sample:
  image:    {{ REGISTRY }}/automation/auto-sample:{{ m[‘auto-sample‘]}}


這一過程還涉及到registry,因為QA環境和STG環境是完全分開的,在進行模板渲染時,我們需要知道到底是發到QA環境還是STG環境,從而對registry的地址做出相應改變,這樣的話,上面說的修改版本號的問題就解決了。

(2)多service管理

還有一個比較棘手的問題,即一個stack中有多個服務怎麽辦?比如,一個比較小的團隊可能總共就幾個人,每個人負責好幾個項目,與微服務的關系有些相似,那麽一個stack可能有好幾個服務,最典型的就是前端、後端,或者是其他的一些中間件,每一項是一個服務。

開始部署時,Rancher裏面的這些服務也要用一個stack來管理,有多個服務就會面臨怎樣管理的問題。比如,一個stack有ABC三個服務,服務C更新時,整個stack也應該更新版本號,因為在Rancher裏面,stack被部署出來之後,有個update available的黃色按鈕,如果有新版本,點這個按鈕,就可以升級這個stack,而且必須升級整個stack,而不是只升級某個服務,這時候就需要管理多個服務。Ponyes記錄了服務和stack之間的關系,任意一個服務更新,也會觸發stack的更新,更新的方法就是每個服務每次更新,stack的版本號+1。

(3)多版本並行發布

接下來還有一個更嚴重的問題,如果多版本並行發布,我們應該怎麽去處理?比如說我們ABC三個模塊,A發布過1.0和2.0,B發布過3.0、4.0,C發布過5.0和6.0。如果發布一個C應用的5.0.2,那麽對應的AB模塊號應該選什麽,這個問題困擾了我們很久。

有好幾種方法可以解決,比如用某個東西記錄C5.0和AB的一個版本號之間的關系,這表示用戶可以自定義。但也存在一個問題,用戶需要自己去管理它們之間的版本號關系,時間長了,可能會弄亂或弄錯版本號,或者弄錯版本號之間的關系,隨後上線到生產環境,後果更嚴重。

還有一種方法,就是將用戶的C版本號最後一次發布到5.0時AB是什麽版本靜態地記錄下來。但這樣的話系統會變得相當復雜,很容易出錯。

最後,我們選擇去除多版本並行發布的能力,只支持單個版本的發布,意味著如果要發布,必須是最新版本,歷史版本可以用另外的方法進行人工處理,這樣的話,系統會更簡單,而且不容易出錯,也不需要用戶去維護一個版本號之間的關系。以上這些功能都是借助我們自己寫的Ponyes解決的。

Rancher 2.0也提到了CI/CD這樣一個功能,在實際過程中,會遇到一個非常現實的問題,從代碼研發到整個生產環境部署有許多環節,具體情況也非常復雜,而CI的作用可能僅止於QA,後面的環節還會有新的難題,這時就需要一個體系把整個生命周期貫穿起來管理,Rancher承擔的作用就在於此。

六、肉身踩坑總結的三條經驗


(1)部署幾套Rancher環境?

這問題看似很小,最初也在我們內部也引發過不少討論。最初我們只部署了一套Rancher,在Rancher裏面用環境去區分QA或production。部署一套Rancher的方式最簡單,但是有一個嚴重的問題:Rancher升級了怎麽辦?這套Rancher既管了QA,又管了production,升級的時候需要把生產環境也升級,此刻如果出現bug,問題將非常嚴重。

後來我們把它拆成四套,Rancher平臺本身也得有一個升級的環境。建議大家在前期部署Rancher的時候要部署多套環境(至少兩套),我們實際上是dev、QA、staging、production每個環境都有一套,總共四套。

(2)配置項爆炸

第二個問題是關於配置項。我們最開始是使用Rancher compose的,它非常簡單強大,我們在Rancher Catalog裏點一下“部署”,配置選項全彈出來,我們只需要點選一些東西,就可以部署一個很復雜的應用。後來我們卻發現,應用的配置項越來越多(甚至多達上百個)。這導致它們難以在一個頁面裏展現,同時上百項的配置讓我們無從填寫,運維也無法成功部署,我們從而面臨了配置項爆炸的問題。

我們的解決經驗是,在容器平臺裏面,配置項一定要集中管理。我們把配置項全部用consul管理,每次容器啟動時到consul裏把配置拉到對應的容器裏來。如此一來,容器可以在任意平臺漂移。另外配置項本身在原server存有副本,我們copy原配置項加以修改,就可以部署另一個實例了。所以說,配置項一定要全部集中管理起來。

(3)泛域名+Rancher LB

我們每一個業務都有一個web服務,要申請自己的域名。每年我們有上百個項目上線,這意味著有上百個域名要申請。加上這些域名都分別需要在開發、測試、生產環境中使用,所以我們每年要申請將近五百個域名。這是一件恐怖的事情。

後來我們就用了泛域名的方法。比如用.sub.example.com的域名,直接CNM到Rancher環境中的其中一臺主機。然後在Rancher上設置它的LB,LB就可以分布在所有的主機上,每個主機上都會有同樣的LB。這個域名任意指向一臺主機,它都可以工作。

比如說,在QA環境,這個LB上serve了如下這些域名,若主機壞掉了,容器本身會啟動,入口問題則可以很簡單地通過修改量來搞定。如果是生產環境則可以在上面再加層nginx,配三個upstream,死掉任意一臺,還可以通過另外兩個入口進來。

使用泛域名的方法,在配置好泛域名之後,在Rancher LB上再加任意域名都不用再去申請新的域名,而是可以直接寫123.sub.example.com,然後直接在LB上配置,配完之後域名即可用,無須再走申請的流程了。

通聯數據是如何使用Docker+Rancher構建自動發布管道的?