中興軟創(ZTEsoft)基于Jenkins和Docker的CI實踐

jopen 9年前發布 | 120K 次閱讀 Docker

本次分享從四個方面展開:基于Jenkins的CI過程、基于Docker的應用發布、基于Dubbo的跨主機的容器連接、困難與展望。

基于Jenkins的CI過程

一切要從2013年4月開始說起,當我4月份從委內瑞拉回來之后立即投身到國內一個運營商的大型后端建設 項目的尾聲中(項目歷時3年多,當時已經接近尾聲),這個項目涉及100多臺主機,包含數十個集群,除了傳統的WEB應用外,還用到了流程引擎、ESB、 規則引擎、搜索引擎以及緩存和日志,是當時比較復雜的體系結構(當然不能跟現在的云平臺相比,但在項目開始的年代這還是一個很不錯的架構),整個項目當時 一兩百號人占了局方整整一層樓十幾個辦公室。

我到了項目組之后成為了一個小組的小頭目,管個四五個人,小組美其名曰“平臺組”,干的都是打雜的事情,包括編譯、打包、部署,日常監控以及系統 優化等工作,說起來簡單,做起來還是很復雜的,當時所有的工作基本上是靠人工的,可想而知,100來臺機器的環境一臺一臺的部署環境,還得靠人工監控,手 工檢查,四五個到處救火忙得不可開交,當時我雖然還不知道CI為啥物(壓根兒就沒這個概念),但也下定決心要改變忙亂的狀態,累一點不要緊,但是累得跟狗 似的還干不好那就白辛苦了。

在2013年的4~8月份,我們主要研究的是自動編譯、打包和發布,采用的基本方式是各種腳本,包括windows下的批處理bat、Linux上的 shell甚至Python,雖基本上完成了自動從SVN取代碼、自動編譯、自動打包以及將應用發布到WebSphere上的這些工作(如下圖):
中興軟創(ZTEsoft)基于Jenkins和Docker的CI實踐

