1. 程式人生 > >基於微服務的Real DevOps實踐

基於微服務的Real DevOps實踐

錘子兩年前登陸墨爾本時,完全是DevOps小白。面試REA的時候,被問到什麼是Continuous Delivery(持續交付),錘子誠懇地表示“不知道”。面試官不依不饒,“不知道不要緊,你想想怎麼樣才能做到Continuous Delivery?” 錘子回顧了一下自己維護專案時的噩夢,斟酌著用詞說:“這需要好多自動化的工具支援,怎麼測試,怎麼接入不同的網路,怎麼部署不同的環境,還有資料庫的data migration和回滾,個頂個的都是痛點。”

之前錘子所做過的系統都是Monolith(單體)架構,所以,每次需要重啟生產環境時,真得一而再,再而三地確認。所以當REA的同事給我講解我們的微服務架構

,和怎麼做Continuous Delivery時,我問:“那最壞的情況就是重啟系統了?”這個同事說:“不,重啟系統是正常情況。”由此,錘子開始慢慢了解REA強大的DevOps。

微服務和DevOps

在介紹REA的DevOps之前,還是簡單說說我們使用的微服務架構。

微服務有時被人詬病違背了DRY原則,但是Monolith架構下各種服務間的強耦合對於擴充套件部署都很痛苦,所以Don’t repeat yourself 誠然不錯,微服務架構下,定義好邊界之後(APIs),每個微服務獨立存在,獨立部署且可擴充套件,即使有一些簡單的複製貼上,其帶來的靈活性也是Monolith架構不具備的。

在REA內部,為了保證某種程度的一致性,我們的微服務都需要遵循

12 Factor

  • 基準程式碼: 一份基準程式碼,多份部署。
  • 依賴: 顯式宣告依賴關係。
  • 配置: 在環境中儲存配置。
  • 後端服務: 把後端服務當作附加資源。
  • 構建,釋出,執行: 嚴格分離構建和執行。
  • 程序: 以一個或多個無狀態程序執行應用。
  • 埠繫結: 通過埠繫結提供服務。
  • 併發: 通過程序模型進行擴充套件。
  • 易處理: 快速啟動和優雅終止可最大化健壯性。
  • 開發環境與線上環境等價: 儘可能的保持開發,預釋出,線上環境相同。
  • 日誌: 把日誌當作事件流。
  • 管理程序: 後臺管理任務當作一次性程序執行。

不過不管微服務設計得如何精良,當一個“小而美”的團隊(5-6名開發人員)需要同時開發維護生產環境中10個以上的微服務時,服務執行和管理上的額外複雜性使得全自動構建和部署變得不可或缺,更進一步,最好使用Continuous Delivery來解決這些問題,而DevOps為真正的Continuous Delivery提供了必要的支援。

那DevOps究竟是什麼?DevOps就是更好的優化開發(DEV)、測試(QA)、運維(OPS)的流程,開發運維一體化,通過高度自動化工具與流程來使得軟體構建、測試、釋出更加快捷、頻繁和可靠。

下面這張圖(圖片來源什麼是 DevOps?)就是DevOps的日常。

既然DevOps不是新工具,不是新團隊,不是新角色,也不是大量知識,而且DevOps的偉大實踐來自於許多不同的領域,並且在IT組織內執行,為了提升IT的效能,那下面就讓錘子講講REA的DevOps實踐,首先自然從最貼近我們程式猿的全工具鏈開始。

REA DevOps全工具鏈

