CMDB

一:IT运维的分类

  IT运维,指的是对已经搭建好的网络、软件、硬件进行维护。运维领域也是细分的,有硬件运维和软件运维。html

  硬件运维主要包括对基础设施的运维,例如机房的设备,主机的键盘,内存等物理设备的维护。web

  软件运维主要包括系统运维和应用运维,系统运维主要包括对OS,数据库,中间件的监控和维护,这些系统介于设备和应用之间,应用运维主要是对线上业务系统的运维。shell

  这里主要讨论的是软件运维的自动化,包括系统运维和应用运维的自动化。数据库

二:传统运维的缺点

  1:平常工做繁琐

  平常运维工做繁琐,研发会常常须要到服务器上查看日志,重启应用,或者是上线某个产品须要部署环境等,都是运维的平常。django

  2:应用运行环境不统一

  在部署某个应用后,应用不能访问,在开发环境运行的好,可是在测试环境后就不能继续用了,由于各种环境的类库不统一。还有一种状况是,因为运维人员的习惯不一样,按照本身的习惯来安装部署环境,每种服务器上运行的软件目录不统一。服务器

  3:运维及部署效率低下

  运维人员须要登陆到服务器上执行命令,部署程序,不只效率低,而且很是容易出现人为错误,人为出错以后也不容易找到问题所在。网络

  4:无用报警信息过多

  运维人员常常会收到不少的无用报警信息,经常会选择屏蔽这些报警信息,而且一旦应用的访问速度出了问题,就须要从系统、网络、应用、数据库等一步步查找信息。app

  5:资产管理和应用系统混乱

  资产管理,服务管理常常记录在Excel或者文本里面,不便于管理。老员工因为熟悉不注重文档的维护,新员工入职时,资产才能更正一次。运维

三:为何须要自动化运维?

  1:项目上线

  流程:产品经理调研(画出原型图)-->定需求-->三方会谈(研发,产品经理,老大们)-->定日期-->测试项目-->最终上线-->应用运维dom

  目前:将代码打包给运维,运维解压上线

  问题:随着机器数量的线性增长,运维的工做量也是线性增长,重复并且是毫无心义的劳动

  解决:

    1:写一个shell脚本,进行部署

    2:搞一个自动化代码上线系统

      必要条件:服务器的各类信息(主机名,CPU,硬盘大小等)

  2:监控系统

  监测服务器的各类信息(硬盘是否满,CPU的使用率,内存使用率,网站服务运行是否正常)

  问题:以前简单的脚本,监测服务器的信息,比较麻烦

  解决:想将服务器的各类信息,以图表的形式展现在web界面上(可视化)

  必要条件:服务器的各类信息(主机名,CPU,硬盘大小等)

  3:自动装机系统

  问题:人工装机须要一台一台去装

  解决:搞一个装机系统,cobbler软件

  必要条件:服务器的各类信息(主机名,CPU等)

  4:Excel表格审计管理资产

四:资产管理系统(CMDB)

CMDB是全部运维工具的数据基础,CMDB全称Configuration Management Database

1,CMDB包含的功能:

  1:用户管理,记录测试,开发,运维人员的用户表

  2:业务线管理,须要记录业务的详情

  3:项目管理,指定此项目需属于那条业务线,以及项目详情

  4:应用管理,指定此应用的开发人员,属于哪一个项目,和代码地址,部署目录,部署集群,依赖的应用,软件等信息。

  5:主机管理,包括云主机,物理机,主机属于哪一个集群,运行着哪些软件,主机管理员,链接着哪些网络设备,云主机的资源地,存储等相关信息。

  6:主机变动管理,主机的一些信息变动,例如管理员,所属集群等信息更改,链接的网络变动等。

  7:网络设备管理,主要记录网络设备的详细信息,及网络设备链接的上级设备

  8:IP管理,IP属于哪一个主机,哪一个网段,是否被占用等

2,CMDB实现的四种方式:

  方式一:Agent方式

  能够将服务器上面的Agent程序做定时任务,定时将资产信息提交到指定API录入数据库

本质就是在各个服务器上执行subprocess.getoutput("命令"),而后将每台机器上执行的结果返回给主句API,而后主机API收到这些数据以后,放到数据库中,最终经过web界面展示给用户。

