一、CMDB前戏
# 项目开发流程 1.需求分析 产品经理 开发人员 客户等三方会议 2.架构设计 框架的选择 语言选择 数据库选择 3.分组开发 小组成员各自开发各自的功能(可能也会有交集) 4. 项目测试 1.程序员自己预测 2.测试人员全方面测试 5.交付上线 运维人员上线及维护程序运行 本质:开发将写好的代码给运维
# 1.代码上线 传统: 开发将写好的代码压缩之后以邮件的形式发送给运维 运维解压之后将项目部署到对应的服务(nginx,apache) 缺点: 上线效率低、人力成本大 解决措施: 开发一个代码上线的程序,让用户通过鼠标点点点即可完成代码的上线,从而不需要运维的参与 必备条件: 服务器的IP地址、服务器磁盘空间、CPU信息等服务器相关的元信息 # 2.监控服务 传统: 执行shell脚本 缺点: 实时率很低、不能自动化 解决措施: 开发一个监控服务器的python程序 将数据通过前端实时展示出来kibana 必备条件: 服务器的IP地址、服务器磁盘空间、CPU信息等服务器相关的元信息 # 3.装机服务 传统: 吃住都在机房,人工一台一台的装 缺点: 人力消耗过大 健康风险 效率低下 解决措施: 插上网线远程一键装机 必备条件: 服务器的IP地址、服务器磁盘空间、CPU信息等服务器相关的元信息 # 4.资产统计 传统: 使用excel表格记录 缺点: 变更记录一致性无法保证 长期下来文件过于混乱 解决措施: 自动统计、自动变更 必备条件: 服务器的IP地址、服务器磁盘空间、CPU信息等服务器相关的元信息 """ 都需要必备条件>>>:获取服务器相关元信息 """ CMDB:服务器资产管理系统 很多自动化运维相关的程序都需要获取服务器数据 CMDB就是这些程序的基石
二、CMDB整体架构
# CMDB是自动化运维的基石 """ 1.利用python执行linux命令获取数据 2.利用HTTP协议将数据以post方式发送出去 """
简单架构图
三、CMDB四套方案
"""业内就四套方案""" 1.python脚本方案(agent方案) web服务 <==> 数据库 <==> API程序 <==> agent(部署到服务器上的python服务) 2.ssh类方案(paramiko模块) paramiko能够支持python代码远程链接服务器并操作服务器 运维工具ansible底层使用的也是paramiko web服务 <==> 数据库 <==> API程序 <==> 中控机(paramiko) <==> 服务器
import paramiko # 创建SSH对象 ssh = paramiko.SSHClient() # 允许链接不在know_hosts文件中的主机 ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # 连接服务器 ssh.connect(hostname='192.168.10.1', port=2222, username='root', password='root@123') # 执行命令 stdin, stdout, stderr = ssh.exec_command('df -lh') """ stdin 输入额外的命令s stdout 正确的输出结果 stderr 错误的输出结构 """ # 获取命令结果 result = stdout.read() print(result) # 关闭链接 ssh.close()
# 上述两种方案孰优孰劣??? """ 上述两套方案对比 agent方案 优点 定时执行agent脚本,速度快 缺点 每次都需要部署 应用场景 服务器数量特别多(新浪目前使用的就是该方案 3万台+服务器) ssh类 优点 不需要部署agent服务 缺点 使用paramiko登陆服务器速度比较慢 应用场景 服务器较少(百台为界限) """ 3.saltstack方案 saltstack也是用python写的一个软件 master与所有minion彼此之间底层通过两个zeromq消息队列进行数据交互 web服务<==>数据库<==>API程序<==>中控机(salt-master)<==>服务器(salt-minion) 优点 不需要写任何代码,直接在中控机和服务器上yum install salt-master/minion 使用场景 服务器上已经部署了saltstack,那就多一事不如少一事 """ 步骤1: master端 1.安装 yum install salt-master 2.修改配置文件 /etc/salt/master的IP interface:10.0.0.1 # 表示master的IP 3.启动 service salt-master start 4.查看服务状态 service salt-master status minion端 1.安装 yum install salt-minion 2.修改配置文件 /etc/salt/minion master:10.0.0.1 # master地址 或者 master -10.0.0.1 -10.0.0.2 -10.0.0.3 ... 3.启动 sevice salt-minion start 4.查看进程 ps aux|grep salt 步骤2:授权中控机可以访问的服务器 主要命令 1.salt-key -L # 查看已授权和未授权的salve 2.salt-key -a salve_id # 接收指定id的salve 3.salt-key -r salve_id # 拒绝指定id的salve 4.salt-key -d salve_id # 删除指定id的salve 5.salt-key -A # 接收所有的未授权的salve 步骤3:执行命令 salt '*' cmd.run 'ifconfig' """ 4.puppet方案(不用) 较老,底层用ruby on rails编写,目前基本不用了 新浪第一代cmdb使用的就是puppt,后来ruby使用者较少,比便于后续编写及维护所以之后基本不在使用了 架构跟salt-stack方案一致,大致每30分钟统计一次 # 总结 我们CMDB用哪套方案 三套全部写 不同的公司可能会采用不同的方案 我们直接一次性全部写完,然后将功能基于django 中间件思想弄成可配置的服务 这样不同的公司采取不同的方案我们只需要在配置文件中修改即可
四、Django重要思想
1.django settings源码及实际应用 django Web框架 主要是专注于开发app django请求生命周期 浏览器 web服务网关接口 django中间件 路由层 视图层 模板层 模型层 """ 在django中有两个配置文件 一个是暴露给用户可以自定义的配置文件 一个是框架全局的配置文件 from django.conf import settings 通过上述的模块导入,会发现settings既可以点出用户自定义配置文件里面的配置 也可以点出全局配置文件的配置 并且django的配置文件可以做到针对自定义配置和全局配置都有的配置 如果用户配置了就用用户的 如果用户没有配置就用默认的 """
# django settings源码 from django.conf import settings settings = LazySettings() class LazySettings(LazyObject): def _setup(self, name=None): # settings_module = 'MyBBS.settings' # os.environ类似一个全局的空字典 settings_module = os.environ.get(ENVIRONMENT_VARIABLE) self._wrapped = Settings(settings_module) class Settings: def __init__(self, settings_module): # 先将全局配置文件里面所有的配置复制给settings对象 for setting in dir(global_settings): if setting.isupper(): setattr(self, setting, getattr(global_settings, setting)) self.SETTINGS_MODULE = settings_module # from MyBBS import settings # import_module模块能够将字符串拆成上面from .. import ..模式 mod = importlib.import_module(self.SETTINGS_MODULE) # 再将自定义配置里的所有配置赋值给settings对象,如果两者有重复的,以下面的为准 for setting in dir(mod): if setting.isupper(): setting_value = getattr(mod, setting) setattr(self, setting, setting_value)
# os.environ使用
# a,b2个py文件 # a.py import os # print(os.environ) # os.environ['name']='simon' # print(os.environ.get('name')) import b print(dir(b)) # 拿到所有变量 # ['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'age', 'name'] res = getattr(b,'age') print(res) # 18 # b.py name = 'simon' age = '18'
import_module模块
# 新建目录aaa,将b.py拖到里面去 # 在a.py中获取b的变量 import importlib str1='aaa.b' # from aaa import b 等价于下面这句 res = importlib.import_module(str1) print(res.name) # simon # import_module 在django中间件中使用
基于django settings源码开发项目
# 和django settings一样设置2套settings,用户配置以及全局配置,根据配置,如果用户配置没有设置就获取全局配置里的默认配置
# 目录
settings_global
--conf
-- settings.py
--lib
--config
-- __init__.py
-- global_settings.py
start.py
# 代码
# star.py
import os
# if __name__ == '__main__':
# 现在全局的大字典中添加暴露给用户自定义配置文件字符串路径
os.environ.setdefault("XXX", "conf.settings")
from lib.config import settings
print(settings.NAME)
# global_settings.py
# 项目默认的全局配置
NAME = '项目默认的全局配置'
A = '哈哈哈'
# __init__
from lib.config import global_settings
import os
import importlib
class LazySettings:
def __init__(self):
# 先读取全局配置
# 将global_settings所有的属性名取出来
for name in dir(global_settings):
# 判断是否是纯大写
if name.isupper():
# 获取属性名对应的属性值
k = name
v = getattr(global_settings,k)
# 将k v设值到对象中
setattr(self,k,v)
# 再读取局部配置
# 先获取局部配置文件字符串路径
str_path = os.environ.get('XXX')
# 利用importlib模块导入配置文件
module = importlib.import_module(str_path)
# 循环读取自定义配置文件中所有的属性名
for name in dir(module):
# 判断是否是纯大写
if name.isupper():
# 获取属性名对应的属性值
k = name
v = getattr(module,k)
# 将k v设值到对象中
setattr(self,k,v)
settings = LazySettings()
# conf/settings.py
# 暴露给用户的自定义配置
# NAME = '暴露给用户的自定义配置'
# 启动start.py时,如果没注销conf/settings.py中的Name获取的就是settings.py中的变量
# 如果注销了,就过去到global_settings.py中的Name