公司成立之初,业务量较小,一个程序包揽了所有的业务逻辑,此时服务器数量少,上线简单,基本开发-测试-上线都是由开发人员完成。

随着业务量逐渐上升,功能增多,代码量增大,而单一功能上线需要重新编译整个程序,编译时间由原来的几秒到几分甚至几十分钟,一方面效率降低,另一方面横向扩容带来的处理性能提升效果逐渐减弱。所以由大一统拆分出各个子模块,将大而全的程序“微服务”化。

微服务的好处自然是不言而喻,但是许多个服务部署、变更也确实让人头疼。

如何解决这个问题呢?百度一下大把的服务治理、服务标准化、流程化,各种名词层出不穷,但就是没有一个具体的实现,对我这种新手真的很不友好。

所以结合具体公司业务,满足线上需求,实现了一套自动发布系统。

背景

我司开发人员完成新功能,测试通过后,再通过脚本上传程序包、启动进程以及一些其他的操作。

对于不是经常变更的业务来说,这么干确实没什么问题,但是我司已经拆出几百个微服务,部署在几百个主机上,而且这样的操作每天都要进行几十甚至上百次的时候,弊端就显现出来了:

  • 编译打包本身耗时很长,再上传到服务器又是漫长的等待
  • 发布时面对一堆零散的脚本,老司机虽然游刃有余,但是这些重复性的工作着实让人厌倦
  • 突发状况需要回退时,又是一阵操作猛如虎

怎么办呢。。。

打包上传时间长?提前把程序包放在仓库,要用的时候直接拿行不行

一堆离散的脚本?老夫来接管脚本,提供一个统一的调用接口ok不

难回退?版本管理想用哪个版本就用哪个版本

为了实现版本管理和发布,我们需要记录服务的版本信息,服务发布实际上就是将对应的主机和服务的某个版本关联。

现有的主机管理是由前一位大佬搭建,技术栈是 Django 1.10.1 ,很老的版本了,为了快速实现功能就在此基础上开发吧。

说干就干,老夫写代码就是一把梭,ctrl+c、 ctrl+v 已是炉火纯青。

服务版本管理

一个服务会有很多个版本,如果用一张表来记录所有的信息,势必会有很多冗余的字段,所以拆分为服务、服务版本两张表,做外键关联。对应到 django 的 model 如下:

我司的代码由自建的gitlab管理,构建也是直接用了gitlab-ci,所以服务表里记录gitlab对应project的地址

from django.conf import settings
from django.db import models class MicroService(models.Model):
LANGUAGE_TYPE = (
('cpp', 'cpp'),
('go', 'go'),
('python', 'python')
('other', 'other')
)
name = models.CharField(u'服务名称', max_length=64)
language = models.CharField(u'语言类型', max_length=16, choices=LANGUAGE_TYPE)
build_orig = models.CharField(u'构建来源', max_length=16, default='git')
build_url = models.CharField(u'构建地址', max_length=128) # gitlab or jenkins 的构建地址,用于触发构建任务
description = models.CharField(u'描述', max_length=256, null=True, blank=True)
created = models.DateTimeField(auto_now_add=True)
created_by = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='created_by', on_delete=models.DO_NOTHING)
updated = models.DateTimeField(auto_now=True)
updated_by = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='updated_by', on_delete=models.DO_NOTHING) class Meta:
db_table = 'micro_service'
unique_together = (('name', ), )
ordering = ['-created']

通过gitlab触发一个构建任务时,服务的某个版本的构建状态有预备、运行中、成功、失败、超时、重复构建,可以使用枚举来记录状态的变化;版本创建完成后不能修改,所以只有创建人和创建时间

from enum import Enum, unique

@unique
class BuildStatus(Enum):
pending = 0
building = 1
success = 2
timeout = 3
failed = 4
duplicate = 5 class MicroServiceVersion(models.Model):
BUILD_STATUS = tuple([(v.value, k) for k, v in BuildStatus.__members__.items()]) microservice = models.ForeignKey(MicroService, on_delete=models.DO_NOTHING)
version = models.CharField(u'版本', max_length=48) # 版本号格式: 时间戳-提交分支-提交id
description = models.CharField(u'描述', max_length=128, null=True, blank=True)
created = models.DateTimeField(auto_now_add=True)
created_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.DO_NOTHING)
status = models.PositiveSmallIntegerField(choices=BUILD_STATUS,default=1)
file_path = models.FilePathField(u'程序包存放路径', max_length=128, null=True, blank=True)
ref = models.CharField(u'构建分支', max_length=128, default='master') class Meta:
db_table = 'micro_service_version'
unique_together=(('microservice', 'version'),)
ordering = ['-created', 'version']

