轉:笨方法使用Kubernetes實現持續交付

weixin_33866037發表於2017-07-11

本文將探討如何構建一種用於持續整合的架構,我們採用了由簡至繁的方法。在每一次將架構複雜化時,我們會給出原先的簡單方法的侷限性,並驗證新增架構的複雜性和/或重構架構是合理的。

本文所給出的終極方法,是Weaveworks探索出的最適合自身的方法。

持續交付

持續交付是以頻繁且少量的方式而非一次性大批量的釋出去生成軟體的方法。

為什麼持續交付很重要?將版本持續部署到應用會消除“釋出日”的思維模式。理論上講,版本的完成越是頻繁,那麼版本的風險也就越低。開發人員還可在程式碼就緒時更改應用(無論是實現新程式碼,或是回滾到舊版本)。這意味著可以更快地更改業務,進而使企業更具競爭力。

由於微服務間使用API互相通訊,需要保證版本間在一定程度上的向後相容性,以免必須在團隊間做版本同步。

根據Conway定律,軟體呈現了其所屬企業的結構。因此,微服務和容器不僅體現了技術上的改進,也同等程度上體現了企業的改進。在將一個單體應用分解為微服務時,應使每個微服務可被獨立的團隊交付。

在本文中,我們將介紹如何使用Kubernetes實現持續交付。

Kubernetes概述

Kubernetes是一種管理容器化應用的容器編排器。正如我們先前所提及的,並不存在使用kubernetes實現持續交付的所謂正確方法。雖然實現持續交付對釋出和自動化非常關鍵,但是Kubernetes並未對該問題提供一種解決方案。

(點選放大影象)

2287474-7debd6d9689aab68.jpg


Kubernetes在平臺中可建立和管理的最小單元稱為Pod。我們從上面的結構圖中可以看到,一個Pod中存在著一個Docker容器。Docker容器映象將應用程式碼包括在一個隔離的環境中。

Pod是一系列在同一機器上一併排程的容器,它們共享同一網路名稱空間。一個容器可與本機通訊,並發現位於同一Pod中、繫結於任何埠上的其它容器。

在Google的Tim Hockin看來,Pod並非永生的。他所指的是,如果由於底層硬體故障等原因導致雲端機器消失,那麼Pod也會隨之而消亡。針對Pod也會消亡這一事實,不應將重要服務置於Pod中執行,寄希望於機器不會消失。機器隨時都可能會消失,尤其是在雲環境中。

應採用的替代做法是將Pod包裹在部署中,由部署指定Pod的數量。例如,可以定義一個部署為具有一個Pod的三個例項,並且這些例項應保持執行。如果當前機器當機了,部署會將這三個Pod例項置於新的機器上,在其它地方啟動它們,並保持它們的執行。

Kubernetes叢集是應用實際執行之處。

第一版架構

下面介紹第一種部署,也是最簡單的一種部署。其中,受版本控制的程式碼將持續整合系統與Docker Registry聯絡起來,然後通過持續整合系統將最新的映象手工部署到Kubernetes叢集中。手工部署的命令為:

kubectl apply -f service.yaml

雖然在一開始時完全可以使用手動部署,但是此後的部署更新應實現持續整合系統的自動化。持續整合系統通過映象標籤更新Kubernetes,並將更新推送到Kubernetes API。這使得Kubernetes從Docker Registry上拉取(Pull)標籤所指向的Docker映象,並加以部署。

(點選放大影象)


更改的提交

在這樣的架構中,如果開發人員使用git push在受版本控制的程式碼中做了一次更改,持續整合系統將自動完成一次Docker build。持續整合系統會對該Docker映象做標籤,標籤所使用的SHA-1雜湊對應於推送程式碼的SHA-1雜湊,並賦予了唯一的名字。此後,持續整合系統會將映象推送到Docker Registry。

Kubectl set image

持續整合系統將執行“kubectl set image”程式提交上述更改。kubectl set image會獲取一個執行中的API物件,並告知Kubernetes使用特定的新標籤更新持續整合系統。例如,使用者可使用kubectl set image更改某個前端服務的當前映象。

然後,Kubernetes會自動拉取回新的Docker映象,並替換當前映象。此外,使用者也可以回滾更新,這是Kubernetes內建的一個特性。

實現回滾

只要新的更改被推送到Master分支,就會進而被推送到生產環境。

要回滾該更改,需要再做一次程式碼更改。開發人員需要從Master分支恢復最近一次提交。當存在合併(Merge)提交時,事情會略為複雜。在理想情況下,使用者需重置回最近一次合併前的版本,然後強制推送新的更改。

