1. 程式人生 > >從0開始搭建一個微服務的持續交付系統

從0開始搭建一個微服務的持續交付系統

本文介紹瞭如何利用開源軟體快速搭建一套微服務的持續交付系統。本文假設的環境是Linux作業系統,用到的軟體包括Git、Jenkins、Salt、ZooKeeper、Apache等。開始之前,我先簡單介紹下持續交付和微服務的概念,以便大家更好的理解本文的精華。

什麼是持續交付?我們先舉個物流的例子,現在各大電商都非常重視物流的自動化建設,在實現包括運輸、裝卸、包裝、分揀、識別等作業過程的裝置和設施自動化的同時,更在研究無人機和自動駕駛汽車送貨,達到物流的全自動。

那麼軟體開發呢,從開發人員check in程式碼到程式碼倉庫,到程式碼的構建、部署、測試、釋出,我們可以形象地把這個過程稱為“軟體物流”,現實世界的物流實現了相當的自動化,“軟體物流”也應如是,實現從開發人員check in程式碼(客戶下單)到生產系統上線(送貨上門)的自動化。

說到這裡,我們可以給持續交付下一個“非專業”的定義,持續交付就是實現“軟體物流”的自動化。

從0開始搭建一個微服務的持續交付系統

圖1.持續交付流水線

圖1摘自《持續交付:釋出可靠軟體的系統方法》,展示了持續交付具體包括的內容。本文重點討論如何實現微服務的持續交付流程,所以會忽略掉整個流程的一些細節(如程式碼分析、單元測試等等)。

那什麼是微服務呢?微服務的概念最初由Martin Fowler與James Lewis於2014年共同提出,微服務架構風格是一種使用一套小服務來開發單個應用的方式途徑,每個服務執行在自己的程序中,並使用輕量級機制通訊,通常是HTTP API,這些服務基於業務能力構建,並能夠通過自動化部署機制來獨立部署,這些服務使用不同的程式語言書寫,以及不同資料儲存技術,並保持最低限度的集中式管理。目前微服務的主流實現方式有兩種:RESTful API和訊息佇列。

從0開始搭建一個微服務的持續交付系統

圖2 RESTful微服務

 

從0開始搭建一個微服務的持續交付系統

圖3 message queue微服務

圖2、圖3是兩種典型微服務架構的簡略圖。當然現實中的系統會複雜的多,比如會有微服務聚合,多級快取,註冊中心等。

微服務相對單體式應用來說有明顯的好處:

  1. 解決了單體式應用的複雜性問題,單個微服務很容易開發、理解和維護。
  2. 每個微服務都可以由獨立的團隊來開發,可以自由選擇開發語言。
  3. 每個微服務可以獨立部署,系統可以快速演進。
  4. 可以對每個微服務進行獨立擴充套件,極大的提高系統伸縮性及資源利用率。

但在一個單體式應用拆分成數十個乃至上百個微服務,由於服務數量的增加,以及微服務支援多種程式語言的特性,對軟體的構建,部署,測試,監控都帶來了全新的挑戰。本文將討論如何通過持續交付來降低微服務構建,部署的複雜度。

微服務的持續交付:統一方法