REA實際使用到的全工具鏈包括:

  • 程式碼倉庫:github企業版。
  • 構建和部署工具:Buildkite和Jenkins,還有一些老的專案依然在使用Bamboo。
  • 容器平臺:微服務用Docker進行打包,Docker的引入讓公司內部微服務的部署流程一致化。
  • 環境:目前絕大部分的service部署在AWS(Amazon Web Services)中,開發環境和測試環境使用同一套IAM,生產環境使用另一套IAM,三套環境通過Virtual Private Cloud (VPC)的設定進行隔離。不同部門的不同的組在IAM下擁有不同角色和訪問許可權。部署採用AWS Cloudformation服務,避免手動建立和更新使用到的AWS的業務。
  • 日誌管理:splunk。Docker已經提供對Splunk的支援,所有微服務的日誌都能夠通過Splunk Agent傳送到集中的Splunk伺服器。集中式的日誌管理方式,方便程式猿們進行trouble shooting,而且完全避免了登陸到不同的機器收集log的窘境。
  • 監控:建立分層的監控體系。使用NewRelic用來監控網路、裝置和應用的效能;使用AWS Cloudwatch監控AWS的服務,比如某個SQS對應的dead-letter queue裡是不是收到了訊息,或者AWS Lamda執行是不是有錯誤等;Nagios提供服務可用性監控。可以直接使用REA內部的rea-health-check庫,提供心跳API供Nagios的主動模式使用;也可以通過設定接收相應的訊息格式,使用Nagios被動模式監控微服務。不管哪種模式下發現問題,Nagios馬上會產生告警傳送到PagerDuty。
  • 告警:PagerDuty。前面提到的監控工具都可以發出告警,這些告警會通過PagerDuty用郵件,Slack,電話和簡訊的方式通知給當時的值日人員。PageDuty雖然是全天24小時執行,也只有極少部分高優先順序的告警才會在非工作時間發出。還有一個告警的來源是Zendesk Ticket,這種資訊通常直接來自於客戶。就我們組而言,基本上都是一些資料錯誤,需要個別修正。
  • 協同工作:Leankit。

工具鏈看起來並不複雜,那麼有了工具鏈,所有的問題就迎刃而解了嗎?答案自然是否定的。

怎麼樣自動化所有流程?怎樣為REA超過40個組管理AWS的賬號?怎麼為AWS裡的測試環境和生產環境配置VPC?怎樣把微服務部署到不同的環境?監控的策略怎麼樣實施,怎麼樣在不同的組之間協調?所有的幾百個微服務,一旦某些微服務除了問題怎麼辦等等。這些都需要工具鏈切切實實的落地。

REA DevOps工具鏈的實施過程中,分層協作不但釐清不同部門的責任,也讓所有開發人員參與到Operation工作中,讓DevOps融入每個IT人員的日常。

REA DevOps的分層協作

REA DevOps不同層面的問題由不同的組負責,如下圖。

不同的Squads(REA引入了Spotify模式)使用DevOps工具鏈來開發和維護自己的微服務。詳情會在下面一節進行介紹。

Delivery Engineering團隊,顧名思義,就是為了讓程式猿們更快更好地釋出應用,主要職責是工具的開發和管理。包括建立Docker Registry,準備好已經安裝了必要庫的baked Docker image,有了這些基準的Docker Images,開發團隊在為自己的微服務構建Docker Image的時可以有效節省時間,還能規避各種庫版本不一致的問題。Delivery Engineering還需要為不同部門配置Buildkite,Buildkite的Agents部署在AWS的EC2中,根據需要連線的環境,多個Agents分佈在不同的VPC。

最值得一提的是Delivery Engineering開發的rea-shipper

  • rea-shipper實現了從構建到部署的全自動,真正解決了最痛的那個點。
  • rea-shipper自動將監控和日誌管理所需要的模組也用Docker打包,在部署過程中與每個微服務的Docker Image整合,如下圖所示。這樣微服務開發人員只需要關注業務的開發,無需擔心日誌和監控的問題。

以我們一個實際的service charge-central為例,登陸到EC2 instance之後,可以看到正在執行的幾個container。

Global Infrastructure & Architecture 團隊負責基礎設施建設,管理維護並開發相應的工具,包括網路、資料中心、AWS賬號的管理、Splunk的整合等。比如,去年悉尼大雨,Amazon的機房被水淹了,澳洲大批網站受到影響,也包括我們公司的一小部分,當時苦了GIA team的人了。

