1. 程式人生 > >如何做好持續整合——Jenkins on Mesos 實踐

如何做好持續整合——Jenkins on Mesos 實踐

首先講一下持續整合的優勢。過去公司做測試可能需要十幾、二十幾個元件,整合一次往往要一兩個小時,費力費時,而且複雜容易出錯,而一旦配置出錯的話耗時會更久。因此,一次整合測試一週才會做一次,測出Bug要到下一週才能更新,再做測試,這個週期會非常漫長。而持續整合的意義就在於減少風險,和重複的過程,最終提高工作效率。

Docker

Docker是現在非常火的一門技術,使用Docker首先解決的是環境的問題。因為開發環境和運維的部署環境千奇百怪,依賴的環境和包各不一樣。其次,Docker是可以實現更快速地交付和部署,只要寫一個Dockerfile,把服務打成一個映象,然後再遷移到各種伺服器上就行了,部署的過程也非常方便,伺服器只要有Docker的環境就可以執行。因為是核心級虛擬化解決方案,Docker利用的額外資源很少,同時,它的更新管理也非常容易,只需要把Dockerfile修改一兩行,其他的伺服器則不需要做改動,也不需要下載其它的安裝依賴包,打好Docker映象直接就可以部署映象、直接執行。這些都是它的優勢。

Mesos

圖片描述
Apache Mesos是一款開源叢集管理軟體。Mesos經過了Facebook,Twitter這些大型公司的萬臺主機驗證,在國內,愛奇藝、去哪網,小米網等公司也擁有大規模的Mesos叢集應用。Mesos實現了兩級排程架構,可以管理多種型別的應用程式。第一級排程是Master的守護程序,管理Mesos叢集中所有節點上執行的Slave守護程序。叢集由物理伺服器或虛擬伺服器組成,用於執行應用程式的任務,比如Hadoop和MPI作業。第二級排程由被稱作Framework的“元件”組成。Framework包括排程器(Scheduler)和執行器(Executor)程序,其中每個節點上都會執行執行器。Mesos能和不同型別的Framework通訊,每種Framework由相應的應用叢集管理。圖中只展示了Hadoop和MPI兩種型別,其它型別的應用程式也有相應的Framework。Mesos支援多種Framework,比如說Hadoop,Spark,Storm等等,各型別的Framework在它上面都可以執行。

Marathon

Marathon是Mesosphere為Mesos生態圈打造的一個輕量級管理服務APP框架,它可以用RESTful API方便地進行操作。

Marathon 協調應用和Frameworks

下圖是在Marathon上釋出各種的服務,它們都可以通過Marathon發到Mesos的叢集資源中。

圖片描述

擴充套件和故障恢復

例如我們發了三個服務,分別是有一個節點的,三個節點的和五個節點的。

我們想拓展這些服務的話,可以呼叫Marathon的API進行擴充套件,秒級擴充套件到下圖。

如果有一臺主機宕掉了, Marathon會均勻地把服務遷移到其他的機器上,選擇資源有空餘的機器進行遷移。這樣能就保證服務是動態的排程,保證服務的高可用,並且這些都是它內部自行處理的,不需要手動干預。

Jenkins

介紹

Jenkins是Java開發的一種持續整合的工具,我們在它的基礎上做了一些重複的工作,比如版本釋出、測試程式碼,以及呼叫外部介面。Jenkins支援很多外掛,可以很方便地選擇使用適合自己團隊的外掛工具。

問題

Jenkins為我們提供了便利,當然Jenkins本身也有它自己的問題,比如傳統的Jenkins是單點的,任務大多是需要排隊的,如果每個任務都自己建一套Jenkins的話,資源會非常浪費。為了解決這些問題,我們引入了Jenkins On Mesos。

Jenkins On Mesos

Jenkins 分為Master 節點和Slave 節點,Master 進行排程,Slave節點負責負責執行Job任務。

Jenkins master

圖片描述

首先我們把Jenkins的Master通過Marathon釋出,Marathon 去呼叫 Mesos Master,之後Mesos Master再去Slave節點起Jenkins的Master。這個機制保證了Jenkins Master的高可用,Marathon會監控Jenkins Master的健康狀態,當Jenkins Master出現崩潰掛掉,Marathon會自動再啟動一個Jenkins Master的任務。Jenkins Master使用Mesos整個大的資源池,Mesos的資源池是一個資源共享的狀態,資源利用率也會更高一些。

Jenkins Slave

圖片描述

