对于数据采集和数据上报这种事情我再熟悉不过了,因为 CMDB 就是我们公司的产品之一,数据采集就是 CMDB 里面最基础的一环。

我们公司的产品都是使用 Python 脚本进行数据采集,因为开发速度快,调试方便,变更也很方便,但是需要一个执行环境,一般这种都是依靠一个安装在主机上面的 agent 提供的。而这次之所以采用 Go 来开发客户端就是考虑到用 Go 开发的客户端可以不需要依赖环境,只需要把代码兼容性做好,就可以直接运行在各种系统上。

1. 客户端开发

客户端要做的事情其实就是三件:数据采集、密钥解析、数据上报,所以从设计上我把这三个事情是分开成独立的事情来做,最终在生成的命令行工具里面也是提供了三个命令。

1.1 数据采集

数据采集主要依赖的是 Go 的第三方库 github.com/shirou/gopsutil 这个库是对标 Python 里面的 psutil 库的,主要用来获取一些系统相关的数据,比如内存、CPU、硬盘、系统,进程等等。

比如以下是一些采集的属性:

数据采集这里也是要注意一些坑的,有的命令在不同系统中可能不一样,比如获取磁盘的数据,在 IOS 系统里面跟 Linux 里面是不同的,苹果系统只需要统计 / 路径的容量就够了。

然后还可以使用 shell命令来提取信息,比如网络数据:

func getConnections() (int, int, error) {
    var tcp, udp int
    cmd := exec.Command("sh", "-c", "expr $(ss -t | wc -l) - 1")

    // 获取命令输出
    tcpString, err := cmd.Output()
    if err == nil {
        tcpNum, err := strconv.Atoi(strings.TrimSpace(string(tcpString)))
        if err == nil {
            tcp = tcpNum
            if tcp < 0 {
                tcp = 0
            }
        }
    }

    cmd = exec.Command("sh", "-c", "expr $(ss -u | wc -l) - 1")

    // 获取命令输出
    udpString, err := cmd.Output()
    if err == nil {
        udpNum, err := strconv.Atoi(strings.TrimSpace(string(udpString)))
        if err == nil {
            udp = udpNum
            if udp < 0 {
                udp = 0
            }
        }
    }

    return tcp, udp, nil
}

这种直接执行命令的方式可能更灵活,但是兼容性就不太行了,所以使用的时候需要充分考虑不同平台的不同命令。

1.2 密钥解析

客户端需要实现一个跟服务端一样的加解密工具,只要能使用给定的密钥对解析出原始的字符即可。

以下分别是Python和go的版本:

1.3 数据上报

数据上报就是按照服务端定义的的接口进行请求即可,接口定义如下:

  • 请求地址:/monitor/server/push,解析密钥后得到
  • 请求方法:POST
  • 请求头:
    • Content-Type:application/json
    • Push-Username:用户名,解析密钥后得到
    • Push-Password:密码,解析密钥后得到
    • Push-Key:密钥Key
    • Push-Value:密钥值
  • 请求体:JSON格式,需要提供数据采集的所有字段,并且格式满足规范,否则上报失败

1.4 编译成命令行工具

本地编译直接执行 go build 就行了,如果要发布版本,则需要创建一个 tag 利用 GitHub Actions 来打包成多个平台的软件包。

具体的打包过程可查看我的博文:Go 学习笔记(11):利用 GitHub Actions 进行多平台打包

2. 客户端使用

客户端版本下载地址:https://github.com/Hopetree/GoMonitor/releases

2.1 下载安装包

到客户端版本中选择最新的版本,下载跟当前系统匹配的安装包:

下载后解压软件包:

tar -zxvf GoMonitor_0.1.1_linux_x86_64.tar.gz

这也就可以得到一个 GoMonitor_0.1.1_linux_x86_64 目录,客户端 GoMonitor 就在这个目录里面。

2.2 本地调试

2.2.1 调试数据采集

首先可以执行仅采集数据的命令:

./GoMonitor collect

输出:

version cmd: echo ''
{"interval":6,"uptime":190047,"system":"darwin-23.1.0-arm64-darwin-14.1.2","cpu_cores":8,"cpu_model":"","cpu":44.98714652940142,"load_1":"5.45","load_5":"4.57","load_15":"3.85","memory_total":17179869184,"memory_used":13741309952,"swap_total":8589934592,"swap_used":7241531392,"hdd_total":494384795648,"hdd_used":213326909440,"network_in":"562.81K","network_out":"1.11M","process":566,"thread":4009,"tcp":0,"udp":0,"version":"","client_version":"0.1.1"}

第一条输出是默认的采集服务版本的命令,默认就是输出空字符串。第二条输出是一个 json 数据,也就是上报的数据结构,可以检查一下有没有什么数据采集失败或者数据不对的。

2.2.2 调试密钥解析

然后可以调试一下解析密钥,比如下面这对密钥是我本地调试的密钥:

./GoMonitor decrypt -k df2433290c3245a59a15c5b5715bd910 -s JdjfCErtHYhcSFLl6efQDgZo4pepf/cbwjSAKd9jCCtNijL7Q+f1fr3mlZe64qVN+1cYQo+fJRARn905UgEUOuVnttobTmnH2pQRuvophvI=  

输出:

macbook::2242400032::http://127.0.0.1:8090/monitor/server/push

这个信息包括3个部分:用户名、密码、上报地址,这三个信息就是客户端向服务器上报的时候请求的信息。

2.2.3 调试数据上报