在推送回滾後,需重構舊版本。持續整合系統將會運轉起來,重構該新映象,並推送新映象到Docker Registry。該新映象是舊映象的一個新拷貝。

不足之處

這種架構方法存在一些不足之處。首先,容器的構建和推送可能會很慢。無論容器是否最大程度上使用了磁碟I/O和網路程式碼,構建和推送所用時間主要取決於容器中的內容。這對於做回滾是一個問題,因為終端使用者為儘快解決問題,需要回滾快速完成。

其次,這種架構耦合緊密,不允許不同的環境(例如開發、試機和生產)處於不同的版本上。對於大多數使用者而言,這無疑是一個問題。

下面,我們將嘗試對第一版架構進行改進!

第二版架構

(點選放大影象)

2287474-0d83bb83bac6cb56.jpg


第二版架構是基於第一版的初始架構而構建的,它引入了一個理念,即讓版本控制配置獨立於其餘的應用程式碼版本庫(Repo)。這可使使用者將版本控制配置作為整個應用的單一資料來源(SSOT,Single Source Of Truth),這表示應用是由所有的微服務組成的。

一種做法是讓使用者服務和具有這些服務程式碼的訂購服務毗鄰於它們的Kubernetes YAML。相對於這種做法,更好的做法是拉取所有這些Kubernetes YAML到一個稱為“配置版本庫”的集中程式碼版本庫中。

這一點很重要,因為這使得叢集被破壞後,使用者可從版本控制重構整個叢集。現在,如果有人意外地刪除了生產叢集,該版本控制配置的版本庫是恢復應用所唯一必須的。

第二版架構新引入了這樣的配置版本庫,因此持續整合系統需要多做一些工作。此外,第二版架構與第一版是相同的。

更改的提交

那麼在提交了程式碼更改後,在架構上發生了什麼?

持續整合系統會構建一個新的容器映象,然後持續整合系統(根據程式碼版本庫的響應執行操作)會將更改推送到Docker Register。持續整合系統克隆(Clone)配置版本庫的最近版本,對Kubernetes YAML應用更改。之後,持續整合系統將更改部署到Kubernetes叢集。最後,Kubernetes叢集將映象從Docker Registry拉取下來。

不足之處

正如我們在前面所提及的,現在大量的工作由持續整合所承擔。最好是讓架構的每一部分只去做好一件事情,而不是讓架構中的某一部分承擔了大部分的負擔。

其次,對程式碼的推送依然是觸發持續整合系統的唯一可能途徑。最好是無需推送程式碼就可實現回滾。在這個例項中直接使用kubectl做帶外(Out of Band)回滾,這意味著開發人員必須手工更新中央配置版本庫。這使得該版本庫不再是SSOT。

第三版架構

(點選放大影象)

2287474-adc71f5d28364c58.jpg


我們已經在第二版架構中實現瞭如上的複雜性,最好是再進一步新增版本管理器。Weaveworks團隊所使用的版本管理器稱為Weave Flux,它是一個完全開源的版本管理軟體,也是Weave Cloud的一個組成部分。雖然還有Spinnaker等其它類似的產品,但是相比於Spinnaker,Weave Flux在設計上要更為簡潔,並且是專門針對容器設計的。

加入版本管理器會進一步地簡化架構,它使得每個架構元素只具有單一的職責。軟體管理器的作用是觀察新容器何時出現在Registry中,進而克隆被版本控制的配置,修改該配置,並將配置推送回版本庫以記錄下所產生的版本。同時,它還會推送新配置到Kubernetes叢集。

更改的提交

現在,持續整合系統已經可以將被版本控制的程式碼自動構建到容器映象中,並推送容器映象到Docker Registry。

版本控制器從配置版本庫中拉取Kubernetes YAML並修改它們,並將修改後的版本推送到叢集中。之後,Kubernetes拉取回Docker Registry的最近版本。

在上圖中,在版本管理器上有一個“紙卷形”的圖示,表示了用於不同環境的各種策略。其中,用於試機的策略,可在任何時候釋出;用於生產的策略,可使用版本管理器GUI上的按鈕手工提交版本。這樣,單個微服務版本庫和所要釋出的策略間不再是緊耦合的。

回滾

在第三版架構中實現回滾非常簡單。使用者只需告知版本管理器要回滾到最近的版本,其中不需要持續整合系統的任何參與。現在由版本管理器實現對配置的更改。

總結

使用Kubernetes實現持續交付可以很簡單,也可以很複雜。微服務應用越是複雜,就越可能需要複雜的架構。雖然實現持續整合並不存在所謂的錯誤路線,但重要的是實現自動化,建立SSOT,並且有效地實現無需推送新程式碼更改的回滾。

文章來源:http://www.infoq.com

相關文章