上一篇文章《記一次詭異的故障排查經歷》中有介紹到咱們的部署程序varian,文章發佈後有小夥伴對varian很感興趣,今天就簡單的介紹一下咱們的varian,揭開她神祕的面紗~php
varian是咱們基於Python3編寫的一套部署程序,處在整個部署系統的中心,與CMDB、Jenkins、SVN/Git、鏡像倉庫Harbor、Kubernetes API、通知系統等都有交互,負責將源代碼通過一系列的處理後打包成Docker鏡像,併發布到各個環境,而後通知相關人員。簡化後的varian架構以下:java
說到解決的問題,要先聊一下部署系統經歷的幾個迭代版本:node
最先項目比較少,所用架構及技術也比較單一,每一個項目都單獨維護了一個shell腳本作部署,腳本里配置了項目的全部信息,包含服務器列表、代碼路徑等項目特有信息和通知類型等公共信息,各項目腳本之間互不干涉。這樣作的好處是每一個項目部署發佈邏輯都比較簡單,修改任何一個項目都對其餘項目無影響;但缺點也很明顯,各個項目腳本分散,任何項目信息變動都須要取改這個腳本,且一些公共功能的修改就須要全部項目腳本都改一遍,不免不出問題。python
後來隨着項目、服務器數量的增多,引入了CMDB來管理項目和主機的基本信息,純shell的腳本也升級爲了python+shell的腳原本維護編譯部署,把一部分公共模塊例如去CMDB拉取項目下的主機列表、郵件通知等從shell腳本中單獨抽出來用python重構,並用python實現了一個主入口,全部項目部署都經過這個主入口進入,而後調用python或shell腳原本實現部署發佈整過程,這樣解決了腳本分散和公共模塊更新全部項目腳本都要跟着修改的問題,可是添加一個新項目仍是要手動更新一堆的腳本文件,效率低且易出錯,各個項目處理邏輯各不相同,對須要熟悉她的新人很不友好。git
如今線上項目數量已經超過50+,且還在不斷增多,微服務、容器化等新技術也不斷加入,天天進行數十上百次的部署更新,對部署系統的健壯性,擴展性有了更高的要求。基於以前一步步的探索,採用微服務的設計理念,咱們實現瞭如今這一套部署程序varian,效率高、易擴展、出錯率大大下降且對新人友好,解決了以上遇到的全部問題。web
說了這麼多,那varian到底是個什麼樣子呢?docker
Lego積木,就是那種各個不一樣的小模塊能拼裝成各類各樣的建築的玩具。設計的思路也主要採用了lego的方式,把全部的功能都拆分紅一個一個的python類,部署項目時就組裝不一樣的類,例如一個最簡單的純靜態web項目,組裝了「拉代碼模塊」+「JS/CSS合併壓縮模塊」+「分發API模塊」+「郵件通知模塊」,若是是一個純java api項目呢?組裝「拉代碼模塊」+「maven編譯模塊」+「分發API模塊」+「郵件通知模塊」便可,從上邊的例子能夠就能夠看出這種組裝模塊的優點。shell
全部模塊可複用,來了一個新項目根據項目架構、開發語言等因素去判斷目前的模塊是否可以知足,若是能夠知足就直接組裝使用吧,若是確認過眼神,實在知足不了呢?那就新加一個模塊,模塊編寫遵循簡單可複用原則,需考慮到後續有相似功能能夠直接使用此模塊。api
可能會有疑問?那些各個項目不一樣的配置怎麼辦?例如代碼路徑。這裏採用了邏輯(模塊)跟配置拆分的設計方式,全部處理邏輯不涉及任何一個項目特有的屬性,項目特有的屬性都單獨配置,咱們採用CMDB來配置,CMDB裏有一張deploy的表,表關聯project,記錄了項目的特殊屬性,例如通知郵件列表等等,邏輯模塊會調用CMDB API自動取出所需配置信息。bash
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()
複製代碼
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的構建步驟中當作shell執行便可