但也明顯存在一些問題:

  1. 自動執行靠的是Windows任務計劃,執行過程、執行情況只能通過檢查腳本執行時寫的日志文件,不直觀。
  2. 代碼只作了編譯,沒有做代碼走查,對代碼質量的提升作用不大。
  3. 發布過程利用IBM提供的wsadmin腳本,只能進行全量的發布,發布過程較長。
  4. </ol>
    9月份之后,項目基本穩定后我也離開了項目現場,但自那之后對這塊工作更加著迷,我從項目現場回來之后也組建了一個科室,還是四五個人,當時我查閱了一些資料,尤其是看到了一本書《 持續集成,軟件質量改進和風險降低之道》, 從此學到一個名詞:CI(持續集成),一發而不可收拾,逢人就鼓吹CI。我組織科室人員一起研究了CruiseControl、Apache Continuum、QuickBuild、Hudson等業界CI常用工具,最后決定以Hudson為框架來逐步實現CI.。一早采用的是 Hudson,后來為便于作二次開發切換到其社區版本Jenkins上。

    Jenkins提供了一個管理界面,并且有豐富的第三方插件,支持定時任務,支持從SVN取代碼,支持Ant編譯和Maven編譯(我們產品編程 框架逐漸從ANT轉向maven模式),支持向tomcat、JBoss、Weblogic和WAS發布應用(Jenkins的WAS插件不支持集群模 式,我們仍然沿用了wsadmin腳本),支持用PMD、Checkstyle、findBugs進行代碼走查并以圖形化方式展現走查結果(包括趨勢圖和 結果詳情),支持調用Windows批處理bat、Linux的Shell等。

    在采用Jenkins框架的基礎上,我們作了一些二次開發,實現了:

    1. 根據任務單增量從SVN取代碼(有一些奇葩的項目現場要求挑任務單升級,因此我們修改了jenkins的svn插件以支持這種需求)。

      中興軟創(ZTEsoft)基于Jenkins和Docker的CI實踐
      </li>

    2. 支持增量編譯(采用兩個Jenkins的JOB,一個做全量編譯,作為首次編譯并產生一個jar包給增量編譯使用,此全量編譯JOB只 使用一次;另一個JOB就引用全量JOB產生的jar包,只對變更(或新增)的代碼編譯產生class等文件,并將它們按部署目錄放好以便于作增量發布, 同時將這些class文件再打入到全量JOB下的jar包中以備下次增量編譯使用)。
    3. 支持增量發布,通過調用lftp腳本實現快速的應用部署(在比較了cwRsync、unison、wget、lftp、ftpsync、csync、Syncrify、DeltaCopy、tar、bacula等工具后,最終lftp勝出,我們采用:lftp -c 'open -e &quot;mirror --allow-chown -x vssver.scc -R --parallel=10 --use-pget-n=10 --log=%LOG_FILE% %LOC_DIR% %REMOTE_DIR%&quot; sftp://%USER%:%PASSWORD%@%IP%'
      這樣的腳本來進行增量發布,將編譯后的結果與部署環境上的進行自動比對更新)。
    4. 支持基于Ant和基于Maven的代碼走查,編寫Ant 腳本和Maven腳本以支持PMD、Checkstyle、findBugs進行代碼走查(由于jenkins中代碼走查插件生成界面時會消耗大量系統資 源,對機器性能影響很大,后面我們改成了通過腳本方式生成并將走查結果打成壓縮包發郵件給相關人員)。
    5. 支持基于Maven的代碼的單元測試(采用TDD編碼方式)。
    6. 支持自動化測試(調用ZTP,ZTP是我司自產的一個自動化測試工具,支持自動化腳本錄制、回放等工作,其工作原理與robotframework比較類似,ZTP工具支持批處理腳本調用,故可以集成到jenkins中)。
    7. </ol>
      當時,我們還想在Jenkins上集成更多的功能,包括:

      1. 改進websphere-deploy插件,支持界面部署WebSphere應用包(這個計劃后面擱淺了,主要是腳本方式已經能支持絕大部分WAS集群的部署了)。
      2. 應 用環境遷移,通過將應用環境遷移過程自動化為Jenkins中的任務,實現應用環境遷移過程的自動化和可視化(目的就是想實現研發、測試及生產都是一套環 境,測試通過后的環境能直接遷移到生產上去,當時只是做運維的一種本能的想法,但也由此引發了對Docker的關注)。
      3. 與業務監控系統 相結合,形成流程化的跨多個Jenkins任務的、整體的應用環境部署自動化和可視化,為將來生產環境部署的自動化和可視化作準備(曾經研究過一段時間 jenkins的FLOW插件,當時FLOW插件的版本還比較低,功能還很弱,引入第三方的工作流工作量會比較大,而事實上這種流程化的編譯部署過程實用 性也比較低,這事就慢慢擱淺了)。
      4. </ol>
        目前我所在的產品線所有的項目都已經采用Jenkins進行編譯、打包、代碼走查及自動部署到測試環境和準生產環境(運營商項目的生產環境發布后面會逐漸由我司自主開發的另一利器“云應用管理平臺”來支持,后面還會講到)。

        基于Docker的應用發布

        前面講了,關于應用環境遷移的想法引發了我對Docker的興趣,實際上這時已經是2014年的6月份了, 于是就跟一些同事自學鼓搗一下,當時Docker 1.0才剛剛發布,當時也就把官網的例子都做了一遍,參考官網作了Hadoop的鏡像,自己又作了WebSphere的鏡像,搭建了Registry,斷 斷續續的作了一些東西,算不上很深入,而Docker本身也在不斷發展,感覺隔幾天就有一個新版本發布出來。

        Docker大潮來勢洶涌,到9月份的時候,我一開始說的那個巨大項目的運營商中有個技術專家提出了要用Docker來作應用發布平臺,當時簡直 是不謀而合,于是有了一個項目,也就可以明正言順的進行Docker研究了,不過既然已經是一個正式的項目了,那光有幾個愛好者是不夠的,需要有正規軍 了,于是請出了公司技術委員會下屬的一個研發團隊,大約有六七人,也就是“云應用管理平臺”的開發團隊,一起進行相關的研究。給生產環境用的發布平臺跟我 們前面講的用jenkins作的自動部署還是有些不同的,生產環境上版本的發布一般是有嚴格限制的,包括版本要求、時間要求(升級時間、故障率和故障解決 時間)等,這一點是與現在的互聯網企業升級自家的系統是完全不同的。

        “云應用管理平臺”圍繞著Docker進行了大量的開發工作,制作了主機管理、容器管理、集群管理、版本計劃管理、版本執行管理等等,其架構如下圖:

        中興軟創(ZTEsoft)基于Jenkins和Docker的CI實踐

        1)Jenkins打包鏡像

        • 自動獲取SVN代碼版本
        • 使用Dockerfile打包鏡像,并自動上傳到Docker Registry。
          中興軟創(ZTEsoft)基于Jenkins和Docker的CI實踐
        • </ul>
          2)集群配置

          • 應用基本信息配置
          • 集群應用綁定
          • 環境變量配置
          • 固定端口號配置
            中興軟創(ZTEsoft)基于Jenkins和Docker的CI實踐

            中興軟創(ZTEsoft)基于Jenkins和Docker的CI實踐

            中興軟創(ZTEsoft)基于Jenkins和Docker的CI實踐
            </li> </ul>
            3)制定發布計劃

            • 選擇鏡像版本(Docker Registry API獲取鏡像列表)
            • 選擇主機,并設置啟動的容器實例數
              中興軟創(ZTEsoft)基于Jenkins和Docker的CI實踐
            • </ul>
              4)執行發布計劃

              • 使用Docker Java API連接docker daemon啟動容器
              • 記錄容器ID
                中興軟創(ZTEsoft)基于Jenkins和Docker的CI實踐
              • </ul>
                5)容器管理

                • 主機檢測(能檢測主機上是否安裝了docker,如果沒有可以自動安裝Docker)
                • 容器節點增加、縮減,用戶選擇的應用鏡像版本和實際運行版本一致時執行伸縮
                • 容器狀態監測
                • </ul>

                  基于Dubbo的跨主機的容器連接

                  一開始我們在測試環境上將所有容器都放在一臺主機上,測試過程很順利,但在移到準生產環境上 時,由于要模擬生產環境只能將容器部署到不同的主機上,這時候就發現了一個奇怪的現象,應用之間調不通了,這里要說一下,我們應用程序是由20多個服務組 成的、通過Dubbo【阿里提供的一個服務框架】作為服務總線串連起來的,Dubbo提供了一個方便的服務發現機制,各個服務(稱為服務提供者)只要向 Dubbo注冊中心注冊過,注冊中心就會將服務的地址發送給同樣在注冊中心注冊的服務調用方(稱為消費者),之后即使dubbo注冊中心掛了也不影響服務 的調用。

                  中興軟創(ZTEsoft)基于Jenkins和Docker的CI實踐

                  當服務提供者部署在容器中時,這時候發現其在Dubbo中心注冊的是容器的IP地址,而對處于另一個主機上的消費者來說這個IP是不可訪問的,我們當時也參考了多種方式,想讓消費者能夠連接上服務提供者的IP,查閱資料總結起來大概有兩種做法:

                  1. 設置容器的IP與主機IP在同一網段內,使容器IP可直接訪問【會占用大量的IP地址,且IP會限制在同一網段,在生產環境中往往不可能】。
                  2. 通過復雜的iptables路由規則,通過多層橋接方式打通網絡【此法是可行的,也是我們今后要考慮的,但當時一堆開發人員對網絡這塊都不是太熟悉】。
                  3. </ol>
                    考慮到當時公司技術委員會下屬另一個研發團隊正在做dubbo的研究和改造,于是拉他們進來討論,結果他們說這個很容易解決,由于主機之間是連通 的,而容器在創建時也映射了主機和端口,只需要在服務注冊時注冊的是映射的主機IP和端口就可以連通了,該研發團隊的效率很高,討論的當天就給出了實現, 考慮到局方要求嚴格管理容器和主機間的映射,我們將主機IP和端口作為環境變量在容器啟動時傳入【擴展了dubbo protocol配置,增加了兩個配置項 publish host、 publishport,對應主機的ip port,并且在注冊服務時將主機的ip port寫到注冊中心】,果然解決了這個問題。

                    當然這是一種特殊情況下的跨主機容器連接方式,更為普遍的方式目前我們正在討論當中,基于ovs的連接方式是正在考慮的一個方案。

                    困難與展望

                    目前我們對Docker的使用還比較初步,雖然基本滿足了項目的要求,但考慮到將來云平臺要求自動擴展、服務發現,這些還有待我們進一步研究。

                    Q&A

                    Q:你好,問一個問題,我們前段時間也把Dubbo框架運行在Docker里面,也是采用你們現在的把宿主機和端口作為環境變量傳入的方式實現的,我比較想了解的是后繼你們有什么更好的方式實現,我看你提到了基于OVS的方案?

                    A:有兩種解決辦法:

                    1. 一種是將顯式傳遞環境變量做成隱式的自動獲取宿主機和端口,從而減少配置工作;
                    2. 另一種則是通用的Open vSwitch(OVS)方案,這是與Dubbo無關的。
                    3. </ol> </blockquote> Q:容器中的Dubbo注冊問題,擴展Dubbo的protocol配置,增加publishhost和publishport解決了注冊問題,能不能說的詳細一點?

                      A:目前我們硬編碼了Dubbo的protocol,在里面加了兩個字段,這種擴展方式有點野蠻,但Dubbo本身提供的擴展方式目前很難支持傳遞環境變量方式,我們在考慮將環境變量隱式獲取,這樣就不用硬編碼了。
                      Q:你們用的還是端口映射吧,那么也會存在很多個端口的問題吧,像IP可以訪問一樣?

                      A:在這個項目中作端口映射是運營商的要求,他們要求能通過配置來設置每個容器的端口映射,這與他們現有的運維方式有關,一開始我們考慮的是docker的自動端口映射,當然這種需求將來肯定是趨勢,我們的“云應用管理平臺”中也有考慮。
                      Q:為何考慮Dubbo而不是etcd做服務發現,Dubbo的優勢是什么?

                      A:選中Dubbo是很偶然的,公司本身有ESB產品,但相對來說比較重,一般用于多個產品間的調用,而Dubbo我們一般用于 產品內部多個模塊之間的調用,是一種輕量級的服務總線,Dubbo這種方式不依賴于硬件和操作系統,etcd并不是所有操作系統都能支持的吧,當然我也沒 有對etcd作深入的研究。
                      Q:Jenkins的slave是選用了虛擬機還是直接物理機?

                      A:我們的Jenkins的master和slave都是用的虛擬機。
                      Q:代碼提交上去,如果測試有問題,回滾是腫么處理,也是通過Jenkins?

                      A:這里要分情況來說,一種是測試發現問題,提單子給開發修改,開發修改完代碼提交到scm,然后觸發Jenkins下一輪的編譯和部署;另一種情況是如果某次部署失敗,則會用部署前的備份直接還原。
                      Q:請問用的Registry V1還是V2 ,分布式存儲用的什么,有沒有加Nginx代理?

                      A:目前我們用的是V1。生產環境多是集群環境,需要加Nginx作分發。目前應用中分布式存儲用的并不多,一般來說用hdfs來存儲一些日志便于后面分析,也有用FastDFS和MongoDB的。
                      Q:底層云平臺用的是私有云?

                      A:底層平臺一開始想用私有云,但運營商已經有了vCenter的環境,因此后來我們改用Ansible來管理各類物理機和虛機,用Docker API來管理容器。
                      Q:Dubbo實現的服務發現是否具備failover功能,自動檢測并遷移失敗容器?

                      A:Dubbo目前不具備遷移容器的功能,其failover是通過負載均衡和心跳連接來控制的,自動檢測和容器遷移我們一般會考慮放在監控系統里面來做,如果放在Dubbo里面會加重Dubbo,只所以用Dubbo也是考慮到它的輕便性。
                      Q:能否談下對Jenkins+Mesos的看法,這個涉及到docker-in-docker的必要性?

                      A:Mesos我們才剛剛接觸,我了解的不太多,至于docker-in-docker我覺得生產上很難用,因為性能方面損失比較嚴重,我們做過性能測試,非--net=host方式的容器性能損失接近30%。
                      Q:能具體介紹下利用Dockerfile打包鏡像嗎,jar包也是在這一步編譯出來的嗎,這樣發布出去的鏡像會既包括代碼又包含jar包吧?

                      A:我們的鏡像中是不包含代碼的,鏡像里面是產品包,編譯是在打鏡像之前做的。
                      Q:對不生產環境中不適合以容器運行的組件,Jenkins+Docker是否就沒有優勢了?

                      A:開發和測試環境還是很有優勢的,當然有些有大量IO操作的服務其實不適合放在容器里面,這主要是性能方面的考慮。
                      Q:云平臺是怎么管理容器的,有沒有使用Docker生態系統相關的組件?

                      A:目前沒有用到Swarm\Compose之類的組件,將來要看這塊的發展了,也有可能會引入k8s或者Mesos來作管理,這些目前都在考慮當中 。
                      Q:在怎么判斷部署Docker服務不可用,不可用后自動遷移還是如何操作?

                      A:目前云應用平臺只在發布時才對Docker容器進行狀態檢測,如果檢測到失敗,會根據指定的容器數目進行重新創建。后續我們會把對容器狀態的持續檢測統一放到監控系統中。
                      Q:我是不是可以這么理解,你們的Jenkins是主要用來CI,而實際集群管理則是云應用平臺做的?

                      A:是的,這個是嚴格分工的,當時作云應用管理平臺時,是以測試交付物為起始點的,這里的測試交付物就是CI的產物,容器方式下就是鏡像了。
                      Q:我可以理解Docker是部署在實體機,實體機上都有一個agent的東西負責與管理端通信,主要負責Docker的管理(安裝,部署,監控等)嗎?

                      A:我們的Docker目前都是部署在虛擬機上的,操作系統是Redhat 7.1,你所謂的agent其實應該就是Docker daemon吧。
                      徐新坤:這個我補充一下,作為Jenkins的slave,會向slave里面啟動一個agent來執行相關腳本命令的。這個屬于Jenkins的功能,可以去體驗下。
                      Q:一個應用多個容器你們怎么負載均衡?

                      A:前面其實回答過,要加Nginx的。
                      Q:利用Dockerfile打包鏡像并上傳到Registry更像是CD環節的事情,那在單元測試、集成測試環境是否有利用到Docker呢,是否使用Jenkins中Docker相關的插件了?

                      A:當前項目的單元測試、集成測試都用到docker容器的。Jenkins中沒有用Docker插件,試過感覺都不太成熟,目前還是Docker命令行最方便。
                      Q:開始的時候有講如果沒有Docker自動部署會自動部署,這個是如何部署的?

                      A:這個前面講過,是通過lftp腳本比對編譯環境與待部署的遠程目錄。
                      Q:也就是你們在虛擬機里面部署的Docker?

                      A:是的,當前的項目是在虛擬機里面部署Docker的,但我個人觀點從長遠看來,其實在物理機上部署Docker會更好,所以現在很多私有云比如OpenStack、CloudStack都能支持直接管理容器,不過目前虛擬機還是不能缺少的,容器的隔離性不如VM。
                      Q:如果用nat模式 容器如何指定IP啊?

                      A:不需要指定容器IP,只需要映射端口。
                      Q:有通過Dubbo做服務路由么?

                      A:Dubbo本身就有服務路由的功能。
                      ===========================
                      以上內容根據2015年10月20日晚微信群分享內容整理。分享人 方進,ZTEsoft資深工程師,十多年間從事過研發、測試、集成、技 術經理、項目經理、架構師和產品經理等各種崗位,不忘初心,始終懷著對技術的渴望和追求,不斷追逐新架構新技術,推行CI改善研發流程,推進云化應用部署 與自動化運維,近期對容器化比較癡迷,如獲至寶,希望能盡早在生產中使用起來,為此借DockOne群與大家分享心得,互相學習。 DockOne每周都會組織定向的技術分享,歡迎感興趣的同學加微信: liyingjiesx,進群參與,您有想聽的話題可以給我們留言。

                      來自: http://dockone.io/article/753

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!