Jenkins Master做的是排程,Jenkins Slave則是真正執行構建任務的地方。Jenkins Master會在Mesos Master上註冊一個它自己的Framework,如果有任務需要構建的話,Jenkins Master 會通知 Jenkins Framework 呼叫 Mesos Master構建一個任務。之後Mesos Master 再呼叫 Mesos Slave去起一個Jenkins Slave的節點去構建任務,它是實時的,使用者資源可能被分配到各個機器上,在不同的機器上並行存在。此外,Jenkins還具備動態排程功能,也就是說,當任務執行完後一定時間,資源會再返還給Mesos,實現合理地利用整個叢集的資源,提高叢集的資源利用率。

Mesos 整體流程

圖片描述

這張圖是Mesos整體的排程流程。第一步,它的叢集有三個Mesos Slave節點資源,資源上報到Mesos Master,Mesos Master收集到這些資源之後把這些資源再提供給Marathon,Marathon如果要發任務,它確認一個Offer1,Offer1足夠任務來執行,就拒絕其他的Offer,並把這個任務傳送給Mesos Master,之後Mesos Master去找Slave1起Marathon的任務。這是Marathon的任務啟動過程。Mesos本身可以和多框架進行通訊,Jenkins Master要跑一個任務,Mesos Master同樣提供資源給Jenkins,提供的資源包括了Marathon 任務使用剩下的資源,比如Task1 確認的 Offer1沒有用完和沒有使用的資源,Mesos也會它提供給Jenkins。而Jenkins也會選擇,比如Jenkins選擇了Offer3,拒絕了其他的Offer,把Jenksin的任務再通過Mesos Master去Mesos Slave中起起來。

Jenkins On Mesos Docker化

Jenkins部署起來非常麻煩,需要安裝各種依賴,如果程式碼是從Git上下載的,那麼還需要安裝一些Git包。而動態排程需要每臺機器上都裝這些依賴,為了解決這種問題,我們把服務全部進行了Docker化,主機上只需要有Docker環境就可以執行我們的服務。

遇到的坑

進行Docker化之後就會面臨Docker化的問題,因為Docker和 Mesos都是比較新的技術,我們遇到了很多坑,也需要去解決。

我們遇到的第一個問題是Jenkinson Mesos需要排程Mesos的Lib庫,如果Docker化之後是隔離的,就調不到Mesos Lib。

第二個問題是Docker化的資料,因為Jenkins是沒有資料庫的,資料都是存在本地的JENKINS_HOME目錄中,如果Jenkins Master掛掉之後,相應的資料就沒有了。

第三個問題是Jenkins需要升級,外掛也需要升級,而映象本身沒辦法自動升級。

解決

為了解決這些問題,首先我們將Mesos打成一個基礎映象,在這個基礎映象上安裝Jenkins的服務製作成一個Jenkins的映象,這樣就可以呼叫Mesos的Lib庫檔案了。

第二是資料備份,我們在Jenkins上安裝了一個外掛,就是SCM Sync Configuration Plugin 這個外掛,它會同步資料到Github。如果這個Jenkins Master掛掉了,遷移到另外一臺主機上,它會從Github上面把資料克隆下來,資料是不會丟失的。此外,如果外掛出了故障,或者因為網路問題導致Github訪問不了,我們把JENKINS HOME目錄掛在主機上進行備份,進行恢復的時候也會很方便。用以上這兩點來保證資料的完整性。

第三對於Jenkins升級或其外掛的升級,我們現在的做法是把它重新打一個映象,重新在Mararhton釋出Jenkins Master。

Jenkins Slave On Docker 工作流程

圖片描述

首先Jenkins Master如果要構建一個Job,讓Mesos Slave起一個Jenkins Slave這樣的容器,容器裡面是沒有Docker環境的,因為容器裡面再裝一個Docker環境就太重了。我們現在的做法是把Jenkins Slave用到的命令掛載,其中包括 /usr/bin/docker /var/lib/docker /sys/fs/cgroup /var/run/docker.sock ,這樣在容器內部就可以操作主機上的Docker環境,Jenkins Slave 可以在容器內部進行一些Docker Build,Docker Run,Docker Push等工作。

Jenkins Job List

圖片描述

這是我們運維平臺一些Job List,左下角是Mesos各個Slave的節點,每一個節點上都有任務,這些任務都是並行的。因為我們的服務模組比較多,可能一個模組一天提交十幾次,這麼多的模組在一天提交幾十次或者上百次的情況也出現過。手動更新、構建的話是非常難做到的。現在,做成Jenkins 分散式執行Job的模式,一天構建幾百上千次也沒有問題,它會把構建的任務均勻的分佈在主機資源裡。

