當前位置:
首頁 > 最新 > 利用 Jenkins Pipline 來編排 DevOps 工具鏈

利用 Jenkins Pipline 來編排 DevOps 工具鏈

講師 | 林栗

編輯 | 黃曉軒

講師簡介

林栗

Micro Focus DevOps工程師

擅長組織級持續集成架構設計與實施,專註於軟體配置管理、DevOps 領域十餘年,對 CMMI、Agile 與 DevOps 有切膚之體會與感人之經驗,依然樂此不疲的自我迭代中。

前言

我今天跟大家分享的話題是:利用 Jenkins Pipline 來編排 DevOps 工具鏈,把我們的產品部署到任何地方。主要內容分成三塊:

第一個我會簡單介紹一下我們公司的敏捷和 DevOps 轉型;

第二個簡單介紹一下 DevOps 工具鏈;

第三個重點是以 Jenkins Pipline 為核心,怎樣實施一個以微服務架構為基礎的,以 Kubernetes 為部署方法的持續集成和持續部署的話題。

敏捷和 DevOps 轉型

開始之前我先簡要介紹一下我們是誰,我們是幹什麼的。Micro Focus大家會比較陌生,但惠普大家都聽說過。不久前2017年9月1日,原先惠普的軟體業務跟來自於英國的 Micro Focus 公司進行了合併,於是江湖上就誕生了一家新的公司。

兩家公司的歷史都非常悠久,最早可以上溯到1939年,在慢慢歷史長河裡面,如果用三個字概括一下公司的話就是「買買買」,一路上買了很多的軟體。

最終形成了混合 IT、DevOps、安全風險以及預測分析這四大領域非常豐富的產品線。

總而言之一句話,我們公司是做企業級軟體的,我們客戶主要是一些歐美的大公司、政府、銀行。介紹這些是想讓大家了解一下我們是在做什麼,以及為什麼有這麼一些 DevOps 的選擇原因。

做為軟體行業的巨頭之一,我們整個公司以 Scaled Agile Framework 這種框架來作為公司運作的框架。

在這樣大的框架下我們正在經歷從傳統軟體行業向 DevOps 的轉型。我自己在這裡面也非常深切的體會到了中間巨大的變革。

我們有什麼樣的變化:

戰略層面。我們做了一個產品集的戰略,說白了就是把業務上和領域上比較相關的產品打包成全家桶賣給客戶。這件事情帶來的變化是我們有很多跨團隊、跨組織的流程和協作的變革。

踐行敏捷的方法。尤其是持續集成、持續部署、持續 Demo 作為我們最核心的實踐。

技術領域。我們把產品容器化,在架構上,做了微服務化的設計與調整。因為我們是做企業軟體的,所以我們對軟體質量、安全以及法律法規上面有比較高的要求。我們把安全是內嵌到 CI/CD 的流程裡面做。

說這麼多那我們項目是什麼樣子呢?我選一個最典型的指標來跟大家說一下。那就是我們 release 周期,兩三年之前我們是一年 release 一次。這在今天,大家可能覺得都不可想像。

我們也在迅速的發生變化,在進步。我們從一年到六個月到三個月,我們目前的目標是兩個禮拜 release 一次,我們是很大型的軟體。大家可能會說這有什麼難的,可是看一下我們項目的情況,我選取了三種比較典型的項目特徵。

項目 A,這個項目有20多年,接近30年了。那時候沒有 Jenkins,C++ 很多功能也沒有誕生,我們還要維護它。最大的挑戰是工具鏈的升級,以及怎麼降低維護它的人力成本。

項目 B,比較新一點,最開始是以微服務作為架構設計誕生的。但有一個很挑戰的地方,它的 Jenkins job 達到600多個。支撐這個項目的 DevOps 工程師人力是三分之一個。這個事情說明的是:微服務給我們的持續集成以及持續部署帶來了更大的挑戰和困難。

項目 C,做的事情就是把 A、B 以及其它的項目產出的東西,我們把它容器化,把它裝在 Kubernetes 裡面,部署到各種公有雲和私有雲上面。這個項目挑戰難度是有很多跨團隊的協作,以及產品集成上面的困難。

舉例

