1. 程式人生 > 其它 >SaaS服務的私有化部署,這樣做最高效|雲效工程師指北

SaaS服務的私有化部署,這樣做最高效|雲效工程師指北

大家好,我是崔力強,我在雲效負責Flow流水線的開發工作。近年來,SaaS化部署形態的產品的私有化部署需求越來越多,比如雲效自身就有私有化部署的版本。為了能夠有效且高效地同時管理SaaS版本和私有化版本的釋出過程,雲效團隊也結合雲原生的基礎設施和標準化工具(比如helm)進行了一系列的探索和實踐,並將其中一些通能的能力進行了產品化。本文會從問題本身出發,講解解決問題的思路,及如何通過“DIY”的方式來實現這套思路。最終講解雲效AppStack產品是如何對這些實踐進行產品化,並使其更容易規模化。

SaaS服務在版本化上的先天不足

軟體交付有兩種基本場景:面向大版本的交付和麵向SaaS的升級更新。

通常來講,提供本地或私有化部署的軟體都屬於第一種。比如Jenkins剛剛釋出了2.319.2版本,那麼這個版本里包含了什麼樣的特性就是明確的。你拿著這個安裝包在任何一臺機器上都可以從頭安裝得到這些功能。

而網際網路產品很大一部分是SaaS化的,即只有一套部署,供所有使用者使用。軟體的維護者更關心的並不是我的產品是否可以在任何一個數據中心從頭搭建出來,而是如何在現有的這個執行中的系統上通過更新某個元件或者服務來快速的交付一個特性。

圖1:SaaS服務交付和大版本交付的交付節奏

從上述的示意圖,可以形象地看到兩種互動方式的差異。

面向大版本的交付會明確該版本中包含的特性以及交付時間, 版本的釋出時間間隔通常比較長,需要對版本的全新安裝以及不同版本之間的升級安裝進行詳盡的測試。

面向SaaS的升級更新,交付的頻率比較高,可以快速響應市場上的需求,但相應的規劃性比較差。同時因為“可重複安裝能力”的優先順序要低於“快速利用已有的服務和能力交付新特性”,因此在架構上可能會逐步產生複雜的依賴,從而進一步地使得全新部署這套服務變的越來越困難。

然而現實並不是非黑即白的。有可能一套網際網路產品在發展了若干年之後有了進軍海外的需求,就需要同時部署海外站, 或者需要做私有化部署。此時該怎麼辦呢?是犧牲效率全部改成版本化的交付,還是以SaaS服務的交付節奏為主?如果是後者,那麼每個私有化大版本釋出前的幾天,團隊需要從紛亂的SaaS部署中釐清需要將哪些服務的什麼版本(比如映象版本)納入到這個大版本中,進行版本驗證,以及潛在的可能要對程式碼和配置進行調整。

圖2:同時兼顧SaaS服務和大版本交付兩種交付方式

假設一個月出一個大版本,那麼在上圖的2月1號到2月7號這七天裡都可能發生了什麼呢?

  1. 可能在對焦,大版本里要求的功能是否都完成了,如果沒有就要拉分支繼續做。
  2. SaaS化版本里面的一些功能可能是私有化部署不需要的,這時需要加一些開關使其不可見,需要改程式碼。
  3. 在這一個月的迭代裡,技術架構發生的調整,刪除了一個微服務,又新加了一個微服務,大版本需要做相應的調整。
  4. 在這一個月的迭代裡,應用的配置項也發生了變更,需要在大版本中做相應調整。

其中:

1和2屬於版本規劃和測試左移的問題。本文暫時不聊。

3和4就是可以通過技術來解決的問題了,本文接下來的部分會重點討論如何高效的解決這兩類問題。

統一版本格式

解決上述問題的核心技術就是要有一個統一的版本格式,無論是SaaS版本還是大版本都應該使用相同的版本格式。

在此基礎之上,要做到

1、版本應該是一個完整的系統描述,包含了所有的映象,配置等一切啟動服務所需要的描述。從而能夠實現基於某個版本,就可以一鍵拉起一個新的可用的環境。

2、每個環境有一個基線的概念,也就是和環境的當前執行態保持一致的那個版本。

圖3:版本中包含的內容

3、在環境中,每個服務還是可以獨立更新的。每一次某個服務在某個環境上(比如服務A的生產環境)的釋出,儘管只修改了系統中的一個服務,但也應該自動生成整個環境的一個新的版本。

4、每個環境的配置應該集中化起來,而不是在各個服務中分別維護。在服務數量比較多的情況下,這種方式可以大大地降低版本維護的成本。尤其是在新建環境的場景下,由於配置集中化了,需要修改什麼就更加的一目瞭然。通常在配置項集中化之後,還會看到另一個好處,那就是重複配置少了,因為一個系統中的不同服務多多少少都會共用一些配置,如果要單獨在服務中維護,就不可避免的出現重複。

圖4:任何製品和配置的變更都引起大版本的更新