數人云運維平臺持續整合實踐

圖片描述

這是數人云運維平臺的持續整合實踐。首先講幾個元件,比如Github,它是儲存程式碼的,第二個元件是我們自己開發了的一個Configserver的API,第三個元件是Jenkins和Marathon。第四個元件是我們的私有Registry,是Docker的一個儲存映象的映象倉庫。最右下角是CDN,安裝包傳送到達的地方。

首先Jenkins觸發任務,Jenkins呼叫Configserver提供的API,這個API就去Github上獲取最新程式碼的Tag,並對比現有的已經更新過的Tag。如果不需要更新,這個任務就完成了,結束了。如果需要更新的話,就進行第三步,把從Github拉的程式碼放到Configserver上,Jenkins Slave的節點會從Configserver去拉取程式碼到Slave的容器之中。把程式碼下載之後再去Pull一個我們編譯環境的映象,然後再用這個映象去編譯我們的程式碼。比如編譯出來一個二進位制程式碼,我們把這個二進位制重新打一個執行時的映象。這個Runtime映象打好之後我們再使用Docker Push把它推到私有的Registry,映象Push到Registry後,就可以釋出到各種的環境,比如說Dev Demo生產環境,呼叫Marathon API直接釋出就可以了。同樣在Jenkins Slave,推完映象之後就可以去呼叫。這樣一個整體構建映象再部署的任務就構建完成了。

如果有一些安裝包,比如我們的Agent包,它不需要釋出Marathon,需要上傳到CDN,也是在Jenkins Slave 中執行的。

配置管理

問題

因為我們引入了Docker,而且是分散式動態排程的,傳統的配置工具如Ansible、Puppet 、SaltStack都已經不適用了,沒辦法去管理Docker內部的東西。這些配置檔案修改起來非常麻煩。

配置中心一期

圖片描述

講一下如何進行配置的更新。首先我們做了一個配置中心的一期,把映象嵌入自己的指令碼,這個指令碼實現的功能就是 根據傳入的ENV CONFIG_SERVER和 SERVICE ,訪問 Configserver的API,API返回的資料就是這個服務需要下載的配置檔案的列表,以及它需要下載到哪個目錄底下。Configserver也非常簡單,起一個Nginx,去Vim手動修改。容器一重啟,就會自動拉這些配置檔案,把配置進行更新。

一期的問題

一期完成之後,因為是多種環境,如Dev Demo環境、預生產環境、生產環境等等,雖然把這些配置都在Configserver上集中配置,但還需要手動修改這些配置。手動修改容易出錯,例如Dev更新了一個服務,可能過了一週才會更新到生產環境。那個時候再去修改生產就很容易出錯,導致無法執行。此外,如果配置發生了Bug需要回滾,手動修改也是不合適的。

配置中心二期

圖片描述
為了解決這些問題,我們做了ConfigCenter的二期。其中有我們自己開發的一個運維平臺,以及Github和Gitlab。Github是個儲存專案的程式碼,Gitlab是用了儲存配置模板和最終配置檔案的。我們用Jenkins把它們整體的串起來,我們的第一個工作是把所有的配置檔案抽象化,各種環境的檔案抽象出來一個模板,放在Gitlab上。它的資料是放在資料庫裡面,這樣組合起來是一個完整的配置檔案。各個環境的值是不一樣的。 我們的運維平臺觸發Jenkins,Jenkins去排程我們的ConfigCenter API,它傳入兩個引數,一個是需要更新的環境,第二個是更新哪個服務。之後API去做對比,從資料庫去讀現有的配置檔案的模板Tag,再去讀新模板的Tag進行對比。如果這個檔案需要更新,把它從資料庫拉過來,資料做匹配,渲染成我們最終的配置檔案,再傳到Gitlab上。剩下的通過Jenkins 觸發 Configserver去調Gitlab下載最新的配置檔案到Configserver伺服器,Jenkins再去呼叫Marathon去重啟服務,服務就會成功更新配置檔案。

這裡有兩個需要注意的點,一方面模板需要更新,另一方面值要更新,這是兩種模式。模板更新是所有的流程都要走一遍,如果模板沒有更新,只是值更新的話,我們只需要在運維平臺上做修改。修改的同時它會做一個標記,說明這個服務配置檔案是需要更新的,之後就會生成一個最新的配置繼續下面的操作。如果這兩個都不需要更新的話就返回,不再操作。

本文來自數人云運維工程師劉金燁在CSDN學院的演講實錄分享整理