上一篇文章《记一次诡异的故障排查经历》中有介绍到我们的部署程序varian,文章发布后有小伙伴对varian很感兴趣,今天就简单的介绍一下我们的varian,揭开她神秘的面纱~
varian是我们基于Python3编写的一套部署程序,处在整个部署系统的中心,与CMDB、Jenkins、SVN/Git、镜像仓库Harbor、Kubernetes API、通知系统等都有交互,负责将源代码经过一系列的处理后打包成Docker镜像,并发布到各个环境,然后通知相关人员。简化后的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()
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执行即可