去年写过一篇文章『中小团队落地配置中心详解』 https://mp.weixin.qq.com/s/uGUvV4jl4YIvNztuepdC8A , 介绍了我们借助 etcd+confd 实现的配置中心方案, 这是一个对运维友好, 与开发解耦的极佳方案, 经过了一年多的实践也确实帮我们解决了配置文件无版本, 难回滚, 更新复杂等问题
这套配置中心解决方案的特点是, 对整个配置文件进行管理, 而非配置项, 且在配置中心修改的配置, 客户端可以实时自动更新. 同时借助于我们自研的配置中心管理 UI(kerrigan)还能够实现记录修改历史, 快速回滚配置, 与线上配置做对比等实用功能
陆续有小伙伴问我能否写篇文章介绍一下配置中心的管理 UI(Kerrigan)的实现, 咖啡君就通过本篇文章来介绍 Kerrigan 的设计思路, 以及用到的技术和部分核心代码, 由于 kerrigan 有过一次改版, 所以界面会与上面文章中的截图有出入
界面与功能
用户登陆进入会看到一个简单的统计页面, 展示配置文件相关数据
这个实现非常简单就是对数据库数据进行查询统计, 都是类似于下边这样的语句输出的结果
Config.objects.all().count()
当点击 "我的项目" 标签时, 会出现所有的项目, 在这里可以搜索你要操作的项目, 或是新建 / 导入项目
当点击 "新建 / 导入项目" 时, 可以选择从 CMDB 同步项目, 或者自己填写项目名称新建配置中心中的项目, 但由于我们配置中心和 CMDB 是打通的, 配置中心里的所有项目都来源于 CMDB, 保证项目信息一致性, 所以新建项目功能并没有被用到
与 CMDB 系统的同步是通过 http 协议进行了, 当点击 "与 CMDB 同步" 按钮时, 会发送个 get 请求到 cmdb 服务器获取项目信息, cmdb 采用 JWT 认证 https://mp.weixin.qq.com/s/Kgj_5ydnT2W4Gt0vrw7gtw , 主要代码如下:
- headers = {
- "WWW-Authenticate": "Token",
- "Content-Type": "application/json",
- "Authorization": "Token eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1NDgyMjg4MzgsImlhdCI6MTU0ODE0MjQzOCwiZGF0YSI6eyJ1c2VybmFtZSI6ImFkbWluQDE2My5jb20ifX0.oKc0SafgksMT9ZIhTACupUlz49Q5kI4oJA-B8-GHqLA"
- }
- requests.get('https://ops-coffee.cn/api/cmdb/project', headers=headers)
在我的项目页面点击项目时, 会进入项目的配置管理页面, 这个页面列出了项目下的所有配置文件, 也可以通过右上角的 "添加配置" 按钮添加配置文件
当添加配置文件时, 会做三件事情:
配置文件表 (Config) 添加一条新数据
历史记录表 (History) 添加一条新数据, 作为历史版本
往 etcd 里写入一条新的 KV 数据, 其中 key 为: 项目 + 环境 + 服务 + 文件名称的组合, 保证在 etcd 内唯一
操作 etcd 的代码如下:
- class EtcdApi:
- def __init__(self):
- self.client = etcd.Client(
- host=str(self.ETCD_HOST),
- port=int(self.ETCD_PORT),
- username=str(self.ETCD_USER),
- password=str(self.ETCD_PASS)
- )
- def read(self, key):
- try:
- kx = self.client.read(key)
- return {"state": 1, "message": "","action": kx.action,"key": kx.key,"value": kx.value,
- "newKey": kx.newKey, "dir": kx.dir, "_children": kx._children}
- except Exception as e:
- return {"state": 0, "message": str(e)}
- def write(self, key, value):
- try:
- kx = self.client.write(key, value)
- return {"state": 1, "message": "","action": kx.action,"key": kx.key,"newKey": kx.newKey,
- "dir": kx.dir, "_children": kx._children}
- except Exception as e:
- return {"state": 0, "message": str(e)}
- def delete(self, key, recursive=False, dir=False):
- try:
- if dir:
- kx = self.client.delete(key, recursive, True)
- return {"state": 1, "message": "","action": kx.action,"key": kx.key,"newKey": kx.newKey,
- "dir": kx.dir, "_children": kx._children}
- else:
- kx = self.client.delete(key)
- return {"state": 1, "message": kx}
- except Exception as e:
- return {"state": 0, "message": str(e)}
当编辑和删除配置文件时, 操作与新建类似, 修改 Config 表数据 -->Histror 表添加新数据 -->修改或删除 etcd 数据, History 表在每次新建或修改配置时都需要添加一条新数据, 这里使用到了 Django 的信号 Signales https://mp.weixin.qq.com/s/cMxdAfsTno56ixurmD4KXA 来实现, 主要代码如下:
- @receiver(signals.post_init, sender=Config)
- def migrate_notify_init(instance, **kwargs):
- instance.old_content = instance.content
- @receiver(signals.post_save, sender=Config)
- def migrate_notify_post(instance, created, **kwargs):
- _t = Setting.objects.get(key='enable_etcd')
- # 每次新建或者 content 变更都往历史表里插入一条历史数据
- if created or instance.old_content != instance.content:
- History.objects.create(
- config=instance,
- user=instance.user,
- content=instance.content
- )
除了 History 表操作之外, 对于 etcd 的操作以及下边要说到的发布功能也是在 signales 里完成的, signals 可以简化代码强化逻辑
当点击 "编辑" 按钮后, 会进入配置文件编辑页面, 在这里可以修改, 保存或发布配置文件, 也可以拿当前配置文件与已发布配置文件做对比
这里 "保存" 和 "发布" 的区别在于, 保存只会将配置文件保存在 Kerrigan 内, 不会修改 etcd 里的数据, 从而实现客户端不更新, 而发布会直接修改 etcd 里的数据, 客户端能够直接更新, 对于未发布的配置文件, 当你点击配置文件时会有如下的提示, 你可以对比或者发布
判断是否发布主要是在 Config 表里加入了 is_published 字段, 同样通过 signals 的 post_save 信号在每次保存时检查这个字段, 如果为 True, 则修改对应 etcd 的值, 否则不处理
- @receiver(signals.post_save, sender=Config)
- def migrate_notify_post(instance, created, **kwargs):
- ...
- # 判断状态为发布且开启了 etcd, 则更新数据到 etcd
- if instance.is_published:
- _r = EtcdApi().write(key, instance.content)
- if _r.get('state') == 0:
- raise '写入 key:%s 失败' % (key)
系统中多次出现 "对比" 功能, 都指的是当前配置文件和已发布配置文件的对比, 通过对比可以清晰的看出修改的内容, 对比结果展示如下
对比功能主要用到了 difflib 模块, 主要代码如下:
difflib.htmlDiff().make_file(src_value, diff_value, context=True, numlines=3)
每一次的添加或者修改都会往 History 表里写入一条新数据,"历史版本" 便是直接读的 History 表, 展示出谁在什么时间修改了什么内容
当点击历史版本时可以查看此版本的配置文件内容, 同时在必要的时候回滚, 有了历史版本的内容, 回滚也只是将历史内容覆盖到 etcd
至此, Kerrigan 介绍完成, 其最主要的功能是通过 web 浏览器来操作 etcd 里的 KV 数据, 在此基础上做了扩展, 对每一次的修改都做了记录, 以实现实用的保存, 发布, 历史, 回滚等功能
最后再回顾一下整个配置中心的工作流程, 配置管理员通过 Kerrigan 来添加或修改配置文件, Kerrigan 记录修改, 同时将修改同步至 etcd, 客户端上的 confd 服务在检测到 etcd 对应 key 的数据发生变化时, 会自动拉取数据覆盖至本地配置文件, 然后配合 check_cmd 和 reload_cmd 指令对配置文件进行检查和重载, 更多细节原理回顾文章『中小团队落地配置中心详解』 https://mp.weixin.qq.com/s/uGUvV4jl4YIvNztuepdC8A
来源: https://www.cnblogs.com/37Y37/p/12143246.html