55

[DevOps]自动化运维基础与自动化监控

 5 years ago
source link: https://segmentfault.com/a/1190000016124547?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

版权申明:本人仅授权实验楼发布、转载、下载及传播。

一、实验介绍

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.EOFpexpect.TIMEOUT 换行符,连接超时报错

三、开发准备

打开Xfce终端,进入 /home/shiyanlou 目录,创建 monitor.py 文件

$ touch monitor.py

安装 pexpect 模块

$ sudo pip install pexpect==4.6.0

四、实验步骤

4.1 什么是自动化运维

自动化运维是指将IT运维中日常的、大量的重复性工作自动化,把过去的手工执行转为自动化操作。 自动化是IT运维工作的升华,自动化运维不单纯是一个维护过程,更是一个管理的提升过程,是IT运维的最高层次,也是未来的发展趋势。

4.2 开源自动化运维工具

  1. Jekins 一个具有许多插件的自动化服务器。用于构建,测试和自动化部署应用程序。通常Jenkins用作软件开发的CI/CD工具。Jenkins 的作业(构建)可以由各种触发器启动。例如提交代码到版本控制系统,按计划事件,通过访问特定URL构建或者在完成其它构建之后进行触发。
  2. Ansible 集合了众多运维工具(puppet、chef、func、fabric)的优点,实现了批量系统配置、批量程序部署、批量运行命令等功能。
  3. SaltStack 基于Python开发的一套C/S架构配置管理工具,简单易部署,同时支持服务器/客户端 和无代理模式。在后一种情况下,Salt 使用SSH连接到受管理的节点/虚拟机。Salt 使用以Python编写的执行模块,其中包含函数以定义配置任务。
  4. Nagios 网络监控工具,能有效监控Windows、Linux和Unix的主机状态,交换机、路由器等网络设备,并发送告警信息。
  5. Zabbix 是一个为应用服务,网络服务和硬件监控提供的解决方案。Zabbix 将收集的数据存储在关系数据库中,如MySQL,PostgreSQL等。Zabbix 允许你监控简单的服务,如HTTP服务。Zabbix agent端可以安装在Windows和 类Unix服务器上,用来检视系统参数,如CPU负载、内存和磁盘利用率等。另外,agent可用于监视标准服务和自定义应用程序。Zabbix也支持通过SNMP、SSH等方式,无需在要监视的服务器上安装代理。
  6. Kubernets 简称k8s,是来自 Google 云平台的开源容器集群管理系统,功能包括自动化容器的部署,调度和节点集群间扩展,支持Docker和Rocket。
  7. OpenShift 由RedHat推出的一款面向开源开发人员开放的平台即服务(PaaS)。 OpenShift通过为开发人员提供在语言、框架和云上的更多的选择,使开发人员可以构建、测试、运行和管理他们的应用。
  8. ELK Elasticsearch,Logstash,Kibana软件的组合,它是用于记录,日志分析,日志搜索和可视化的完整工具。Elasticsearch是基于Apache Lucene的搜索工具。Logstash是用于收集,解析和存储日志的工具,可以通过Elasticsearch对其进行索引。

4.3 自动化运维系统的功能

具体应包括哪些功能没有统一的标准,视每个公司业务和开发需求而定。大体上,一个成熟的自动化运维系统功能应包含如下五大功能模块:

FBfEnav.png!web

(CMDB)配置管理
集中监控报警
(ITSM)流程管理
日志分析与处理
持续集成与发布

推荐几个Github上不错的自动化运维平台:

  1. OpsManage 代码及应用部署CI/CD、资产管理CMDB、计划任务管理平台、SQL审核|回滚、任务调度、站内WIKI
  2. adminset CMDB、CD、DevOps、资产管理、任务编排、持续交付、系统监控、运维管理、配置管理
  3. 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))

效果图如下

jANrUj3.png!web

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

效果图如下

iEBFBfM.png!web

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

效果图如下

bMBnm2B.png!web

mUj6Vny.png!web

yQNJNny.png!web

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")))

效果图如下

BnUbeiq.png!web

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)

效果图如下

ERNNBbB.png!web

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

效果图如下

MNZ36nF.png!web

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

效果图如下

YNR3maz.png!web

将上述功能函数使用使用面向对象的方式实现,通过 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)

五、实验总结

本实验讲解了自动化运维的基本概念,常用的开源工具及使用场景,阐述了一个成熟的自动化运维系统应该具有哪些功能,通过自动化服务器监控脚本定时获取服务器信息,模拟自动化运维的实现过程。开发自动化运维平台是一个持续的过程,我们可以借助开源软件简化工作,结合公司具体业务实现目标。

六、课后习题

监控服务器当前的在线用户数,每分钟返回一次结果

七、参考链接


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK