探祕varian:優雅的釋出部署程式

37丫37發表於2018-07-31

上一篇文章《記一次詭異的故障排查經歷》中有介紹到我們的部署程式varian,文章釋出後有小夥伴對varian很感興趣,今天就簡單的介紹一下我們的varian,揭開她神祕的面紗~

什麼是varian

varian是我們基於Python3編寫的一套部署程式,處在整個部署系統的中心,與CMDB、Jenkins、SVN/Git、映象倉庫Harbor、Kubernetes API、通知系統等都有互動,負責將原始碼經過一系列的處理後打包成Docker映象,併發布到各個環境,然後通知相關人員。簡化後的varian架構如下:

varian架構圖

專案環境介紹

  • 專案數量:50+
  • 開發語言:php、java、nodejs
  • 程式碼版本管理工具:svn、git
  • 編譯方式:maven、grunt、yarn
  • 通知方式:email、sms、im

varian能解決我們哪些問題

說到解決的問題,要先聊一下部署系統經歷的幾個迭代版本:

  1. 最早專案比較少,所用架構及技術也比較單一,每個專案都單獨維護了一個shell指令碼做部署,指令碼里配置了專案的所有資訊,包含伺服器列表、程式碼路徑等專案特有資訊和通知型別等公共資訊,各專案指令碼之間互不干涉。這樣做的好處是每個專案部署釋出邏輯都比較簡單,修改任何一個專案都對其他專案無影響;但缺點也很明顯,各個專案指令碼分散,任何專案資訊變更都需要取改這個指令碼,且一些公共功能的修改就需要所有專案指令碼都改一遍,難免不出問題。

  2. 後來隨著專案、伺服器數量的增多,引入了CMDB來管理專案和主機的基本資訊,純shell的指令碼也升級為了python+shell的指令碼來維護編譯部署,把一部分公共模組例如去CMDB拉取專案下的主機列表、郵件通知等從shell指令碼中單獨抽出來用python重構,並用python實現了一個主入口,所有專案部署都通過這個主入口進入,然後呼叫python或shell指令碼來實現部署釋出整過程,這樣解決了指令碼分散和公共模組更新所有專案指令碼都要跟著修改的問題,但是新增一個新專案還是要手動更新一堆的指令碼檔案,效率低且易出錯,各個專案處理邏輯各不相同,對需要熟悉她的新人很不友好。

  3. 現線上上專案數量已經超過50+,且還在不斷增多,微服務、容器化等新技術也不斷加入,每天進行數十上百次的部署更新,對部署系統的健壯性,擴充套件性有了更高的要求。基於之前一步步的探索,採用微服務的設計理念,我們實現了現在這一套部署程式varian,效率高、易擴充套件、出錯率大大降低且對新人友好,解決了以上遇到的所有問題。

varian究竟長何種模樣

說了這麼多,那varian究竟是個什麼樣子呢?

設計思路

Lego積木,就是那種各個不同的小模組能拼裝成各種各樣的建築的玩具。設計的思路也主要採用了lego的方式,把所有的功能都拆分成一個一個的python類,部署專案時就組裝不同的類,例如一個最簡單的純靜態web專案,組裝了“拉程式碼模組”+“JS/CSS合併壓縮模組”+“分發API模組”+“郵件通知模組”,如果是一個純java api專案呢?組裝“拉程式碼模組”+“maven編譯模組”+“分發API模組”+“郵件通知模組”即可,從上邊的例子可以就可以看出這種組裝模組的優勢。

lego拼裝模組

所有模組可複用,來了一個新專案根據專案架構、開發語言等因素去判斷目前的模組是否能夠滿足,如果可以滿足就直接組裝使用吧,如果確認過眼神,實在滿足不了呢?那就新加一個模組,模組編寫遵循簡單可複用原則,需考慮到後續有類似功能可以直接使用此模組。

可能會有疑問?那些各個專案不同的配置怎麼辦?例如程式碼路徑。這裡採用了邏輯(模組)跟配置拆分的設計方式,所有處理邏輯不涉及任何一個專案特有的屬性,專案特有的屬性都單獨配置,我們採用CMDB來配置,CMDB裡有一張deploy的表,表關聯project,記錄了專案的特殊屬性,例如通知郵件列表等等,邏輯模組會呼叫CMDB API自動取出所需配置資訊。

實現方法

  • 目錄結構如下:
varian/
|-- main.py #入口主函式
|-- module
|   |-- __init__.py
|   |-- notify.py
|   |-- check.py
|   |-- ...更多模組
|-- project
    |-- website #專案名
    |   |-- cache   #存放log等內容
    |   |-- docker  #打包docker映象目錄
    |   |-- svn     #svn原始碼目錄
複製程式碼
  • 簡化過的主函式main.py如下(程式碼隨機刪除。。意思對就行吧)
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import argparse,sys
from module import build,public

parser=argparse.ArgumentParser(description='deploys duang!!!')

parser.add_argument(dest='pro_name',type=str)
parser.add_argument(dest='env_name',type=str)
parser.add_argument(dest='parameters',nargs='*')

args=parser.parse_args()

class M(object):
    def __init__(self):
        self.pro_name = args.pro_name
        self.env_name = args.env_name
        self.parameters = args.parameters

        self.build_ob = build.BUILD(self.pro_name,self.env_name)
        self.public_ob = public.PUBLIC(self.pro_name,self.env_name)
        
        self.maps = {
            "7":"self.build_ob.Maven_Build",
            
            "14":"self.public_ob.Remove_Cache",
        }

    def main(self):
        self.arg_list = self.parameters
       
        if self.env_name not in ("dev","qa","hidden","product"):
            print("\n環境引數錯誤.\n")
            sys.exit()

        for self.every_arg in self.arg_list:
            self.func = self.maps[self.every_arg]
            self.func_ob = str("%s()" % self.func)
            exec(self.func_ob)

if __name__ == '__main__':
    m = M()
    m.main()
複製程式碼
  • modele下的模組函式,以maven編譯模組為例
class BUILD(object):
    def __init__(self,pro_name,env_name):
        self.pro_name = pro_name
        self.env_name = env_name

        self.svn_path = ("%s/project/%s/svn" % (sys.path[0],self.pro_name))

    def Maven_Build(self):
        self.command = str("cd %s; mvn clean package -P%s -Dmaven.test.skip=true" % (
            self.svn_path, self.env_name)
        )

        try:
            print("\nStart maven build in webapp.\n")
            self.result = os.system(self.command)
            assert self.result == 0
        except AssertionError:
            print("\nMvn build error!\n")
            sys.exit()  # 異常退出,這個再模組中非常重要
複製程式碼

使用方法

  • 控制檯使用:
python main.py static qa 1 3 6 8

# 第一個引數為專案名
# 第二個引數為部署環境
# 後邊的引數就是要構建的模組組合
複製程式碼
  • Jenkins使用:

只需要將控制檯命令貼到jenkins的構建步驟中當做shell執行即可

總結

  1. 簡單即是美
  2. 適合自己的就是最好的

掃碼關注公眾號檢視更多原創文章

相關文章