我們以這個項目 C為一個例子,打個比方,我們乾的事情是什麼呢?好比說我們在用樂高積木搭一艘軍艦,要一塊一塊的快速組裝起來。我們艦隊的成員大概有180多個工程師,有21個時光團隊。我們的彈藥庫是6個大的產品,從邏輯業務上切分成了20多個 service ,每個 service 向下還可以切出很多組件和技術角度的 service 。我們 Git 倉庫有120多個,發布給客戶的東西有140多個Docker image ,在 Kubernetes 裡面部署起來有145個 pod 。

我們認為這麼高度集成複雜的產品,自動化的測試系統是我們的生命線,而 CI/CD 系統就是我們這艘軍艦的動力系統,通過 CI/CD 的流程,我們拉動項目運轉周期,協調各團隊不同角色之間的協作。

DevOps 工具鏈

我們為項目選擇了什麼工具。剛剛也講到,我們公司自己本身就有非常豐富完整的從 DevOps 到 IT 運維,到項目管理到敏捷的工具都是有的。工具這個東西沒有最好的,只有最適合的。我跟大家分享一下,實際用到了哪些工具。

大家看這張圖上,Jenkins 像一個老管家一樣,他在這裡的地位就是起到了對工具編排引擎的作用,可以理解是一個框架。這裡有開源的也有商用的,也有我們公司自己做的,選這些工具有一些方法和思路。

我先分享一下方法:

首先,建立一個我們想要達到的目標,以及工具所能提供功能的矩陣圖,因為滿足需求永遠是第一步。

第二,我們要考慮工具跟其它工具集成的功能、能力以及難度。

第三,擴展性和靈活性。就是說它是否提供豐富的 API ,它插件的數量、質量,它提供的 SDK 等等都是需要考慮的。

第四,用戶的接受程度。這個對使用面很廣的工具是很重要的。

第五,我們的學習曲線,實施的難度和維護成本都要考慮。

第六,商用軟體的話還要考慮技術支持。如果是開源的軟體,要考慮社區的活躍度,以及熱點趨勢還在不在,

第七,應用的範圍。我們的工具到底是用在項目內部的,還是我部門的,還是 BU 的,還是整個公司的。不同範圍對軟體的一些高可用性、性能、災難恢復以及很多企業功能要求是不一樣的。

第八,價格因素。

第九,考慮所有因素以後最重要的是要做 POC ,要做工具之間 demo 的對比,以及在一些小範圍的項目做試點。因為只有經過項目運作檢驗以後,才能夠證明這個工具是適合我們的,其實我們在做的時候,有時候確實會推翻,會覺得發現有一些 issue 是沒有辦法解決的。

回到工具鏈圖看一下,最左邊的這列是項目管理以及協作的工具,前面樂高軍艦的圖上,寫出了非常精確的人力投入的點,以及計劃的點,怎麼體現出來的?就是 Agile Manager 軟體,這個系統非常好用。它完全是基於 Scrum 模型的項目管理,裡面有豐富的數據管理,很漂亮的 Dashboard 等等。

在基礎設施上選用了 Docker 和 Kubernetes ,在雲平台選用了私有雲 Vmware 和公有雲 AWS ,並實現了持續部署。

這邊源代碼管理工具,這裡有兩個風格,一個是 GitHub,另外一個是谷歌出品的 Gerrit 工具。

這兩種工具是完全不一樣的理念,谷歌的 Gerrit 在安卓生態圈特別流行,他的理念更注重控制,更中心化,更嚴格的審核機制。GitHub 是經典的 social coding的理念和產品設計。

我們做了 POC 以後認為 GitHub 是更適合我們想法的,全公司裡面我們選擇工具有很高自由度,沒有強制要求。

可是整個公司 GitHub 應該是第一流行的,大家都選擇了它,我們也是把這個工具從公司層面做了全球部署,它的性能、界面和功能都是非常好的,應該是一統江湖的工具了,其它的大家可能各自有各自的想法。

打包和部署 Maven 和 Ansible 是比較通用的工具。Packer 和 Terraform 優點是可以對付各種不同雲平台的基礎措施,包括 AWS和 Google Cloud Platform, 微軟的 Azure 和私有的 OpenStack 也是同樣支持的。Cloud Formation 是專門針對 AWS 基礎設施提供的工具。

