一:IT運維的分類
IT運維,指的是對已經搭建好的網絡、軟件、硬件進行維護。運維領域也是細分的,有硬件運維和軟件運維。
硬件運維主要包括對基礎設施的運維,例如機房的設備,主機的鍵盤,內存等物理設備的維護。
軟件運維主要包括系統運維和應用運維,系統運維主要包括對OS,數據庫,中間件的監控和維護,這些系統介於設備和應用之間,應用運維主要是對線上業務系統的運維。
這里主要討論的是軟件運維的自動化,包括系統運維和應用運維的自動化。
二:傳統運維的缺點
1:日常工作繁瑣
日常運維工作繁瑣,研發會經常需要到服務器上查看日志,重啟應用,或者是上線某個產品需要部署環境等,都是運維的日常。
2:應用運行環境不統一
在部署某個應用后,應用不能訪問,在開發環境運行的好,但是在測試環境后就不能繼續用了,因為各類環境的類庫不統一。還有一種情況是,由於運維人員的習慣不同,按照自己的習慣來安裝部署環境,每種服務器上運行的軟件目錄不統一。
3:運維及部署效率低下
運維人員需要登錄到服務器上執行命令,部署程序,不僅效率低,並且非常容易出現人為錯誤,人為出錯之后也不容易找到問題所在。
4:無用報警信息過多
運維人員經常會收到很多的無用報警信息,常常會選擇屏蔽這些報警信息,並且一旦應用的訪問速度出了問題,就需要從系統、網絡、應用、數據庫等一步步查找信息。
5:資產管理和應用系統混亂
資產管理,服務管理經常記錄在Excel或者文本里面,不便於管理。老員工由於熟悉不注重文檔的維護,新員工入職時,資產才能更正一次。
三:為什么需要自動化運維?
1:項目上線
流程:產品經理調研(畫出原型圖)-->定需求-->三方會談(研發,產品經理,老大們)-->定日期-->測試項目-->最終上線-->應用運維
目前:將代碼打包給運維,運維解壓上線
問題:隨着機器數量的線性增加,運維的工作量也是線性增加,重復而且是毫無意義的勞動
解決:
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 """
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'])
參考安裝:
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)
字符串格式化字符
String.prototype.format = function(args){ return this.replace(/\{(\w+)\}/g, function(s, i){ return args[i]; }); };
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
