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

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

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

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

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

背景

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

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

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

怎么办呢。。。

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

一堆离散的脚本?老夫来接管脚本,提供一个统一的调用接口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']

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

Django实现自动发布(1数据模型)的更多相关文章

  1. Django实现自动发布(2视图-任务接收)

    上一篇服务版本的新增,是通过触发 gitlab 任务来实现的,那么如何得到任务的最终状态呢? 好在 gitlab 为我们提供了webhook,也就是消息钩子,可以发送pipeline消息到我们指定的地 ...

  2. Django实现自动发布(2视图-服务管理)

    通常页面要能对资源进行增删改查,对应http的 POST.DELETE.UPDATE.GET 页面显示使用了layui,而layui的表格有自己的数据获取方式,所以我们的视图要做一些调整,不使用后端渲 ...

  3. Django实现自动发布(3发布-升级和回退)

    发布实际上就是将服务的某个版本和一台主机关联,我用一张表(MicroServiceInstance)记录了主机id.服务id.版本id,目前一台主机只能部署一个版本,所以主机id和服务id要做联合索引 ...

  4. Django实现自动发布(3发布-安装)

    相对于服务的升级.回退,新部署一个服务要复杂一些,要满足以下要求: 已经运行了服务实例的主机不能重复部署 进程启动需要的配置文件要先同步到主机上 之前的升级.回退都是指进程的操作,不涉及配置文件的变更 ...

  5. Django实现自动发布(2视图-服务版本查找和新增)

    前面做好了服务的管理,接下来是服务版本的管理,和服务类似,版本也有增删改查.先在服务的管理页面做一个入口,如下图: 需要在上一步的服务管理页面增加按钮.按钮方法,点击按钮跳转时要打开一个新的页面,所以 ...

  6. nginx+uWSGI+django+virtualenv+supervisor发布web服务器

    nginx+uWSGI+django+virtualenv+supervisor发布web服务器   导论 WSGI是Web服务器网关接口.它是一个规范,描述了Web服务器如何与Web应用程序通信,以 ...

  7. eclipse项目自动发布到tomcat目录,缺文件。

    eclipse项目自动发布到tomcat目录,缺文件. 解决方案: 项目--Properties-->Deployment Assembly-->Add--> Folder Add- ...

  8. php利用svn hooks将程序自动发布到测试环境

    利用svn hooks将php程序自动发布到测试环境 复制仓库hooks目录下的post-commit.tmpl为post-commit cp post-commit.tmpl post-commit ...

  9. 一键自动发布ipa(更新svn,拷贝资源,压缩资源,加密图片资源,加密数据文件,加密lua脚本,编译代码,ipa签名,上传ftp)

    一键自动发布ipa(更新svn,拷贝资源,压缩资源,加密图片资源,加密数据文件,加密lua脚本,编译代码,ipa签名,上传ftp) 程序员的生活要一切自动化,更要幸福^_^. 转载请注明出处http: ...

随机推荐

  1. 91.用js遍历原生json数据

    <!doctype html> <html lang="en"> <head>     <meta charset="UTF-8 ...

  2. FastJson--阿里开源的速度最快的Json和对象转换工具 https://www.cnblogs.com/kaituorensheng/p/8082631.html

    import java.util.ArrayList;import java.util.List;import java.util.HashMap;import java.util.Map; impo ...

  3. Django-ModelFrom中修改save后的字段值

    在ModelForm提交中,保持原未修改字段的值,views中部分代码: project = Iredmail.objects.get(id=id) ssh_crt_name = project.ss ...

  4. RHEL6+GFS2+MYSQL高可用

    RHCS集群安装部署 组件介绍: luci: luci是一个基于web的,用来管理和配置RHCS集群,通过luci可以轻松的搭建一个功能强大的集群系统,节点主机可以使用ricci来和luci 管理段进 ...

  5. CentOS6.7搭建部署FTP服务 (详解主配置文件)

    FTP传输 三种解析: username -->UID  :/etc/passwd    将用户名转换成UID的库. hostname--->        IP   :DNS服务,/et ...

  6. scratch2.0的教材视频,王木头系列

    在线视频 http://v.qq.com/vplus/d05a62f676f6f3b6b87401b4530cff9a?page=cover 理论辩证 https://www.sohu.com/a/1 ...

  7. OSI七层模型数据流

    前段时间去学习了思科网络基础CCNA的知识,与我们运维所需的网络基础大同小异,当然其包容性要大很多.我们主要来看下网络方面的内容: 网络七层模型 七层网络模型是我们进行网络间通信的基本理论依据,由上至 ...

  8. phpstorm通过FileWatchers配置自动格式化代码插件

    在自动格式代码的插件中, prettier一直是挺不错的, 这个插件在不同的IDE里有不同的配置地方, 但是配置参数基本上是差不多的. 下面就说明下在phpstorm(版本2019.2)中如何配置的吧 ...

  9. nuxt 项目设置缩进为4个空格

    1..editorconfig 文件下的indent_size: 2更改为indent_size: 4 2..prettierrc 文件 { "singleQuote": true ...

  10. Easyui Datagrid扩展fixRownumber方法 转载

    $.extend($.fn.datagrid.methods, { fixRownumber : function (jq) { return jq.each(function () { var pa ...