由於微服務的特性,微服務的持續交付會比單體式應用的持續交付複雜的多。本節列出了為了降低微服務持續交付的複雜度,我們遵循的一些原則:

  1. 統一方法。這裡有兩個層面的含義,第一是流程的統一,有很多公司對運維自動化非常重視,但在開發,測試階段沒有采用自動化的方法。隨著DevOPS運動的興起,大家逐漸意識到需要在開發,測試階段採用與生產環境相同的交付方法,這樣在系統部署到生產環境的時候,這一交付流程已經經過多次的檢驗,出錯的概率大大降低了。第二層含義與微服務相關,各個微服務可能用不同的語言實現,如Java、Python、C++、Golang、純前端(JavaScript),我們要對採用不同語言實現的微服務使用統一的交付方法。
  2. 在版本控制系統中,每個微服務應該對應一個獨立的倉庫。以Git為例,一個Project下面,每個微服務對應一個獨立Repository。這樣各個微服務可以獨立check in程式碼,而不會在持續構建的時候互相影響。
  3. 設計持續交付系統時要考慮實現軟體交付的全自動化,雖然在現實中,會存在提交測試,生產變更稽核等人工環節。但在理想情況下,開發人員check in 程式碼之後,能夠自動觸發構建,多套環境的部署及測試。
  4. 支援單個微服務升降級,這要求持續交付系統,對每個可部署的單元(微服務)要有獨立的版本號。
  5. 程式與配置分離。要支援一套程式(可執行包+配置檔案包)多處部署,這裡強調了一套程式,是指在開發人員check in程式碼後,構建系統只生成一份程式(可執行包+配置檔案包)。不管是部署到開發環境,測試環境,還是生產環境我們要用同一套程式,而不是對每個環境單獨打包。我們知道Java war包會要求把配置檔案包含在裡面,這會造成不同的環境要求提供不同的war包,這就違反了我們說的這個原則,後面我們會討論如何處理這個問題。
  6. 在應用程式部署時,不得依賴外網資源。我們把部署過程獨立為兩個階段:環境準備階段和應用程式部署階段。環境準備包括作業系統,JDK或其他語言執行時系統級依賴庫的安裝,得益於IaaS的相對成熟,我們把這一階段獨立出來。而應用的部署需要定製化,也是本文討論的部分。在部署應用時,要求所有的資源從內網獲得,這樣可以保證應用部署過程的快速、穩定、可重複。

快速搭建微服務的持續交付:持續構建

下面我們結合一個虛構的專案來介紹持續交付的實現細節,假設我們有一個專案BetaCat,由ms1、ms2…msN,n個微服務構成。下面我們重點介紹ms1微服務如何實現持續交付,其它微服務可以類推。

本節討論下如何實現持續構建,下一節會探討持續部署。

從0開始搭建一個微服務的持續交付系統

圖4 Jenkins處理倉庫程式碼流程

如圖4所示,開發人員check in 程式碼到Git倉庫後,Jenkins會自動地進行構建工作,並把打好的包上傳到Repo server上。

從0開始搭建一個微服務的持續交付系統

圖5 配置檔案示例

作為統一方法的一部分,我們在每個微服務倉庫上建立了CI目錄,用於配置檔案的打包,在CI目錄裡,只放入需要引數化的配置檔案,執行指令碼等,並會嚴格遵循原有系統的目錄結構,如圖5所示,我們要求有start.sh、stop.sh及service(用於Linux的init啟停該微服務)。

圖5中配置檔案引數化內容,引數部分用”{{“與”}}”包圍起來,在持續部署的時候會根據傳入的引數替換為特定的值。

我們還定義了持續構建的統一輸出,對每個微服務採用tgz的打包格式,微服務ms1持續構建的輸出檔案示例如下:

  • ms1-1.0.7.tgz (可執行包)
  • ms1_config-1.0.7.tgz(配置檔案包)

在可執行包裡面要求把所有的依賴庫(除了系統lib庫)都包含在裡面,對不同程式語言的微服務的構建工具沒有強制要求,統一由Jenkins呼叫。C/C++我們推薦使用CMake,Java一般用Maven,Python直接打包。

配置檔案包就是前面GIT倉庫的CI目錄直接打包而成。

從0開始搭建一個微服務的持續交付系統

圖6 Bundle示例

同時為了在部署時不用具體指定每個微服務的版本號,我們引入了bundle的概念,如圖6。在任何一個微服務構建之後,會觸發bundle,sha512校驗檔案生成,並上傳到Repo Server。

最後讓我們看下持續交付上傳到Repo Server的目錄結構:

從0開始搭建一個微服務的持續交付系統

圖7 目錄結構

這樣持續構建的工作就完成了,接下來就需要進行持續部署了。

快速搭建微服務的持續交付:持續部署

在開始持續部署的討論之前,我們先描述一下軟體執行注入配置的三個時點:

從0開始搭建一個微服務的持續交付系統

圖8 配置注入的三個時間點打包時點,典型的是Java的war包,會把配置檔案打包在一起。部署時點,在部署的時候利用專門的部署工具更新配置檔案,這也是我們採用的方法;執行時點,程式執行時通過環境變數或註冊中心/配置中心獲得配置資訊,如用Docker部署微服務時就要考慮通過這種方法來獲得所需要的配置資訊。

從0開始搭建一個微服務的持續交付系統

圖9 採用salt進行部署

圖9顯示了我們對不同的環境統一採用salt進行部署。由於我們支援使用者只輸入bundle的版本資訊來實現部署,這就要求在持續部署的時候,部署系統能自動獲取每個微服務的版本號,為此我們對salt/foreman做了一點小改動,修改後返回的pillar格式包含各個微服務的版本,同時下載並解壓對應的配置檔案包到salt master的相應目錄,以及關閉salt master file_list快取:fileserver_list_cache_time: 0。

從0開始搭建一個微服務的持續交付系統

圖10 foreman web介面以及Salt格式

圖10左邊表示我們在foreman web介面上設定的引數,右邊表示通過salt pillar.items取得的格式,可以看到多了每個微服務的版本號資訊。

下面我們按照部署三部曲(安裝、配置注入、服務執行)來介紹部署規則檔案(saltstate、sls檔案)的編寫:

1、betacat_ms1.sls 第一部分:安裝

從0開始搭建一個微服務的持續交付系統

在這一部分,檢查並建立安裝目錄,下載需要的可執行包,並解壓到正確的位置,可執行包直接從Repo Server獲取,並通過sha512驗證檔案的完整性。

2、betacat_ms1.sls 第二部分:配置注入

從0開始搭建一個微服務的持續交付系統

配置注入部分,讀取配置檔案包,通過salt master轉換後下發給目標機。這裡用紅框標出了設計的核心。通過salt的file.recurse和之前持續部署中打好的配置程式包,並把所有的配置項傳入。可以做到不用對多個配置檔案單獨編寫部署邏輯,完全引數化。

3、betacat_ms1.sls 第三部分:服務執行

從0開始搭建一個微服務的持續交付系統

在這一部分,確保微服務在執行狀態,並在必要的時候重啟。這裡需要特別指出的一點,在整個sls檔案中,對不同的微服務來說,只有3個元引數:專案名稱(BeatCat)、微服務名稱(ms1)以及sig(ms1, 微服務程序的唯一識別字符串)。那麼我們可以通過簡單的指令碼來自動生成sls檔案,而不需要手工編寫。大大降低持續部署的開發維護成本。

快速搭建微服務的持續交付:全自動化

為了支援持續交付流程的全自動化,我們引入了ZooKeeper,如圖14。

從0開始搭建一個微服務的持續交付系統

圖14 引入ZooKeeper後的流程

  1. 程式碼check in 到Git後,觸發構建,Jenkins會把打好的包上傳到Repository Server,並更新ZooKeeper的本次及latest包版本資訊。
  2. 偵聽到ZooKeeper的latest包版本資訊變動後,會觸發saltstack的部署命令向各個環境部署最新的程式。
  3. 部署完畢,會更新ZooKeeper上的目標機部署版本資訊。
  4. 偵聽到ZooKeeper上的目標機部署版本資訊變動後,會觸發一套或多套自動化測試指令碼的執行。
  5. 自動化測試通過後,會更新ZooKeeper上的包版本的測試資訊。
  6. 通過測試的包,可以自動上傳到生產環境的repo server,並更新生產環境ZooKeeper的包版本資訊。
  7. 生產環境,偵聽到ZooKeeper的包版本資訊變動後,會觸發生產環境的部署。
  8. 生產環境部署完畢,會更新ZooKeeper上的目標機部署版本資訊。

歡迎加入Java高階架構學習交流群:939420159,免費領取Dubbo、
Redis、Netty、zookeeper  Spring cloud、分散式、高併發、效能
調優、微服務等架構技術資料