所以全工具鏈的配置和開發是Global Infrastructure & Architecture 和Delivery Engineering的職責,而作為程式猿的錘子,則是工具鏈的使用者。下面就說說程式猿所參與的DevOps日常。

程式猿DevOps日常

1. Coding

前面提到過程式碼庫使用github企業版,採用github flow

微服務需要的部署指令碼和AWS Cloudformation的資訊,提供給不同監控工具的介面,fried Docker image 定義等,也都是程式碼的一部分,需要開發人員完成。

2. 構建和部署

構建和部署就以Buildkite為例子,這是一個微服務的buildkite指令碼。

這個流程裡程式碼檢查和單元測試自動化起來很容易,那麼怎麼做整合測試?REA基於Ian Robinson提出的用消費者驅動的契約進行面向服務開發的模式開發了 開源的Pact 測試框架,用輕量級的契約測試來代替厚重的整合測試。Pact在消費端用單元測試的形式(更輕)來生成 pact 契約,服務端通過驗證契約來保證兩者穩定整合。一旦有一端契約未經協商發生改變,那麼Pact測試就會失敗。

構建成功之後,會把微服務打包成Docker Image然後上傳到Docker Registry。我們會選擇在Delivery Engineering提供的基準Docker Image之上來打包,這是一個微服務的Dockerfile的例子:

用這種方式,在buildkite上打包並上傳到Docker Registry的時間小於三分鐘。

部署時,指令碼會呼叫rea-shipper。不同的環境下,Buildkite會選擇不同的Agent進行部署:Test 環境的non-prod-corp:default和Prod環境的prod-corp:default。部署的時間通常10分鐘以內,下面是一個微服務部署到test(6分1秒)和prod(5分43秒)的時間,圖中能夠看到Cloudformation更新的步驟。

儘管是全自動的部署,考慮到生產環境的重要性,我們還是選擇謹慎地Block,需要某個開發人員手動觸發。觸發的時間沒有特別的規定,只是在我們的kanban中,deploy是最後一步,這意味著只有真正部署到生產環境,這個卡片才算完成。如果部署過程中出現失敗,rea-shipper不會切換執行中的ASG(Auto Scalling Group),業務並不會受到影響。如果部署的新版本發現bug需要緊急回滾,可以很容易地根據Docker Image的版本找到相應的Image進行部署。

3. 運維

日常的運維如下圖所示:

需要處理的問題一般有兩種:

  • 直接源於客戶的問題,使用Zendesk Ticket。
  • 源於生產環境的問題,比如PagerDuty告警。

我們Tribe有5個Squad,除了有超過30個microservice之外,還有跟不同系統的介面,如果不能組織好,開發人員每天必定會被各種問題打擾。所以如圖所示,Tribe級別有Dingo(工作時間)或者Owl(非工作時間)作為介面人,負責處理和分發問題到Squad級別的Squid。Dingo,Owl和Squid是團隊的開發人員輪崗。

總結

本文介紹了REA DevOps的實踐,包括工具鏈,工具鏈的分層協作以及使用中的流程。再來對比一下Gene Kim的3個方法:流程,反饋和持續學習,這3個方法是DevOps的主要部分,提供一種路標來理解和執行DevOps。錘子能夠看到的是在REA DevOps實踐中,每個開發人員都參與到流程的不斷優化中,讓流程變得更順暢和快速;通過不同方式視覺化監控和反饋,以達到更快的反饋路徑;開放全程式碼庫給所有開發人員,鼓勵程式猿持續學習和改進等等。

到達下面的狀態:

這種變化並不是技術改進帶來的,而是源於持續學習的企業文化。而這,正是DevOps最需要的。

原文作者:虎頭錘,2015年4月登陸澳洲之後,入職REA Group