优势:速度快
缺点:须要为每台服务器部署有关Agent程序
使用场景:服务器比较多的时候

  方式二:ssh类实现方式(基于paramiko模块)

  中控机经过Paramiko(py模块)登陆到各个服务器上,而后执行命令的方式去获取各个服务器上的信息。

优势:没有Agent
缺点:有一个中控机,速度慢
使用场景:服务器比较少的时候

  方式三:salt-stack方式

此方案本质上和第二种方案是差很少的流程,中控机发送命令给服务器执行。服务器将结果放入另外一个队列中,中控机获取将服务信息发送到API进而录入到数据库。

优势:速度快,开发成本低
缺点:依赖于第三方工具
使用场景:公司已经使用salt-stack软件

saltstack的安装和配置

1:安装和配置

master端:
"""
1. 安装salt-master
    yum install salt-master
2. 修改配置文件:/etc/salt/master
    interface: 0.0.0.0    # 表示Master的IP 
3. 启动
    service salt-master start
"""
slave端:
"""
1. 安装salt-minion
    yum install salt-minion
2. 修改配置文件 /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
3. 启动
    service salt-minion start
"""
View Code

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
"""
View Code

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'])

参考安装:

http://www.cnblogs.com/tim1blog/p/9987313.html

https://www.jianshu.com/p/84de3e012753

  方式四:puppet方式(Ruby写的,了解)

  每隔30分钟,经过RPC消息队列将执行的结果返回给用户

 AES介绍

from Crypto.Cipher import AES 
def encrypt(message):
    key = b'dfdsdfsasdfdsdfs'
    cipher = AES.new(key, AES.MODE_CBC, key)
    ba_data = bytearray(message,encoding='utf-8')
    v1 = len(ba_data)
    v2 = v1 % 16
    if v2 == 0:
        v3 = 16
    else:
        v3 = 16 - v2
    for i in range(v3):
        ba_data.append(v3)
    final_data = ba_data.decode('utf-8')
    msg = cipher.encrypt(final_data) # 要加密的字符串,必须是16个字节或16个字节的倍数
    return msg 
# ############################## 解密 ##############################
def decrypt(msg):
    from Crypto.Cipher import AES 
    key = b'dfdsdfsasdfdsdfs'
    cipher = AES.new(key, AES.MODE_CBC, key)
    result = cipher.decrypt(msg) # result = b'\xe8\xa6\x81\xe5\x8a\xa0\xe5\xaf\x86\xe5\x8a\xa0\xe5\xaf\x86\xe5\x8a\xa0sdfsd\t\t\t\t\t\t\t\t\t'
    data = result[0:-result[-1]]
    return str(data,encoding='utf-8')
msg = encrypt('你好好爱好爱好sss')
res = decrypt(msg)
print(res)
View Code

字符串格式化字符

String.prototype.format = function(args){
        return this.replace(/\{(\w+)\}/g, function(s, i){
            return args[i];
        });
    };
View Code

 CMDB表结构

from django.db import models

class UserProfile(models.Model):
    """
    用户信息
    """
    name = models.CharField(u'姓名', max_length=32)
    email = models.EmailField(u'邮箱')
    phone = models.CharField(u'座机', max_length=32)
    mobile = models.CharField(u'手机', max_length=32)
    password = models.CharField(u'密码', max_length=64)
    class Meta:
        verbose_name_plural = "用户表"
    def __str__(self):
        return self.name

class UserGroup(models.Model):
    """
    用户组
    """
    name = models.CharField(max_length=32, unique=True)
    users = models.ManyToManyField('UserProfile')
    class Meta:
        verbose_name_plural = "用户组表"
    def __str__(self):
        return self.name

class BusinessUnit(models.Model):
    """
    业务线
    """
    name = models.CharField('业务线', max_length=64, unique=True)
    contact = models.ForeignKey('UserGroup', verbose_name='业务联系人', related_name='c')
    manager = models.ForeignKey('UserGroup', verbose_name='系统管理员', related_name='m')
    class Meta:
        verbose_name_plural = "业务线表"
    def __str__(self):
        return self.name

class IDC(models.Model):
    """
    机房信息
    """
    name = models.CharField('机房', max_length=32)
    floor = models.IntegerField('楼层', default=1)
    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):
    """
    资产信息表,全部资产公共信息(交换机,服务器,防火墙等)
    """
    device_type_choices = (
        (1, '服务器'),
        (2, '交换机'),
        (3, '防火墙'),
    )
    device_status_choices = (
        (1, '上架'),
        (2, '在线'),
        (3, '离线'),
        (4, '下架'),
    )
    device_type_id = models.IntegerField(choices=device_type_choices, default=1)
    device_status_id = models.IntegerField(choices=device_status_choices, default=1)
    cabinet_num = models.CharField('机柜号', max_length=30, null=True, blank=True)
    cabinet_order = models.CharField('机柜中序号', max_length=30, 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('管理IP', max_length=64, blank=True, null=True)
    vlan_ip = models.CharField('VlanIP', max_length=64, blank=True, null=True)
    intranet_ip = models.CharField('内网IP', max_length=128, blank=True, null=True)
    sn = models.CharField('SN号', max_length=64, unique=True)
    manufacture = models.CharField(verbose_name=u'制造商', max_length=128, null=True, blank=True)
    model = models.CharField('型号', max_length=128, null=True, blank=True)
    port_num = models.SmallIntegerField('端口个数', null=True, blank=True)
    device_detail = models.CharField('设置详细配置', max_length=255, null=True, blank=True)
    class Meta:
        verbose_name_plural = "网络设备"

class Server(models.Model):
    """
    服务器信息
    """
    asset = models.OneToOneField('Asset')
    hostname = models.CharField(max_length=128, unique=True)
    sn = models.CharField('SN号', max_length=64, db_index=True)
    manufacturer = models.CharField(verbose_name='制造商', max_length=64, null=True, blank=True)
    model = models.CharField('型号', max_length=64, null=True, blank=True)
    manage_ip = models.GenericIPAddressField('管理IP', null=True, blank=True)
    os_platform = models.CharField('系统', max_length=16, null=True, blank=True)
    os_version = models.CharField('系统版本', max_length=16, null=True, blank=True)
    cpu_count = models.IntegerField('CPU个数', null=True, blank=True)
    cpu_physical_count = models.IntegerField('CPU物理个数', null=True, blank=True)
    cpu_model = models.CharField('CPU型号', max_length=128, null=True, blank=True)
    create_at = 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=8)
    model = models.CharField('磁盘型号', max_length=32)
    capacity = models.FloatField('磁盘容量GB')
    pd_type = models.CharField('磁盘类型', max_length=32)

    server_obj = 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=128)
    hwaddr = models.CharField('网卡mac地址', max_length=64)
    netmask = models.CharField(max_length=64)
    ipaddrs = models.CharField('ip地址', max_length=256)
    up = models.BooleanField(default=False)
    server_obj = 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=32)
    manufacturer = models.CharField('制造商', max_length=32, null=True, blank=True)
    model = models.CharField('型号', max_length=64)
    capacity = models.FloatField('容量', null=True, blank=True)
    sn = models.CharField('内存SN号', max_length=64, null=True, blank=True)
    speed = models.CharField('速度', max_length=16, null=True, blank=True)
    server_obj = models.ForeignKey('Server',related_name='memory')
    class Meta:
        verbose_name_plural = "内存表"
    def __str__(self):
        return self.slot






class AssetRecord(models.Model):
    """
    资产变动记录,creator为空时,表示是资产汇报的数据。
    """
    asset_obj = models.ForeignKey('Asset', related_name='ar')
    content = models.TextField(null=True)# 新增硬盘
    creator = models.ForeignKey('UserProfile', null=True, blank=True) #
    create_at = models.DateTimeField(auto_now_add=True)
    class Meta:
        verbose_name_plural = "资产记录表"
    def __str__(self):
        return "%s-%s-%s" % (self.asset_obj.idc.name, self.asset_obj.cabinet_num, self.asset_obj.cabinet_order)


class ErrorLog(models.Model):
    """
    错误日志,如:agent采集数据错误 或 运行错误
    """
    asset_obj = models.ForeignKey('Asset', null=True, blank=True)
    title = models.CharField(max_length=16)
    content = models.TextField()
    create_at = models.DateTimeField(auto_now_add=True)
    class Meta:
        verbose_name_plural = "错误日志表"
    def __str__(self):
        return self.title
models