其它還有很多的工具,我們在選擇它的時候要符合自己的需求,要按照一定的套路來進行這樣的抉擇。

利用Jenkins Pipeline 實現CI/CD

有了上面的這些工具我們具體怎麼做持續集成和持續部署的呢?講到CI/CD的話題,我想引用一句托爾斯泰的名言:幸福的家庭都是相同的,不幸的家庭卻各有各的不幸。

CI/CD 這個事情,模型和框架都是一樣的,各家公司有各家公司的困難和挑戰,有不同的條件限制,最終實現的效果也是不一樣的。

下面我想分享一些 idea,就是我們在實施 CI/CD 時的一些想法。我認為做這些事情為我們真正帶來好處的點分享給大家,希望有遇到跟我們類似情況的時候可以有所啟發。

首先講 CI/CD 有一個先入的條件,就是軟體的架構設計。我們是以微服務作為架構設計的。這個架構很大程度上就已經決定了你的流程該是什麼樣子,以及具體實施應該有什麼樣的要求。

我們一些新的項目一開始用了微服務,對一些老的項目,我們也花了非常大的經歷去做服務的定義和切割。

具體來講反映到 DevOps 能看到的角度就是把以前的單體代碼倉庫切割成若干個獨立的,每一個倉庫裡面的內容和服務都可以獨立的編譯、部署、測試,這是我們的第一步。

基於微服務的架構,我們 CI/CD 的想法就是形成多層級 CI/CD 的系統。每一層的內部是一個小周期,在這個小周期裡面是一個標準的構建、測試、部署完整的閉環。

當他跑完這個閉環以後,會向上一個級別 promote 自己的一個版本,就進入一個新的大周期新一輪 CI/CD 標準的循環。例如:假設一個工程師提交了一行代碼,那麼就會至少經過組件級別、 Service 級別以及 Suite 集成級別,至少有三層 CI/CD 的循環,最終會進入 Release 的隊列。

多層級的 CI/CD ,這個也不算很新奇,很多都是這麼做的,我想說有下面三點需要特別注意。首先是 Service 之間集成的驗證。

理想很豐滿,現實很骨感。我們做微服務總是希望服務之間是解耦的,不依賴的,但我們業務上高度集成的產品,現實有時候確實是互相依賴、互相傷害的。

就好比說,我自己的小周期是 ok 的,可 A 和 B 放在一起就不好了,也許旁邊還有一個無辜的 C 說我也不好了,怎麼辦?我們的思路就是說要做通過基於 API 的契約測試。我希望對方該有什麼樣的行為,我去寫 case 測是不是符合我的預期。

第二,我們有 Promote 的機制,必須是一種靈活和自動化的 Promote 和 Rollback 機制。我們做集成的時候總會挑某一個服務 Stable 版本,以及其他的官方認證過的 Stable 版本,放在一起做集成測試,如果 ok ,那就是新的Stable,如果不可以的話,就 Rollback 回去。這套機制也是藉助了 GitHub 的Pull request 方式來完成的。

第三,很重要的一點,我們有這麼多 Service 而且還分層級,我們 Version mapping 關係的維護是很重要的。每一層的組件,Service 以及整個產品集必須有聲明自己版本的機制。Stable 是什麼版本,最新是什麼版本,RC、GN分別是什麼版本,我下面用到哪些組件是什麼版本,向上我又被誰用到了我的什麼版本,這些都會有很明確的 mapping 關係,這些也是隨著我們代碼和配置是編譯在一起的。並且我們是以一種自動化腳本的方式,能夠自動更新他們的,這點很重要。

下面一個話題就是 Operation as a service 。我們把自動化測試和監控等等公共的能力作為一項服務,提供給每個不同團隊。

打個比方就以自動化測試的框架和 case 來說,它實際上是運行在 K8s 裡面的,是作為 K8s 裡面的 Service 跟我們產品運行在一起的。這麼做是因為安全上的一些考慮,Service 之間相互調用的埠和 API 是不允許曝露到Kubernetes 外面網路的,全部都要走 K8s 裡面的網路。

我們要測這些東西,那自動化的框架就必須要在 K8s 裡面。這麼做我們發現帶來一個好處,我們不僅僅是有官方每天執行的測試和報告,任何一個人,他只要去部署我們的產品,他的環境裡面都會預設給他起這樣一個 Service 以及相關的 Pod,裡面裝的就是測試系統,就會幫他跑。