服务实例

服务发布实际上就是将主机和服务的某个版本关联:

  • 部署,在实例表里创建一条主机、服务版本的关联记录
  • 升级、回退,修改对应实例的版本
  • 删除,删除相关数据
状态

当我们进行部署、升级、回退、删除等操作时,可能由于一些原因导致失败,所以用一个字段来记录实例的状态,方便进行后续的重试等操作。

锁定

假如 A用户 正在对 service_a 的实例进行升级操作,那么其他用户不能操作 service_a 的实例,可以将这些实例全部锁定,A用户的操作完成后再解除锁定

对应的 model :

from asset.models import Asset

@unique
class InstanceStatus(Enum):
running = 0 # 运行中 大部分时候处于此状态
installing = 1
upgrading = 2
reverting = 3
deleting = 4
install_failed = 11
upgrade_failed = 12
revert_failed = 13
delete_failed = 14 class MicroServiceInstance(models.Model):
STATUS = tuple([(v.value, k) for k, v in InstanceStatus.__members__.items()]) microservice = models.ForeignKey(MicroService, on_delete=models.DO_NOTHING)
version = models.ForeignKey(MicroServiceVersion, on_delete=models.DO_NOTHING)
host = models.ForeignKey(Asset, on_delete=models.DO_NOTHING)
port = models.IntegerField(u'端口号', null=True, blank=True, )
tag = models.CharField(u'标签', max_length=64, blank=True, null=True)
weight = models.PositiveSmallIntegerField(u'权重', default=100)
description = models.CharField(u'描述', max_length=128, blank=True, null=True)
created = models.DateTimeField(auto_now_add=True)
created_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.DO_NOTHING)
status = models.PositiveSmallIntegerField(u'实例状态', choices=STATUS, default=0)
locked = models.BooleanField(u'操作锁定', default=False)
is_maintain = models.BooleanField(u'是否维护中', default=False) # 保留字段 class Meta:
db_table = 'micro_service_instance'
ordering = ['-created']

理清了服务、版本、实例的关系,建好了数据模型,接下来就是视图了。

最新文章

  1. 51nod 1515 明辨是非 并查集 + set + 启发式合并
  2. 虚拟机去混杂模式与 vlan in vxlan 特性
  3. Web 仪表盘
  4. MySQL数据库优化技术之数据库表的设计
  5. HDU 4336-Card Collector(状压,概率dp)
  6. 使用vagrant作为开发环境后,js报错
  7. jquery封装的选项卡
  8. pragma指令简介
  9. 怎样用C#代码管理SharePoint解决方式
  10. java入门学习(十二)运算语句 if switch
  11. 模拟exit()退出命令实现
  12. SQL server 导出平面文件时出错: The code page on Destination - 3_txt.Inputs[Flat File Destination Input].Columns[UserId] is 936 and is required to be 1252.
  13. io系列之其他事项
  14. 南阳236----心急的C小加
  15. Spark会把数据都载入到内存么?
  16. 10-Linux与windows文件互传-pscp坑---- 'pscp' 不是内部或外部命令,也不是可运行的程序或批处理文件
  17. 测试人必备:国内外最好用的6款Bug跟踪管理系统
  18. nyoj 38 布线问题 Kruskal and Prim
  19. 使用GitHub建立个人网站
  20. Oracle使用split和splitstr函数批量分隔字符串

热门文章

  1. elementUI的导航栏在刷新页面的时候选中状态消失的解决
  2. Product settype acts as a very important role in CRM WebClient UI architecture
  3. ARM处理器基础知识
  4. CentOS6.7搭建部署DHCP服务 (详解主配置文件)
  5. 初步学习JAVA面向对象初步认识及面向对象内存分析图举例说明
  6. Tensorflow简单实践系列(三):图和会话
  7. [TJOI2018]最长上升子序列
  8. JQuery学习笔记之属性与样式
  9. httprunner学习7-extract提取content返回对象
  10. MySQL主从备份