一、 前言
1.1 简介
CMDB(Configuration Management Database)配置管理数据库,是所有运维工具的数据基础。70%~80%的IT相关问题与环境的变更有着直接的关系。实施变更管理的难点和重点并不是工具,而是流程。即通过一个自动化的、可重复的流程管理变更,使得当变更发生的时候,有一个标准化的流程去执行,能够预测到这个变更对整个系统管理产生的影响,并对这些影响进行评估和控制。而变更管理流程自动化的实现关键就是CMDB。
1.2 功能
应该知道包含这几种功能:整合、调和、同步、映射和可视化
- 用户管理,记录测试,开发,运维人员的用户表
- 业务线管理,需要记录业务的详情
- 项目管理,指定此项目用属于哪条业务线,以及项目详情
- 应用管理,指定此应用的开发人员,属于哪个项目,和代码地址,部署目录,部署集群,依赖的应用,软件等信息
- 主机管理,包括云主机,物理机,主机属于哪个集群,运行着哪些软件,主机管理员,连接哪些网络设备,云主机的资源池,存储等相关信息
- 主机变更管理,主机的一些信息变更,例如管理员,所属集群等信息更改,连接的网络变更等
- 网络设备管理,主要记录网络设备的详细信息,及网络设备连接的上级设备
- IP管理,IP属于哪个主机,哪个网段, 是否被占用等
二、 四种实现方式
2.1 Agent方式
-
流程分析
优缺点分析:
优点: 速度快,使用于服务器多的大型公司
缺点: 需要为每一台服务器都部署一个Agent程序,机器过多时耗费的人力成本大
2.2 ssh方式(基于paramiko模块)
-
流程分析
优缺点分析:
优点: 不需要为每一台服务器都部署一个Agent程序,适用于服务器较少的情况
缺点: 需要登录,执行速度慢,需要部署一台中控机
import paramiko #创建ssh对象 ssh = paramiko.SSHClient() # 连接服务器 ssh.connect(hostname=\'localhost\', port=22, username=\'root\', password=\'123\') # 执行命令 stdin, stdout, stderr= ssh.exec_command(\'ifconfig\') # 拿到命令的执行结果 res = stdout.read() # 关闭连接 ssh.close()
2.3 saltstack方式
-
流程分析
优缺点分析:
优点: 速度快,开发成本低
缺点: 需要依赖于第三方工具,需要部署中控机
- saltstack安装与配置
1. 安装
master端
# 安装salt-master
yum install salt-master
# 修改配置文件:/etc/salt/master
interface: 0.0.0.0 # 表示Master的IP
# 启动
service salt-master start
slave端:
# 安装salt-minion
yum install salt-minion
# 修改配置文件 /etc/salt/minion
master: 10.211.55.4 # master的地址
或
master:
- 10.211.55.4
- 10.211.55.5
random_master: True
id: c2.salt.com # 客户端在salt-master中显示的唯一ID
# 启动
service salt-minion start
2. 授权
"""
salt-key -L # 查看已授权和未授权的slave
salt-key -a salve_id # 接受指定id的salve
salt-key -r salve_id # 拒绝指定id的salve
salt-key -d salve_id # 删除指定id的salve
"""
3. 执行
# 在master服务器上对salve进行远程操作
salt \'c2.salt.com\' cmd.run \'ifconfig\'
# 基于API的方式
import salt.client
local = salt.client.LocalClient()
result = local.cmd(\'c2.salt.com\', \'cmd.run\', [\'ifconfig\'])
2.4 Puppet方式(了解)
- 通过RPC消息队列将执行的结果返回给用户!年代久远,作为了解,不做叙述
三、 表结构设计
首先,创建一个Django项目,由于我们的数据表既与后台管理有关又与API有关,所以我们在设计表结构时又新创建了两个APP(backend,warehouse),这样设计的好处就是相互独立又方便三者间的关联。
然后我们在warehouse的models中创建数据库模型
from django.db import models # Create your models here. class UserInfo(models.Model): \'\'\' 用户信息 \'\'\' name = models.CharField(verbose_name=\'姓名\', max_length=32) age = models.CharField(max_length=11, verbose_name=\'年龄\') gender = models.CharField(max_length=11, verbose_name=\'性别\') email = models.EmailField(verbose_name=\'邮箱\') phone = models.CharField(verbose_name=\'手机\', max_length=32) class Meta: verbose_name_plural = \'用户表\' def __str__(self): return self.name class UserGroup(models.Model): \'\'\' 用户组 \'\'\' name = models.CharField(max_length=32, verbose_name=\'组名\') users = models.ManyToManyField(\'UserInfo\', verbose_name=\'组成员\') class Meta: verbose_name_plural = \'用户组表\' def __str__(self): return self.name class BusinessUnit(models.Model): \'\'\' 业务线 \'\'\' name = models.CharField(max_length=32) contact = models.ForeignKey(\'UserGroup\', verbose_name=\'业务联系人\') manager = models.ForeignKey(\'UserGroup\', verbose_name=\'管理人员\', related_name=\'aaa\') class Meta: verbose_name_plural = \'业务线表\' def __str__(self): return self.name class Idc(models.Model): \'\'\' 机房信息 \'\'\' name = models.CharField(max_length=32, verbose_name=\'机房名\') floor = models.IntegerField(default=10, verbose_name=\'楼层\') class Meta: verbose_name_plural = \'机房信息表\' def __str__(self): return self.name class Tag(models.Model): \'\'\' 资产标签 \'\'\' name = models.CharField(\'标签\', max_length=32, unique=True) class Meta: verbose_name_plural = "标签表" def __str__(self): return self.name class Asset(models.Model): \'\'\' 资产信息表 \'\'\' type_choices = ( (1, \'服务器\'), (2, \'交换机\'), (3, \'防火墙\') ) status_choices = ( (1, \'上架\'), (2, \'在线\'), (3, \'离线\'), (4, \'下架\') ) device_type_id = models.IntegerField(choices=type_choices, default=1) device_status_id = models.IntegerField(choices=status_choices, default=1) cabinet_num = models.CharField(max_length=32, verbose_name=\'机柜号\', null=True, blank=True) cabinet_order = models.CharField(max_length=32, verbose_name=\'机柜序号\', null=True, blank=True) idc = models.ForeignKey(\'Idc\', verbose_name=\'IDC机房\', null=True, blank=True) business_unit = models.ForeignKey(\'BusinessUnit\', verbose_name=\'属于的业务线\', null=True, blank=True) tag = models.ManyToManyField(\'Tag\') latest_date = models.DateField(null=True) create_at = models.DateTimeField(auto_now_add=True) class Meta: verbose_name_plural = "资产表" def __str__(self): return "%s-%s-%s" % (self.idc.name, self.cabinet_num, self.cabinet_order) class NetworkDevice(models.Model): \'\'\' 网络设备 \'\'\' asset = models.OneToOneField(\'Asset\') management_ip = models.CharField(max_length=64, verbose_name=\'管理ip\', null=True, blank=True) vlan_ip = models.CharField(max_length=64, verbose_name=\'VLANIP\', null=True, blank=True) intranet_ip = models.CharField(max_length=128, verbose_name=\'内网IP\', null=True, blank=True) sn = models.CharField(max_length=64, verbose_name=\'sn号\', null=True, blank=True) manufacture = models.CharField(max_length=128, verbose_name=\'制造商\', null=True, blank=True) model = models.CharField(max_length=128, verbose_name=\'型号\', null=True, blank=True) port_num = models.SmallIntegerField(verbose_name=\'端口数量\', null=True, blank=True) device_detail = models.CharField(max_length=255, verbose_name=\'设置详细配置\', null=True, blank=True) class Meta: verbose_name_plural = "网络设备表" class Server(models.Model): \'\'\' 服务器 \'\'\' asset = models.OneToOneField(\'Asset\') hostname = models.CharField(max_length=32, unique=True) sn = models.CharField(max_length=64, db_index=True) manufacturer = models.CharField(max_length=64, verbose_name=\'制造商\', null=True, blank=True) model = models.CharField(max_length=64, verbose_name=\'型号\', blank=True, null=True) manage_ip = models.GenericIPAddressField(verbose_name=\'管理IP\', null=True, blank=True) os_platform = models.CharField(max_length=32, verbose_name=\'系统\', null=True, blank=True) os_version = models.CharField(max_length=32, verbose_name=\'系统版本\', null=True, blank=True) cpu_count = models.IntegerField(verbose_name=\'CPU数量\', null=True, blank=True) cpu_physical = models.IntegerField(verbose_name=\'CPU物理数量\', null=True, blank=True) cpu_model = models.CharField(max_length=128, verbose_name=\'CPU型号\', null=True, blank=True) create_time = models.DateTimeField(auto_now_add=True, blank=True) class Meta: verbose_name_plural = "服务器表" def __str__(self): return self.hostname class Disk(models.Model): \'\'\' 硬盘信息 \'\'\' slot = models.CharField(max_length=12, verbose_name=\'插槽位\') model = models.CharField(max_length=32, verbose_name=\'磁盘型号\') capacity = models.CharField(max_length=32, verbose_name=\'磁盘容量GB\') pd_type = models.CharField(max_length=32, verbose_name=\'磁盘类型\') server = models.ForeignKey(\'Server\', related_name=\'disk\') class Meta: verbose_name_plural = "硬盘表" def __str__(self): return self.slot class Nic(models.Model): \'\'\' 网卡信息 \'\'\' name = models.CharField(max_length=32, verbose_name=\'网卡名称\') hwaddr = models.CharField(max_length=64, verbose_name=\'网卡MAC地址\') netmask = models.CharField(max_length=64) ipaddrs = models.CharField(max_length=256, verbose_name=\'IP地址\') up = models.BooleanField(default=False) server = models.ForeignKey(\'Server\', related_name=\'nic\') class Meta: verbose_name_plural = "网卡表" def __str__(self): return self.name class Memory(models.Model): \'\'\' 内存信息 \'\'\' slot = models.CharField(max_length=12, verbose_name=\'插槽位\') model = models.CharField(max_length=64, verbose_name=\'内存型号\') manufacturer = models.CharField(max_length=32, verbose_name=\'制造商\', null=True, blank=True) capacity = models.FloatField(verbose_name=\'容量\', null=True, blank=True) sn = models.CharField(max_length=64, verbose_name=\'sn号\', null=True, blank=True) speed = models.CharField(max_length=16, verbose_name=\'速度\', null=True, blank=True) class Meta: verbose_name_plural = "内存表" def __str__(self): return self.slot class AssetRecord(models.Model): \'\'\' 资产变更记录表 \'\'\' asset = models.ForeignKey(\'Asset\') content = models.TextField(null=True) creator = models.ForeignKey(\'UserInfo\', null=True, blank=True) create_time = models.DateTimeField(auto_now_add=True) class Meta: verbose_name_plural = "资产记录表" def __str__(self): return \'<{}> <{}> <{}>\'.format(self.asset.idc.name, self.asset.cabinet_num, self.asset.cabinet_order) class ErrorLog(models.Model): \'\'\' 错误日志记录 \'\'\' asset = models.ForeignKey(\'Asset\', null=True, blank=True) title = models.CharField(max_length=64) content = models.TextField() create_time = models.DateTimeField(auto_now_add=True) class Meta: verbose_name_plural = "错误日志表" def __str__(self): return self.title