更進一步這些測試的代碼,以及我們部署的文件(例如:K8s 的 yaml 文件等)都是放在 GitHub 上面。任何一個團隊,除了用我提供的這個標準,還可以把倉庫複製過去,針對特殊的需要做一些修改,就很容易的做出針對自己的測試服務框架。

好處是每個小團隊不用花力氣維護這些系統,我只關心我的業務,去寫 case 就好了。他做出來以後,按照他自己特殊的標誌,在 K8s 裡面運行起來。並且一些共性的東西還可以貢獻給中心的倉庫。

與此類似,我們的監控也是這樣做的。我們監控是用了 Prometheus 和 Grafana ,這本身就是天生的為 K8s 和 Docker 做的,它也是作為一個 Pod 跟產品環境部署在一起的。

這不是我們官方有一個總的監控系統,我們任何人都可以做自己的小系統,這就很方便了。這個意思就是說共享了基礎的能力。

接下來 Pipeline as code,這個用到了 Jenkins 2.0 以後的一個核心功能。用代碼、腳本定義我們的流水線。

這個事情跟以前傳統方式配置 Jenkins 是有一個革命性的變化,在我看來,我們每一個倉庫,在它根目錄下面都會有一個Jenkins file。這個文件就定義了該倉庫流水線的行為,並且大家可以看到這個版本化的管理。在這件事情我認為不僅僅是流水線是代碼定義,更進一步我們做的是通過代碼定義了我們的流程和規則。

舉例:我們用 Kubernetes 部署東西,要編寫很多的 yaml 文件。它本身是不需要編譯的,但是它的格式很敏感,無法在構建環節發現錯誤。在部署時,如果語法有問題就會失敗,我們想儘早的發現錯誤,那我就會對它做語法檢查,另外還有語義檢查。

我們有很多的 Service 運行在共同的環境裡面,我們內部協商了很多埠,協商了很多 lable 和配置,大家要有這套規則,這些規則不是通過開會、郵件、寫文檔就可以約束得住的。

我們就把這些規則全部翻譯成了代碼,在我們 CI/CD 環境裡面跑,任何一個工程師要改 Kubernetes 中的任何一個配置,當他提交修改時發送到 GitHub, CI/CD 首先做的第一件事情就是對這些 yaml 文件語法跟語義做檢查,如果通不過根本不可能讓你部署。

Pipeline as code 與 Operation as a service 解決的就是怎麼樣在微服務的組織下共享一些能力。

Jenkins Pipeline 至少有三種方式可以達到代碼的復用:

第一,本地文件級

第二,從遠端的某個 URL 執行公共的定義的內容

第三,把一些公共的函數或者類抽象出來做全局的類,然後調用。

這是為了把我們部署的行為和環境,不僅僅要降低維護成本,主要還是做標準化的統一。

統一我們的 build chain。既然我們是微服務的團隊,每個服務之間採用的技術棧,差異是非常大的。尤其是像 go 語言這種,編譯打包的方式各不相同。我們每個項目都是用 Jenkins file 方式來做流水線的。

我們希望 Jenkins 內部行為,介面的對象盡量是統一。我們就採用 Maven 抹平每個 Service 之間技術棧的不同。Maven 插件非常豐富,可以對 C++、Java、npm 都可以完成打包,甚至包括 docker image 也是用 Maven 做的。

持續集成的時候根據你各種不同的需要,不同的參數打進去,利用模板引擎形成最終的 yaml 文件。這都是用 Maven 做出來的。最終形成的效果就是說簡化了 Jenkins file 內部的邏輯編程和配置。

接下來是 pre-flight build 和 private CI/CD 的概念。第一個是在任何變更合入分支之前,跑一套 CI/CD 保證質量的。第二個是我們 CI/CD 不僅僅只有官方系統可以跑,任何一個工程師可以對自己私人的代碼修改完成持續集成的。

接下來看看怎麼樣跟 GitHub 集成。我們官方的 git倉庫原則上是不允許存在有特性分支的。

我們是秉持著主線開發的模式,任何一個工程師工作的時候,首先複製出這麼一套倉庫到他私人倉庫的名下,做完了修改,Pull Request 到官方倉庫。這時候 GitHub 的 webhook 會告訴 Jenkins 這個事件,Jenkins 就會根據 Jenkins