如果数据采集和密钥解析都没有问题,那么此时可以调试一下数据上报,也就是给服务器上报一条数据,并得到返回信息。

./GoMonitor report -k df2433290c3245a59a15c5b5715bd910 -s JdjfCErtHYhcSFLl6efQDgZo4pepf/cbwjSAKd9jCCtNijL7Q+f1fr3mlZe64qVN+1cYQo+fJRARn905UgEUOuVnttobTmnH2pQRuvophvI= --debug

如果 report 命令中带有 --debug 参数则表示是调试模型,此时就会输出上报的数据和解析数据,然后输出服务器的接口返回,数据如下:

version cmd: echo ''
{"interval":6,"uptime":190673,"system":"darwin-23.1.0-arm64-darwin-14.1.2","cpu_cores":8,"cpu_model":"","cpu":21.910828025186774,"load_1":"3.22","load_5":"3.14","load_15":"3.37","memory_total":17179869184,"memory_used":13876232192,"swap_total":8589934592,"swap_used":7491878912,"hdd_total":494384795648,"hdd_used":213313060864,"network_in":"81.20K","network_out":"51.97K","process":570,"thread":3959,"tcp":0,"udp":0,"version":"","client_version":"0.1.1"}
macbook::2242400032::http://127.0.0.1:8090/monitor/server/push
{"code": 0, "error": "", "message": "", "data": {"interval": 6, "uptime": "2 \u5929", "system": "darwin-23.1.0-arm64-darwin-14.1.2", "cpu_cores": 8, "cpu_model": "", "cpu": 21.9, "load_1": "3.22", "load_5": "3.14", "load_15": "3.37", "memory_total": "16.0G", "memory_used": "12.92G", "swap_total": "8.0G", "swap_used": "6.98G", "hdd_total": "460.43G", "hdd_used": "198.66G", "network_in": "81.20K", "network_out": "51.97K", "process": 570, "thread": 3959, "tcp": 0, "udp": 0, "version": "", "client_version": "0.1.1", "memory": 80.8, "hdd": 43.1}}

这里有4条数据,第一条依然是采集服务版本的默认命令,第二条是上报的数据体,第三条是解析的服务器接口信息,第四条就是服务器返回的数据,如果 code 是0就表示上报成功,此时也可以在服务器上面看到新上报的数据。

更多命令和参数的含义可以查看工具帮助:

./GoMonitor --help

输出:

NAME:
   GoMonitor - 一个简单的agent客户端,用于采集主机信息并上报到服务端

USAGE:
   GoMonitor [global options] command [command options] 

VERSION:
   0.1.1

COMMANDS:
   collect  采集主机信息
   decrypt  解密密钥,并显示原文
   report   采集主机信息,并解析密钥,将信息上报到服务端,非调试模式不输出任何信息
   help, h  Shows a list of commands or help for one command

GLOBAL OPTIONS:
   --help, -h     show help
   --version, -v  print the version

2.2 Linux 设置成系统服务

如果本地调试数据采集和上报都没问题,则可以将客服端设置成系统服务来运行,这样可以保证客户端随系统自启动。

操作步骤:

step1:将命令移动到指定目录:

cp GoMonitor /usr/local/bin/
chmod 755 /usr/local/bin/GoMonitor

step2:创建服务配置文件

vi /etc/systemd/system/gomonitor.service

内容如下:

[Unit]
Description = go monitor agent
After = network.target syslog.target
Wants = network.target

[Service]
Type = simple
ExecStart = /usr/local/bin/GoMonitor report -i 5 -k df2433290c3245a59a15c5b5715bd910 -s JdjfCErtHYhcSFLl6efQDgZo4pepf/cbwjSAKd9jCCtNijL7Q+f1fr3mlZe64qVN+1cYQo+fJRARn905UgEUOuVnttobTmnH2pQRuvophvI=

[Install]
WantedBy = multi-user.target

step3:加载配置,启动服务并设置成开机自启动

systemctl daemon-reload
systemctl start gomonitor
systemctl enable gomonitor
systemctl status gomonitor

2.3 更新客户端

如果要更新客户端的版本,可以直接重新下载客户端的软件包,更新二进制文件,然后重新启动服务,比如我进行的操作:

systemctl stop gomonitor
mkdir /tmp/040201 && cd /tmp/040201
wget https://github.com/Hopetree/GoMonitor/releases/download/v0.1.1/GoMonitor_0.1.1_linux_x86_64.tar.gz --no-check-certificate
tar -zxvf GoMonitor_0.1.1_linux_x86_64.tar.gz
cd GoMonitor_0.1.1_linux_x86_64
\cp GoMonitor /usr/local/bin/
chmod 755 /usr/local/bin/GoMonitor

systemctl daemon-reload
systemctl restart gomonitor
systemctl status gomonitor

cd /tmp && rm -rf /tmp/040201

客户端兼容性

目前已经验证过的系统如下:

内核 系统 验证 备注
darwin macOS OK
linux CentOS OK
linux Debian OK
linux Ubuntu OK
linux Redhat OK
linux 群晖 OK 无法获取系统版本信息
linux PVE OK
windows Windows 11 OK

结论就是三大系统都是兼容的,只是个别采集指标(主要是TCP和UDP数据)无法兼容到。

版权声明:如无特殊说明,文章均为本站原创,转载请注明出处

本文链接:https://tendcode.com/subject/article/server-status-2/

许可协议:署名-非商业性使用 4.0 国际许可协议