5、對環境的任何變更都應該最終反映在版本中。只有這樣才能保證你做的變更,可以原樣的在另一個環境,另外一家客戶的機房中被正確的執行,比如DDL和DML。

6、所有的日常釋出行為,本質上就是針對版本變更這個動作的一些場景化封裝。比如對某一個服務做變更,那就可以建立一個獨立的CD流水線進行映象構建,建立臨時版本,更新環境,將臨時版本寫入基線。而進行某個配置變更,就是修改基線,然後應用基線到環境。

圖5:圍繞版本構建日常構建釋出等工作流

圍繞Helm進行版本管理和構建部署

在不同的基礎設施之上,上述的思路可以有不同的實現方式。

而在K8S基礎設施上,Helm Chart就是版本格式的不二之選。

Helm的核心概念包括:

  1. 一套K8S資原始檔的組織方式,資原始檔中可以使用變數佔位符
  2. 變數管理機制,使用helm提供的機制,可以很容易的將整個大版本的變數提取出來放到統一的檔案來維護,這就契合了我們前面提到的需求
  3. 一個渲染引擎,在執行時,將變數替換到檔案中,並進一步應用到叢集中
  4. 一套部署歷史管理的機制,比如update/rollback等

下面看一個典型的例子:

圖6:基於Helm構建版本

得益於K8S資源的強大描述能力,形成一個“版本”的各種組成部分都可以很好的描述,比如:

  1. 系統的域名是什麼?
  2. 不同的URL應該路由到哪個服務?
  3. 可以將Flyway和相關的SQL遷移指令碼打包成一個Job,來做DDL。
  4. 可以將其他的需要對系統進行資料初始化的任務打包成一個Job。

在此之上,再加上helm提供的模板化能力,就可以清楚的將對一個環境的描述分為兩個部分:

  1. 不變的部分,也就是那些模板化的資原始檔,不同的環境會共用這部分描述。
  2. 抽取出來的屬於某個環境的變數。

因此上圖中的藍色的框內的就是“測試環境”的一個版本。

helm chart作為版本,可以看到,本質上就是一堆描述檔案。這些描述檔案可以以目錄的形式存在,也可以以tgz包的形式存在。因為面向SaaS的交付的變更頻率會非常高,因此每次打一個tgz包就會顯得非常的臃腫。所以筆者會採取目錄的形式,那麼什麼是承載目錄,並且還能實現版本序列技能力的技術呢,很顯然就是Git啦。

我們把上面思路中的那個圍繞版本進行一系列研發活動那種圖翻譯到Helm和Git上,就是這樣:

圖7:圍繞helm chart構建日常構建釋出等工作流

至此,利用現成的一些標準化工具,就實現了一套版本機制,及圍繞版本機制的開發流程。

在這套流程下:

  1. 面向SaaS的交付流程,仍然非常敏捷,且同時會自動的維護好各個環境的基線。
  2. 由於各個環境都通過helm chart中的模板檔案“耦合”在了一起,當你修改一個環境時候,自然就需要考慮其他環境怎麼辦,因此一致性也很好的得到了保證。任何時刻,我都可以使用某個環境的基線來重建這個環境。
  3. 也可以基於一個環境的基線,快速地創建出另一個環境的基線,只需要簡單的修改一下環境的變數檔案即可。

一些小細節

在實際使用這套方案的時候,其實還是很多小細節,需要慢慢優化。這裡就簡單列兩個:

  1. 所有的映象的tag包含日期和commitId,在後續定位問題時候,可以通過這些資訊快速的找到對應的程式碼,進行排查。
  2. 在上述的CD流水線中更新一個環境之前,確保基線與執行態的一致性,如果不一致,則不進行更新,避免有人修改了基線的程式碼庫,意外的被你捎帶上了環境。

規模化的採納最佳實踐

上述方案最大的好處,就是採納的都是標準的元件,具有很大的靈活性,和可定製性。

但這同時也是這個方案的壞處,就是太靈活了,各種最佳實踐也需要慢慢摸索和調整。在調整的過程中可能會發現很多類似上面提到的“小細節”,需要進行規範或者封裝。如果進行規模化的推廣,那麼就要求每個團隊都有一個很熟悉這些工具的同事。如果無法找到這麼多熟悉工具的同是,那就可以考慮對上述的思路進行產品化,使得大部分的開發人員都可以低成本的follow最佳實踐。

雲效的AppStack,就著眼解決這個問題,通過白屏化應用編排、版本管理、以及企業級應用編排模板等產品能力幫助降低開源工具使用門檻,提供了開箱即用的最佳實踐。

  1. 應用編排。即上述的基於helm來描述多環境配置的產品化實現。
  2. 版本和基線。有了版本和基線,就可以快速地進行回滾和基於某個版本一鍵拉起環境等操作。
  3. 整合釋出流水線。將上文中提到的常見的日常工作流程和版本結合在一起,避免每個團隊分別配置。

點選下方;連結體驗雲效應用交付平臺 AppStack。

https://www.aliyun.com/product/yunxiao/appstack?channel=yy_practice