file 定義內容運行 job,並回寫消息給 GitHub。當這個 Pull Request 被批准合入以後,同時也會再被執行 CI/CD 的流程。

具體的效果我們是用的 MultiBranch Pipeline 。這個插件有一個好處值得擁有,它可以掃描整個代碼倉庫,只要發現有 Jenkins file,可以自動幫你創建出每一個分支 job。

當你 Pull Request 提交過來後會自動掃描幫你創建出 Jenkins 的 Pull Request 的 job,如果關閉會在 job 上打一個橫線,這個 job 就會自動的銷毀了。這個是節省了很多配置 Jenkins job 上面人力的成本,全都可以自動的做出來。

前面主要集中於持續集成,接下來我們看一下部署。我們部署的情況也是比較複雜的,公有雲要支持 AWS,微軟的 Azure,私有的要支持 OpenStack 和Vmware。部署在實驗室或者客戶環境裡面都要進行部署,部署的用途有給 Dev,有給 QA,有給 Staging 環境,有給 Demo 環境。

具體到產品安裝的方式就更五花八門和複雜了,有不同大小、不同模塊,我們是變形金剛,A+B、C+D 等等的組合。總的來說我們要做這個部署,大致粗略的劃分要做這幾件事情:

首先,基於公有雲,要創建出一套基礎設施,AWS 上的 EC2,網路,存儲等等,在私有雲上面相映的虛擬機要創建出來。

第二,要把 K8s 安裝起來。

最後,在 K8s 中起我們的 Pod 和 Service 等等。

我們要怎麼做這個事情呢?我們的思路就是針對每一步高度抽象出獨立的工具,這個工具的能力可以完成很複雜的配置。

第一層是用 Terraform(支持各種其他公有雲)、Clud Formation、Ansible(主要針對 VMware)。

做了第一層基礎設施以後,有時客戶已經有自己的IT基礎設施,那我們有一個 Pre-check。這個工具會幫客戶檢查是否符合安裝 Kubernetes 的條件,如果不符合要展示出來。

第二層我們有一個工具 Container Delivery Foundation,這件工具專門負責安裝 K8s,包括多 master,多 node,各種網路和存儲配置,都是用這個工具來完成的。

第三層就是產品安裝環節。我們用 Go 語言封裝了 Ansible 做大量的複雜邏輯,最終達到的效果是通過輸入各種不同參數和配置,就算一個小白,任何一個人拿到他都可以把有140多個 Pod 的產品在 K8s 裡面跑起來。

有了這些獨立強大的安裝部署工具以後,我們怎麼樣來把他編排起來的呢?主要是用 Jenkins Pipline 的方式。這裡有很多共性的步驟可以復用的,圖的上半部分是我們在實驗室內部模擬了一次產品升級。

下半部分是一次在 AWS 上面的安裝部署。大家可以看到有一個 stage:check service status,它總共出現了3次,背後的代碼和工具都是一樣的,是高度的抽象復用。不僅僅是為了節省成本,主要是為了標準化。要保證大家在所有情況下做的事情都是一樣的。

接下來給大家介紹一款比較好玩的工具 —— Slack,是即時聊天的工具,可以做工作協作。它的意義是形成一個虛擬的作戰室,相同的話題可以在一起有一個專門的頻道進行聊天。

像一些部署的消息,我們測試的報告,我們都會發到這個系統裡面。更重要的是他是 ChatOps 界面、介面的工具。你想讓這個工具做一些事情,對話框裡面打一些關鍵字,Slack 收到消息以後,就會去跟你想操作的系統講話。非常好,在手機上也可以操作。

我在 DevOps 領域想挑一個我認為最有價值的實踐來講,我認為是 infra as code。

這個事情不僅僅是解放了我們自己,把我們的基礎設施進行了代碼的標準化定義,更重要的是做 DevOps 我希望是 everything as code,包括我們的流水線、流程、規則等所有的都翻譯成代碼,為什麼?這才是我們做到自動化輕鬆運營的基石和前提條件。


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 DevOps時代 的精彩文章:

CI/CD和DevOps 的過去和未來

TAG:DevOps時代 |