配置管理系統


一、 前言

1.1 簡介

CMDB(Configuration Management Database)配置管理數據庫,是所有運維工具的數據基礎。70%~80%的IT相關問題與環境的變更有着直接的關系。實施變更管理的難點和重點並不是工具,而是流程。即通過一個自動化的、可重復的流程管理變更,使得當變更發生的時候,有一個標准化的流程去執行,能夠預測到這個變更對整個系統管理產生的影響,並對這些影響進行評估和控制。而變更管理流程自動化的實現關鍵就是CMDB

1.2 功能

應該知道包含這幾種功能:整合、調和、同步、映射和可視化

  • 用戶管理,記錄測試,開發,運維人員的用戶表
  • 業務線管理,需要記錄業務的詳情
  • 項目管理,指定此項目用屬於哪條業務線,以及項目詳情
  • 應用管理,指定此應用的開發人員,屬於哪個項目,和代碼地址,部署目錄,部署集群,依賴的應用,軟件等信息
  • 主機管理,包括雲主機,物理機,主機屬於哪個集群,運行着哪些軟件,主機管理員,連接哪些網絡設備,雲主機的資源池,存儲等相關信息
  • 主機變更管理,主機的一些信息變更,例如管理員,所屬集群等信息更改,連接的網絡變更等
  • 網絡設備管理,主要記錄網絡設備的詳細信息,及網絡設備連接的上級設備
  • IP管理,IP屬於哪個主機,哪個網段, 是否被占用等

二、 四種實現方式

2.1 Agent方式

  • 流程分析
    • 在每台服務器上部署一個agent腳本(python代碼實現的,用的是它的subprocess模塊,定時觸發執行subprocess.getoutput(cmd)方法) ,將agent執行的結果通過requests模塊返回給API程序,處理之后儲存到數據庫,然后通過前端界面展示出來

優缺點分析:

  優點: 速度快,使用於服務器多的大型公司

  缺點: 需要為每一台服務器都部署一個Agent程序,機器過多時耗費的人力成本大

2.2 ssh方式(基於paramiko模塊

  • 流程分析
    • agent方式不同的是,不用再每台服務器上部署agent腳本,而是通過ssh服務實現的。方法就是將python代碼放置於一台單獨的服務器上,即中控機。中控機通過paramiko模塊以ssh方式遠程鏈接登錄到每台服務器上執行linux命令來獲取所需要的信息並將數據返回到中控機並轉交給API,然后由API程序將數據處理之后儲存到數據庫,再通過前端界面展示

 

優缺點分析:

  優點: 不需要為每一台服務器都部署一個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方式

  • 流程分析
    • 與第二種類似,同樣需要一個中控機,同時它還依賴於第三方軟件saltstacksaltstack有兩個身份,即masterminion,我們可以在中控機上安裝salt-master來控制所有的salt-minion服務器,中控機salt-master通過(salt 'minion主機名' cmd.run '命令')向服務器minion發送命令,minion會將執行的結果放入隊列中,再由master從隊列中取出數據,轉交給API處理后儲存到數據庫中,通過前端界面展示

 

優缺點分析:

  優點: 速度快,開發成本低

  缺點: 需要依賴於第三方工具,需要部署中控機

  • 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
models.py

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM