内容简介:版权申明:本人仅授权实验楼发布、转载、下载及传播。本实验将讲解自动化运维的概念和基础知识,常用开源软件的使用场景,一个自动化运维系统需要具备哪些功能;通过Pexpect库实现自动监控服务器的负载、磁盘、内存、CPU、网络接口(流量)、端口等。本课程难度为初级,适合想了解自动化运维或具有Python基础的用户,使用Python开发自动化运维系统应该从何入手。
版权申明:本人仅授权实验楼发布、转载、下载及传播。
一、实验介绍
1.1 实验内容
本实验将讲解自动化运维的概念和基础知识,常用开源软件的使用场景,一个自动化运维系统需要具备哪些功能;通过Pexpect库实现自动监控服务器的负载、磁盘、内存、CPU、网络接口(流量)、端口等。
1.2 实验知识点
自动化监控
1.3 实验环境
- Python2.7
- Xfce终端
- Pexpect模块
1.4 适合人群
本课程难度为初级,适合想了解自动化运维或具有 Python 基础的用户,使用Python开发自动化运维系统应该从何入手。
1.5 代码获取
你可以通过下面命令将代码下载到实验楼环境中,作为参照对比进行学习。
$ wget https://shiyanlou1.oss-cn-shanghai.aliyuncs.com/code/monitor.py
二、实验原理
Pexpect库的核心组件
-
spawn类
spawn是pexpect的主要类接口,功能是启动和控制子应用程序,以下是它的构造函数定义:class pexpect.spawn(command, args=[], timeout=30, maxread=2000, searchwindowsize=None, logfile=None, cwd=None, env=None, ignore_sighup=False, echo=True, preexec_fn=None, encoding=None, codec_errors='strict', dimensions=None)
-
sendline
发送需要执行的命令,如输入password -
expect
期望得到的输出结果,可以通过列表传递多个值,如["$", "#"]
-
pexpect.EOF
、pexpect.TIMEOUT
换行符,连接超时报错
三、开发准备
打开Xfce终端,进入 /home/shiyanlou
目录,创建 monitor.py
文件
$ touch monitor.py
安装 pexpect
模块
$ sudo pip install pexpect==4.6.0
四、实验步骤
4.1 什么是自动化运维
自动化运维是指将IT运维中日常的、大量的重复性工作自动化,把过去的手工执行转为自动化操作。 自动化是IT运维工作的升华,自动化运维不单纯是一个维护过程,更是一个管理的提升过程,是IT运维的最高层次,也是未来的发展趋势。
4.2 开源自动化运维工具
-
Jekins
一个具有许多插件的自动化服务器。用于构建,测试和自动化部署应用程序。通常Jenkins用作软件开发的CI/CD工具。Jenkins 的作业(构建)可以由各种触发器启动。例如提交代码到版本控制系统,按计划事件,通过访问特定URL构建或者在完成其它构建之后进行触发。 -
Ansible
集合了众多运维工具(puppet、chef、func、fabric)的优点,实现了批量系统配置、批量程序部署、批量运行命令等功能。 -
SaltStack
基于Python开发的一套C/S架构配置管理工具,简单易部署,同时支持服务器/客户端 和无代理模式。在后一种情况下,Salt 使用SSH连接到受管理的节点/虚拟机。Salt 使用以Python编写的执行模块,其中包含函数以定义配置任务。 -
Nagios
网络监控工具,能有效监控Windows、 Linux 和Unix的主机状态,交换机、路由器等网络设备,并发送告警信息。 -
Zabbix
是一个为应用服务,网络服务和硬件监控提供的解决方案。Zabbix 将收集的数据存储在关系数据库中,如MySQL,PostgreSQL等。Zabbix 允许你监控简单的服务,如HTTP服务。Zabbix agent端可以安装在Windows和 类Unix服务器上,用来检视系统参数,如CPU负载、内存和磁盘利用率等。另外,agent可用于监视标准服务和自定义应用程序。Zabbix也支持通过SNMP、SSH等方式,无需在要监视的服务器上安装代理。 -
Kubernets
简称k8s,是来自 Google 云平台的开源容器集群管理系统,功能包括自动化容器的部署,调度和节点集群间扩展,支持 Docker 和Rocket。 -
OpenShift
由RedHat推出的一款面向开源开发人员开放的平台即服务(PaaS)。 OpenShift通过为开发人员提供在语言、框架和云上的更多的选择,使开发人员可以构建、测试、运行和管理他们的应用。 -
ELK
Elasticsearch,Logstash,Kibana软件的组合,它是用于记录,日志分析,日志搜索和可视化的完整工具。Elasticsearch是基于Apache Lucene的搜索工具。Logstash是用于收集,解析和存储日志的工具,可以通过Elasticsearch对其进行索引。
4.3 自动化运维系统的功能
具体应包括哪些功能没有统一的标准,视每个公司业务和开发需求而定。大体上,一个成熟的自动化运维系统功能应包含如下五大功能模块:
(CMDB)配置管理 集中监控报警 (ITSM)流程管理 日志分析与处理 持续集成与发布
推荐几个Github上不错的自动化运维平台:
- OpsManage 代码及应用部署CI/CD、资产管理CMDB、计划任务管理平台、 SQL 审核|回滚、任务调度、站内WIKI
- adminset CMDB、CD、DevOps、资产管理、任务编排、持续交付、系统监控、运维管理、配置管理
- jumpserver 全球首款完全开源的堡垒机,是符合 4A 的专业运维审计系统, 官网地址
4.4 Pexpect实现自动化监控服务器
Pexpect 是一个用来启动子程序并对其进行自动控制的纯 Python 模块。 Pexpect 可以用来和像 ssh、ftp、passwd、telnet 等命令行程序进行自动交互。通过Pexpect实现连接到服务器,并执行指定命令,如 cat /proc/cpuinfo
,通过正则表达式过滤或字符串切片得到需要的CPU型号、核数、主频等信息,其它监控项类似。
4.4.1 SSH登录执行命令
函数通过执行 ssh -l user host command
,使用 user
用户登录到 host
,获取 command
命令的返回结果
def ssh_command(host, user, password, command): """ SSH登录执行命令 :param host: <str> 主机IP :param user: <str> 用户名 :param password: <str> 登录密码 :param command: <str> bash命令 :return: pexpect的spawn对象 """ ssh = pexpect.spawn('ssh -l {} {} {}'.format(user, host, command)) # 登录口令 i = ssh.expect(['password:', 'continue connecting (yes/no)?'], timeout=30) if i == 0: ssh.sendline(password) if i == 1: ssh.sendline('yes') ssh.expect('[p,P]assword: ') # Password/password ssh.sendline(password) index = ssh.expect(["$", "#", pexpect.EOF, pexpect.TIMEOUT]) # 此处注意,root用户登录符号为#,普通用户为$ if index != 0: print("登录失败!报错内容:{};{}".format(ssh.before, ssh.after)) return False return ssh
4.4.2 内存监控
执行 cat /proc/meminfo
,使用 r"(\d+) kB"
正则匹配内存信息
def memory(): """内存监控""" ssh = ssh_command("192.168.1.1", "username", "password", "cat /proc/meminfo") ssh.expect(pexpect.EOF) # 命令执行完毕 ssh.close() # 关闭连接进程 data = re.findall(b"(\d+) kB", ssh.before) MemTotal = int(data[0]) / 1024 # 除以1024得到MB MemFree = int(data[1]) / 1024 Buffers = int(data[2]) / 1024 Cached = int(data[3]) / 1024 SwapCached = int(data[4]) / 1024 SwapTotal = int(data[13]) / 1024 SwapFree = int(data[14]) / 1024 print("*******************内存监控 {}******************".format(datetime.today().strftime("%Y-%m-%d %H:%M:%S"))) print("总内存: {} MB".format(MemTotal)) print("空闲内存: {} MB".format(MemFree)) print("给文件的缓冲大小: {} MB".format(Buffers)) print("高速缓冲存储器使用的大小: {} MB".format(Cached)) print("被高速缓冲存储用的交换空间大小: {} MB".format(SwapCached)) print("给文件的缓冲大小: {} MB".format(Buffers)) if int(SwapTotal) == 0: print("交换内存总共为:0") else: print("交换内存利用率: {0:.4}%".format((SwapTotal - SwapFree) / float(SwapTotal) * 100)) print("内存利用率: {0:.4}%".format((MemTotal - MemFree) / float(MemTotal) * 100))
效果图如下
4.4.3 负载监控
执行 cat /proc/loadavg
,使用字符串切片获取结果
def load(): """监控负载""" ssh = ssh_command("192.168.1.1", "username", "password", "cat /proc/loadavg") ssh.expect(pexpect.EOF) ssh.close() loadavg = ssh.before.strip().split() print("*******************负载均衡监控 {}******************".format(datetime.today().strftime("%Y-%m-%d %H:%M:%S"))) print("系统5分钟前的平均负载: {}".format(loadavg[0])) print("系统10分钟前的平均负载: {}".format(loadavg[1])) print("系统15分钟前的平均负载: {}".format(loadavg[2])) print("分子是正在运行的进程数,分母为总进程数: {}".format(loadavg[3])) print("最近运行的进程ID: {}".format(loadavg[4]))
效果图如下
4.4.4 磁盘空间监控
执行 df -h
,使用字符串切片获取结果
def disk(): """磁盘空间监控""" ssh = ssh_command("192.168.1.1", "username", "password", "df -h") ssh.expect(pexpect.EOF) ssh.close() data = ssh.before.strip().split('\n') disklists = [] for disk in data: disklists.append(disk.strip().split()) print("*******************磁盘空间 {}******************".format(datetime.today().strftime("%Y-%m-%d %H:%M:%S"))) for i in disklists[1:]: print("\t文件系统: {}".format(i[0])) print("\t容量: {}".format(i[1])) print("\t已用: {}".format(i[2])) print("\t可用: {}".format(i[3])) print("\t已用%挂载点: {}".format(i[4]))
效果图如下
4.4.5 网卡流量监控
执行 cat /proc/net/dev
,使用字符串切片获取结果
def ionetwork(): """获取网络接口的输入和输出""" ssh = ssh_command("192.168.1.1", "username", "password", "cat /proc/net/dev") ssh.expect(pexpect.EOF) ssh.close() li = ssh.before.strip().split('\n') print("*******************网络接口的输入和输出监控 {}******************".format(datetime.today().strftime("%Y-%m-%d %H:%M:%S"))) net = {} for line in li[2:]: net_io = {} line = line.split(":") eth_name = line[0].strip() net_io['Receive'] = round(float(line[1].split()[0]) / (1024.0 * 1024.0), 2) # bytes / 1024 / 1024 得到MB net_io['Transmit'] = round(float(line[1].split()[8]) / (1024.0 * 1024.0), 2) net[eth_name] = net_io for k, v in net.items(): print("接口{}: 接收 {}MB 传输 {}MB".format(k, v.get("Receive"), v.get("Transmit")))
效果图如下
4.4.6 活动端口监控
执行 cat /proc/net/dev
,直接输出结果
def com(): """端口监控""" ssh = ssh_command("192.168.91.58", "support", "splinux", "netstat -tpln") ssh.expect(pexpect.EOF) ssh.close() print("*******************端口监控 {}******************".format(datetime.today().strftime("%Y-%m-%d %H:%M:%S"))) print(ssh.before)
效果图如下
4.4.7 获取CPU信息
执行 cat /proc/cpuinfo
,使用 r'processor.*?(\d+)'
正则匹配CPU信息
def cpu_info(): """CPU信息获取""" ssh = ssh_command("192.168.1.1", "username", "password", "cat /proc/cpuinfo") ssh.expect(pexpect.EOF) ssh.close() cpu_num = re.findall('processor.*?(\d+)', ssh.before)[-1] print("*******************CPU信息 {}******************".format(datetime.today().strftime("%Y-%m-%d %H:%M:%S"))) print("CPU数目: {}".format(str(int(cpu_num) + 1))) li = ssh.before.replace('\t', '').split('\r') CPUinfo, procinfo, nprocs = {}, {}, 0 for line in li: if line.find("processor") > -1: CPUinfo['CPU%s' % nprocs] = procinfo nprocs = nprocs + 1 else: if len(line.split(':')) == 2: procinfo[line.split(':')[0].strip()] = line.split(':')[1].strip() else: procinfo[line.split(':')[0].strip()] = '' for processor in CPUinfo.keys(): print("CPU属于的名字及其编号、标称主频: {}".format(CPUinfo[processor]['model name'])) print("CPU属于其系列中的哪一代的代号: {}".format(CPUinfo[processor]['model'])) print("CPU制造商: {}".format(CPUinfo[processor]['vendor_id'])) print("CPU产品系列代号: {}".format(CPUinfo[processor]['cpu family'])) print("CPU的实际使用主频: {0:.2} GHz".format(float(CPUinfo[processor]['cpu MHz']) / 1024))
效果图如下
4.4.8 获取vmstat信息
执行 vmstat 1 2 | tail -n 1
,直接输出结果
def vmstat(): """内核线程、虚拟内存、磁盘和CPU活动的统计信息""" ssh = ssh_command("192.168.1.1", "username", "password", "vmstat 1 2 | tail -n 1") ssh.expect(pexpect.EOF) ssh.close() vmstat_info = ssh.before.strip().split() processes_waiting = vmstat_info[0] processes_sleep = vmstat_info[1] swpd = int(vmstat_info[2]) / 1024 free = int(vmstat_info[3]) / 1024 buff = int(vmstat_info[4]) / 1024 cache = int(vmstat_info[5]) / 1024 si = int(vmstat_info[6]) / 1024 so = int(vmstat_info[7]) / 1024 io_bi = vmstat_info[8] io_bo = vmstat_info[9] system_interrupt = vmstat_info[10] system_context_switch = vmstat_info[11] cpu_user = vmstat_info[12] cpu_sys = vmstat_info[13] cpu_idle = vmstat_info[14] cpu_wait = vmstat_info[15] st = vmstat_info[16] print("*******************vmstat信息统计 {}******************".format(datetime.today().strftime("%Y-%m-%d %H:%M:%S"))) print("等待运行进程的数量: {}".format(processes_waiting)) print("处于不间断状态的进程: {}".format(processes_sleep)) print("使用虚拟内存(swap)的总量: {} MB".format(swpd)) print("空闲的内存总量: {} MB".format(free)) print("用作缓冲的内存总量: {} MB".format(buff)) print("用作缓存的内存总量: {} MB".format(cache)) print("交换出内存总量 : {} MB".format(si)) print("交换入内存总量 : {} MB".format(so)) print("从一个块设备接收: {}".format(io_bi)) print("发送到块设备: {}".format(io_bo)) print("每秒的中断数: {}".format(system_interrupt)) print("每秒的上下文切换数: {}".format(system_context_switch)) print("用户空间上进程运行的时间百分比: {}".format(cpu_user)) print("内核空间上进程运行的时间百分比: {}".format(cpu_sys)) print("闲置时间百分比: {}".format(cpu_idle)) print("等待IO的时间百分比: {}".format(cpu_wait)) print("从虚拟机偷取的时间百分比: {}".format(st))
效果图如下
将上述功能函数使用使用面向对象的方式实现,通过 While True
循环每分钟执行一轮,完整代码如下:
#!/usr/bin/python3 # -*- coding:utf-8 -*- # __author__ = 'liao gao xiang' import re import time from datetime import datetime import pexpect class Monitor(object): """服务器自动化监控""" def __init__(self): self.host = "192.168.1.1" self.user = "username" self.password = "password" def ssh_command(self, command): """SSH登录执行命令""" ssh = pexpect.spawn('ssh -l {} {} {}'.format(self.user, self.host, command)) # 登录口令 i = ssh.expect(['password:', 'continue connecting (yes/no)?'], timeout=30) if i == 0: ssh.sendline(self.password) if i == 1: ssh.sendline('yes') ssh.expect('[p,P]assword: ') ssh.sendline(self.password) index = ssh.expect(["$", "#", pexpect.EOF, pexpect.TIMEOUT]) # 此处注意,root用户登录符号为#,普通用户为$ if index != 0: print("登录失败!报错内容:{};{}".format(ssh.before, ssh.after)) return False return ssh def memory(self): """内存监控""" ssh = self.ssh_command("cat /proc/meminfo") ssh.expect(pexpect.EOF) data = re.findall(b"(\d+) kB", ssh.before) MemTotal = int(data[0]) / 1024 # 除以1024得到MB MemFree = int(data[1]) / 1024 Buffers = int(data[2]) / 1024 Cached = int(data[3]) / 1024 SwapCached = int(data[4]) / 1024 SwapTotal = int(data[13]) / 1024 SwapFree = int(data[14]) / 1024 print("*******************内存监控 {}******************".format(datetime.today().strftime("%Y-%m-%d %H:%M:%S"))) print("总内存: {} MB".format(MemTotal)) print("空闲内存: {} MB".format(MemFree)) print("给文件的缓冲大小: {} MB".format(Buffers)) print("高速缓冲存储器使用的大小: {} MB".format(Cached)) print("被高速缓冲存储用的交换空间大小: {} MB".format(SwapCached)) print("给文件的缓冲大小: {} MB".format(Buffers)) if int(SwapTotal) == 0: print("交换内存总共为:0") else: print("交换内存利用率: {0:.4}%".format((SwapTotal - SwapFree) / float(SwapTotal) * 100)) print("内存利用率: {0:.4}%".format((MemTotal - MemFree) / float(MemTotal) * 100)) def vmstat(self): """内核线程、虚拟内存、磁盘和CPU活动的统计信息""" ssh = self.ssh_command("vmstat 1 2 | tail -n 1") ssh.expect(pexpect.EOF) vmstat_info = ssh.before.strip().split() processes_waiting = vmstat_info[0] processes_sleep = vmstat_info[1] swpd = int(vmstat_info[2]) / 1024 free = int(vmstat_info[3]) / 1024 buff = int(vmstat_info[4]) / 1024 cache = int(vmstat_info[5]) / 1024 si = int(vmstat_info[6]) / 1024 so = int(vmstat_info[7]) / 1024 io_bi = vmstat_info[8] io_bo = vmstat_info[9] system_interrupt = vmstat_info[10] system_context_switch = vmstat_info[11] cpu_user = vmstat_info[12] cpu_sys = vmstat_info[13] cpu_idle = vmstat_info[14] cpu_wait = vmstat_info[15] st = vmstat_info[16] print("*******************vmstat信息统计 {}******************".format(datetime.today().strftime("%Y-%m-%d %H:%M:%S"))) print("等待运行进程的数量: {}".format(processes_waiting)) print("处于不间断状态的进程: {}".format(processes_sleep)) print("使用虚拟内存(swap)的总量: {} MB".format(swpd)) print("空闲的内存总量: {} MB".format(free)) print("用作缓冲的内存总量: {} MB".format(buff)) print("用作缓存的内存总量: {} MB".format(cache)) print("交换出内存总量 : {} MB".format(si)) print("交换入内存总量 : {} MB".format(so)) print("从一个块设备接收: {}".format(io_bi)) print("发送到块设备: {}".format(io_bo)) print("每秒的中断数: {}".format(system_interrupt)) print("每秒的上下文切换数: {}".format(system_context_switch)) print("用户空间上进程运行的时间百分比: {}".format(cpu_user)) print("内核空间上进程运行的时间百分比: {}".format(cpu_sys)) print("闲置时间百分比: {}".format(cpu_idle)) print("等待IO的时间百分比: {}".format(cpu_wait)) print("从虚拟机偷取的时间百分比: {}".format(st)) def cpu_info(self): """CPU信息获取""" ssh = self.ssh_command("cat /proc/cpuinfo") ssh.expect(pexpect.EOF) cpu_num = re.findall(r'processor.*?(\d+)', ssh.before)[-1] print("*******************CPU信息 {}******************".format(datetime.today().strftime("%Y-%m-%d %H:%M:%S"))) print("CPU数目: {}".format(str(int(cpu_num) + 1))) li = ssh.before.replace('\t', '').split('\r') CPUinfo, procinfo, nprocs = {}, {}, 0 for line in li: if line.find("processor") > -1: CPUinfo['CPU%s' % nprocs] = procinfo nprocs = nprocs + 1 else: if len(line.split(':')) == 2: procinfo[line.split(':')[0].strip()] = line.split(':')[1].strip() else: procinfo[line.split(':')[0].strip()] = '' for processor in CPUinfo.keys(): print("CPU属于的名字及其编号、标称主频: {}".format(CPUinfo[processor]['model name'])) print("CPU属于其系列中的哪一代的代号: {}".format(CPUinfo[processor]['model'])) print("CPU制造商: {}".format(CPUinfo[processor]['vendor_id'])) print("CPU产品系列代号: {}".format(CPUinfo[processor]['cpu family'])) print("CPU的实际使用主频: {0:.2} GHz".format(float(CPUinfo[processor]['cpu MHz']) / 1024)) def load(self): """监控负载""" ssh = self.ssh_command("cat /proc/loadavg") ssh.expect(pexpect.EOF) loadavg = ssh.before.strip().split() print("*******************负载均衡监控 {}******************".format(datetime.today().strftime("%Y-%m-%d %H:%M:%S"))) print("系统5分钟前的平均负载: {}".format(loadavg[0])) print("系统10分钟前的平均负载: {}".format(loadavg[1])) print("系统15分钟前的平均负载: {}".format(loadavg[2])) print("分子是正在运行的进程数,分母为总进程数: {}".format(loadavg[3])) print("最近运行的进程ID: {}".format(loadavg[4])) def ionetwork(self): """获取网络接口的输入和输出""" ssh = self.ssh_command("cat /proc/net/dev") ssh.expect(pexpect.EOF) li = ssh.before.strip().split('\n') print("*******************网络接口的输入和输出监控 {}******************".format(datetime.today().strftime("%Y-%m-%d %H:%M:%S"))) net = {} for line in li[2:]: net_io = {} line = line.split(":") eth_name = line[0].strip() net_io['Receive'] = round(float(line[1].split()[0]) / (1024.0 * 1024.0), 2) # bytes / 1024 / 1024 得到MB net_io['Transmit'] = round(float(line[1].split()[8]) / (1024.0 * 1024.0), 2) net[eth_name] = net_io for k, v in net.items(): print("接口{}: 接收 {}MB 传输 {}MB".format(k, v.get("Receive"), v.get("Transmit"))) def disk(self): """磁盘空间监控""" ssh = self.ssh_command("df -h") ssh.expect(pexpect.EOF) data = ssh.before.strip().split('\n') disklists = [] for disk in data: disklists.append(disk.strip().split()) print("*******************磁盘空间 {}******************".format(datetime.today().strftime("%Y-%m-%d %H:%M:%S"))) for i in disklists[1:]: print("\t文件系统: {}".format(i[0])) print("\t容量: {}".format(i[1])) print("\t已用: {}".format(i[2])) print("\t可用: {}".format(i[3])) print("\t已用%挂载点: {}".format(i[4])) def com(self): """端口监控""" ssh = self.ssh_command("netstat -tpln") ssh.expect(pexpect.EOF) print("*******************端口监控 {}******************".format(datetime.today().strftime("%Y-%m-%d %H:%M:%S"))) print(ssh.before) if __name__ == '__main__': m = Monitor() while True: m.memory() m.vmstat() m.cpu_info() m.load() m.ionetwork() m.disk() m.com() time.sleep(60)
五、实验总结
本实验讲解了自动化运维的基本概念,常用的开源 工具 及使用场景,阐述了一个成熟的自动化运维系统应该具有哪些功能,通过自动化服务器监控脚本定时获取服务器信息,模拟自动化运维的实现过程。开发自动化运维平台是一个持续的过程,我们可以借助开源软件简化工作,结合公司具体业务实现目标。
六、课后习题
监控服务器当前的在线用户数,每分钟返回一次结果
七、参考链接
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 某小公司自动化智能监控平台的实践
- 用深度学习DIY自动化监控系统
- 从列表搜索到自动化测试监控的碎碎念
- 使用 Monit 替代 Supervisor 自动化管理和监控服务小结
- Kong 发布 Kong Brain 和 Kong Immunity,可进行智能自动化和适应性监控
- Java自动化——使用Selenium+POI实现Excel自动化批量查单词
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Head First Python
Paul Barry / O'Reilly Media / 2010-11-30 / USD 49.99
Are you keen to add Python to your programming skills? Learn quickly and have some fun at the same time with Head First Python. This book takes you beyond typical how-to manuals with engaging images, ......一起来看看 《Head First Python》 这本书的介绍吧!