使用 Docker 部署 ServerStatus 服务器监控系统

news2024/11/18 2:35:22

一、ServerStatus 介绍

GitHub:https://github.com/cppla/ServerStatus

ServerStatus 是一个酷炫高逼格的云探针、云监控、服务器云监控、多服务器探针~。

特性

  • 使用 Rust 完全重写 Server、Client,单个执行文件部署
  • 支持上下线和简单自定义规则告警 (Telegram、 Wechat、 Email、 Webhook)
  • 支持 http 协议上报,可以方便部署到各免费容器服务和配合 cf 等优化上报链路
  • 支持 vnstat 统计月流量,重启不丢流量数据
  • 支持 Railway 快速部署
  • 支持 Systemd 开机自启

image.png

二、检查宿主机系统版本

cat /etc/os-release

三、检查本地 Docker 环境

检查 Docker 服务状态

// 1) 低版本 Docker 安装
yum install docker -y

----
// < '推荐' >
// 2) 高版本 Docker 安装
curl -fsSL https://get.docker.com/ | sh

----
// 关闭防火墙
systemctl disable --now firewalld
setenforce 0

// 启用 Docker
systemctl enable --now docker

检查 Docker 配置信息

docker info

开启 IPv4 forwarding

echo "net.ipv4.ip_forward=1" >>  /etc/sysctl.conf
systemctl restart network
sysctl net.ipv4.ip_forward

四、安装 Docker-compose

下载 Docker-compose 二进制包

curl -L https://github.com/docker/compose/releases/download/v2.2.2/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose

给文件增加执行权限

chmod +x /usr/local/bin/docker-compose

检查 Docker-compose 版本

docker-compose -v

五、下载 ServerStatus 镜像

docker pull stilleshan/serverstatus

六、使用 Docker-cli 部署

mkdir /docker/ServerStatus/server -p && cd /docker/ServerStatus/server
( 省略 )
docker run -d --name=serverstatus --restart=always \
  -p 8888:80 \
  -p 35601:35601 \
  -v /docker/ServerStatus/server/config.json:/ServerStatus/server/config.json \
  stilleshan/serverstatus

七、下载 ServerStatus 安装文件

创建数据目录

mkdir /docker/ServerStatus/server -p && cd /docker/ServerStatus/server

下载安装文件

yum install git -y
git clone https://github.com/stilleshan/ServerStatus.git
[root@localhost ServerStatus]# ls
config.json  docker-compose.yml  Dockerfile  README.md  screenshot.jpg  status.sh  web

查看 Docker-compose.yaml 文件

[root@localhost ServerStatus]# vim docker-compose.yml
version: "3"
services:
  serverstatus:
    image: stilleshan/serverstatus
    container_name: serverstatus
    ports:
      - 8888:80
      - 35601:35601
    volumes:
      # - ./web:/usr/share/nginx/html
      - ./config.json:/ServerStatus/server/config.json
    environment:
      TZ: Asia/Shanghai
    restart: always

创建 ServerStatus 容器

docker-compose up -d

查看 ServerStatus 容器状态

docker ps

image.png

八、访问 ServerStatus 服务端

image.png

九、客户端安装

修改 status-client.py

[root@node01 ~] vim status-client.py 
# -*- coding: utf-8 -*-

SERVER = "192.168.80.8"	# 填写服务器地址
PORT = 35601
USER = "admin" 			# 设置账号 ( 待会需要在服务端填写 )
PASSWORD = "admin"		# 设置密码 ( 待会需要在服务端填写 )
INTERVAL = 1 			# 更新间隔, 单位: 秒


import socket
import time
import string
import math
import re
import os
import json
import subprocess
import collections
import platform

def get_uptime():
    f = open('/proc/uptime', 'r')
    uptime = f.readline()
    f.close()
    uptime = uptime.split('.', 2)
    time = int(uptime[0])
    return int(time)

def get_memory():
    re_parser = re.compile(r'^(?P<key>\S*):\s*(?P<value>\d*)\s*kB')
    result = dict()
    for line in open('/proc/meminfo'):
        match = re_parser.match(line)
        if not match:
            continue;
        key, value = match.groups(['key', 'value'])
        result[key] = int(value)

    MemTotal = float(result['MemTotal'])
    MemFree = float(result['MemFree'])
    Cached = float(result['Cached'])
    MemUsed = MemTotal - (Cached + MemFree)
    SwapTotal = float(result['SwapTotal'])
    SwapFree = float(result['SwapFree'])
    return int(MemTotal), int(MemUsed), int(SwapTotal), int(SwapFree)

def get_hdd():
    p = subprocess.check_output(['df', '-Tlm', '--total', '-t', 'ext4', '-t', 'ext3', '-t', 'ext2', '-t', 'reiserfs', '-t', 'jfs', '-t', 'ntfs', '-t', 'fat32', '-t', 'btrfs', '-t', 'fuseblk', '-t', 'zfs', '-t', 'simfs', '-t', 'xfs']).decode("Utf-8")
    total = p.splitlines()[-1]
    used = total.split()[3]
    size = total.split()[2]
    return int(size), int(used)

def get_load():
    system = platform.linux_distribution()
    if system[0][:6] == "CentOS":
        if system[1][0] == "6":
            tmp_load = os.popen("netstat -anp |grep ESTABLISHED |grep tcp |grep '::ffff:' |awk '{print $5}' |awk -F ':' '{print $4}' |sort -u |grep -E -o '([0-9]{1,3}[\.]){3}[0-9]{1,3}' |wc -l").read()
        else:
            tmp_load = os.popen("netstat -anp |grep ESTABLISHED |grep tcp6 |awk '{print $5}' |awk -F ':' '{print $1}' |sort -u |grep -E -o '([0-9]{1,3}[\.]){3}[0-9]{1,3}' |wc -l").read()
    else:
        tmp_load = os.popen("netstat -anp |grep ESTABLISHED |grep tcp6 |awk '{print $5}' |awk -F ':' '{print $1}' |sort -u |grep -E -o '([0-9]{1,3}[\.]){3}[0-9]{1,3}' |wc -l").read()

    return float(tmp_load)
#return os.getloadavg()[0]

def get_time():
    stat_file = file("/proc/stat", "r")
    time_list = stat_file.readline().split(' ')[2:6]
    stat_file.close()
    for i in range(len(time_list))  :
        time_list[i] = int(time_list[i])
    return time_list
def delta_time():
    x = get_time()
    time.sleep(INTERVAL)
    y = get_time()
    for i in range(len(x)):
        y[i]-=x[i]
    return y
def get_cpu():
    t = delta_time()
    st = sum(t)
    if st == 0:
        st = 1
    result = 100-(t[len(t)-1]*100.00/st)
    return round(result)

class Traffic:
    def __init__(self):
        self.rx = collections.deque(maxlen=10)
        self.tx = collections.deque(maxlen=10)
    def get(self):
        f = open('/proc/net/dev', 'r')
        net_dev = f.readlines()
        f.close()
        avgrx = 0; avgtx = 0

        for dev in net_dev[2:]:
            dev = dev.split(':')
            if dev[0].strip() == "lo" or dev[0].find("tun") > -1:
                continue
            dev = dev[1].split()
            avgrx += int(dev[0])
            avgtx += int(dev[8])

		self.rx.append(avgrx)
		self.tx.append(avgtx)
		avgrx = 0; avgtx = 0

		l = len(self.rx)
		for x in range(l - 1):
			avgrx += self.rx[x+1] - self.rx[x]
			avgtx += self.tx[x+1] - self.tx[x]

		avgrx = int(avgrx / l / INTERVAL)
		avgtx = int(avgtx / l / INTERVAL)

		return avgrx, avgtx

def liuliang():
    NET_IN = 0
    NET_OUT = 0
    with open('/proc/net/dev') as f:
        for line in f.readlines():
            netinfo = re.findall('([^\s]+):[\s]{0,}(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)', line)
            if netinfo:
                if netinfo[0][0] == 'lo' or 'tun' in netinfo[0][0] or netinfo[0][1]=='0' or netinfo[0][9]=='0':
                    continue
                else:
                    NET_IN += int(netinfo[0][1])
                    NET_OUT += int(netinfo[0][9])
    return NET_IN, NET_OUT

def get_network(ip_version):
	if(ip_version == 4):
		HOST = "192.168.80.18"		# 客户端地址
	elif(ip_version == 6):
		HOST = "ipv6.google.com"
	try:
		s = socket.create_connection((HOST, 80), 2)
		return True
	except:
		pass
	return False

if __name__ == '__main__':
	socket.setdefaulttimeout(30)
	while 1:
		try:
			print("Connecting...")
			s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
			s.connect((SERVER, PORT))
			data = s.recv(1024)
			if data.find("Authentication required") > -1:
				s.send(USER + ':' + PASSWORD + '\n')
				data = s.recv(1024)
				if data.find("Authentication successful") < 0:
					print(data)
					raise socket.error
			else:
				print(data)
				raise socket.error

			print(data)
			data = s.recv(1024)
			print(data)

			timer = 0
			check_ip = 0
			if data.find("IPv4") > -1:
				check_ip = 6
			elif data.find("IPv6") > -1:
				check_ip = 4
			else:
				print(data)
				raise socket.error

			traffic = Traffic()
			traffic.get()
			while 1:
				CPU = get_cpu()
				NetRx, NetTx = traffic.get()
				NET_IN, NET_OUT = liuliang()
				Uptime = get_uptime()
				Load = get_load()
				MemoryTotal, MemoryUsed, SwapTotal, SwapFree = get_memory()
				HDDTotal, HDDUsed = get_hdd()

				array = {}
				if not timer:
					array['online' + str(check_ip)] = get_network(check_ip)
					timer = 10
				else:
					timer -= 1*INTERVAL

				array['uptime'] = Uptime
				array['load'] = Load
				array['memory_total'] = MemoryTotal
				array['memory_used'] = MemoryUsed
				array['swap_total'] = SwapTotal
				array['swap_used'] = SwapTotal - SwapFree
				array['hdd_total'] = HDDTotal
				array['hdd_used'] = HDDUsed
				array['cpu'] = CPU
				array['network_rx'] = NetRx
				array['network_tx'] = NetTx
				array['network_in'] = NET_IN
				array['network_out'] = NET_OUT

				s.send("update " + json.dumps(array) + "\n")
		except KeyboardInterrupt:
			raise
		except socket.error:
			print("Disconnected...")
			# keep on trying after a disconnect
			s.close()
			time.sleep(3)
		except Exception as e:
			print("Caught Exception:", e)
			s.close()
			time.sleep(3)

在客户端运行 status-client.py 脚本

[root@node01 ~] python status-client.py &
[1] 105194

服务端配置

修改 config.json 文件,必须配置项为 username/password/host

[root@server ServerStatus] vim config.json 
{"servers":
 [
  {
   "username": "admin",					# 客户端账号
   "password": "admin",					# 客户端密码
   "name": "腾讯云-上海",
   "type": "KVM",
   "host": "192.168.80.18",			# 填写客户端 IP 地址
   "location": "CN",
   "disabled": false
  },
  {
   "username": "2",
   "password": "xxx",
   "name": "阿里云-香港",
   "type": "KVM",
   "host": "None",
   "location": "HK",
   "disabled": false
  },
  {
   "username": "3",
   "password": "xxxx",
   "name": "谷歌云-日本",
   "type": "KVM",
   "host": "None",
   "location": "JP",
   "disabled": false
  }
 ]
}

在 Web 监控页查看效果

image.png

大功告成~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1407293.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

01. eNSP环境以及VRP基本使用

eNSP的基本使用 1. eNSP的桥连接1.1. 具体操作&#xff08;1&#xff09;创建环回适配器&#xff08;2&#xff09;设置虚拟网卡&#xff08;3&#xff09;使用eNSP桥接计算机 2. 华为VRP系统2.1. 实验1&#xff1a;VRP的基本操作2.2. 实验2&#xff1a;文件命令&#xff08;1&…

mysql 基础(三)

一、多表设计 数据库设计范式 第一范式(确保每列保持原子性) 第一范式是最基本的范式。如果数据库表中的所有字段值都是不可分解的原子值&#xff0c;就说明该数据库表满足了第一范式。第二范式就是要有主键&#xff0c;要求其他字段都依赖于主键。 没有主键就没有唯一性&…

el-tree勾选后退出再打开显示之前已经勾选的

官网文档 element-ui官网文档有默认展开和默认选中 <el-tree:data"data"show-checkboxnode-key"id":default-expanded-keys"[2, 3]":default-checked-keys"[5]":props"defaultProps"> </el-tree><script>…

力扣518. 零钱兑换 II

动态规划 思路&#xff1a; 假设 dp[i] 为金额 i 使用零钱的组合数&#xff0c;其可以由其中的一种零钱 coin 和 i - coin 组合&#xff1b; 遍历零钱数组&#xff0c;对每一种零钱 coin 进行如下操作&#xff1a; 从 coin 到 amount 金额进行遍历&#xff0c;dp[j] dp[j] d…

Prometheus 薪资翻倍的监控系统?

1. 介绍与架构 Prometheus是一个开源的系统监控和警报工具包&#xff0c;用于收集和存储时间序列数据&#xff0c;包括指标信息、记录时间戳以及可选的键值对标签。许多公司使用Prometheus监控K8s集群。 2. 合适与不合适场景 合适场景 Prometheus适用于记录各种数字时间序列…

web系统架构基于springCloud的各技术栈

博主目前开发的web系统架构是基于springCloud的一套微服务架构。 使用的技术栈&#xff1a;springbootmysqlclickhousepostgresqlredisrocketMqosseurekabase-gatewayapollodockernginxvue的一套web架构。 一、springboot3.0 特性&#xff1a;Spring Boot 3.0提供了许多新特性…

每日一题——LeetCode1313.解压缩编码列表

这么简单的题目要说的这么复杂 nums里每相邻的两个元素nums[i]、nums[j]为一对&#xff0c;nums[i]表示nums[j]的次数 var decompressRLElist function(nums) {let res[]for(let i0,j1;j<nums.length-1;i2,j2){while(nums[i]--){res.push(nums[j])}}return res }; 消耗时…

代码随想录 Leetcode107. 二叉树的层序遍历 II

题目&#xff1a; 代码&#xff08;首刷自解 2024年1月24日&#xff09;&#xff1a; class Solution { public:vector<vector<int>> levelOrderBottom(TreeNode* root) {vector<vector<int>> res {};if(root nullptr) return res;queue<TreeNode…

第11次修改了可删除可持久保存的前端html备忘录:将样式分离,可以自由秒添加秒删除样式

第11次修改了可删除可持久保存的前端html备忘录&#xff1a;将样式分离&#xff0c;可以自由秒添加秒删除样式 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"…

Cesium for Unity包无法加载

太上老君急急如律⚡令⚡ &#x1f959;关闭UnityHub&#x1f9c0;启动梯子&#x1f96a;cmd 启动UnityHub &#x1f959;关闭UnityHub &#x1f9c0;启动梯子 &#x1f96a;cmd 启动UnityHub 把批处理启动文件&#x1f448;中的exe的路径换成自己的安装目录&#xff01;保存…

使用Electron打包vue文件变成exe应用程序

文章目录 一、下载Electron二、修改下载的Electron项目1.修改index.html文件2.修改main.js文件3.修改package.json文件 三、修改vue项目1.修改vite.config.js文件2.修改.env.production文件3.修改auth.js文件4.修改router下得index.js文件6.修改Navbar.vue文件 四、Electron打包…

ARMv8-AArch64 的异常处理模型详解之异常类型 Exception types

异常类型详解 Exception types 一&#xff0c; 什么是异常二&#xff0c;同步异常&#xff08;synchronous exceptions&#xff09;2.1 无效的指令和陷阱异常&#xff08;Invalid instructions and trap exceptions&#xff09;2.2 内存访问产生的异常2.3 产生异常的指令2.4 调…

Type-c一分二C+L/C+C同时快充数据线方案

一分二快充线是一种具有同时快充功能的线缆&#xff0c;可以实现同时给两个设备充电&#xff0c;并且都能达到快充的效果。那么&#xff0c;一分二快充线是如何实现同时快充功能的呢&#xff1f; 首先&#xff0c;一分二快充线采用了一种高效能的充电芯片LDR6020&#xff0c;这…

文件上传技术总结

语言可解析的后缀 &#xff08;前提&#xff1a;在Apache httpd.conf 配置文件中有特殊语言的配置 AddHandler application/x-httpd-php .php 搭配大小写、双重、空格来进行 其中&#xff1a; phtml、pht、php3、php4和php5都是Apache和php认可的php程序的文件后缀 常见的…

Web开发4:单元测试

在Web开发中&#xff0c;单元测试是一种重要的开发实践&#xff0c;它可以帮助我们确保代码的质量和可靠性。通过编写和运行单元测试&#xff0c;我们可以验证代码的正确性&#xff0c;减少错误和缺陷&#xff0c;并提高代码的可维护性。本文将介绍单元测试的概念、好处以及如何…

Markdown 数学公式详细总结

✍️作者简介&#xff1a;小北编程&#xff08;专注于HarmonyOS、Android、Java、Web、TCP/IP等技术方向&#xff09; &#x1f433;博客主页&#xff1a;开源中国、稀土掘金、51cto博客、博客园、知乎、简书、慕课网、CSDN &#x1f514;如果文章对您有一定的帮助请&#x1f4…

二分搜索树(Java)

完整代码在最后 树结构&#xff1a; 1.树结构本身是一种天然的组织结构 2.高效 二分搜索树的基础 1、二叉树 1.和链表一样&#xff1a;动态存储 2.具有唯一的根 3.每个结点最多只有2个孩子&#xff0c;每个结点最多只有一个父亲 4.具有天然的递归结构 2、满二叉树 a. 叶子…

关于IP地址欺骗的知识,看这篇文章就差不多了

无论是什么媒介,身份盗窃始终是一种威胁。所谓的“IP欺骗”是恶意用户为了他们的黑客攻击企图快速获得可信度的一种常见方式。 考虑到每台计算机和服务器都有一个唯一的标识符(Internet Protocol或IP地址),几乎任何使用互联网的人都可能受到攻击。IP欺骗是一种“伪造”源地…

开始读 Oracle PL/SQL Programming 第6版

最近觉得PL/SQL越来越重要&#xff0c;因为这本书早就在待读列表中&#xff0c;因此决定系统的学一下。 2024年1月24日晚开始读。 在亚马逊上的评价还不错&#xff1a; 本书的第一作者是Steven Feuerstein&#xff0c;是Oracle资深的Developer Advocate。 本书的示例代码可…

Gradlew安装配置和使用

官网 https://gradle.org/install/ 在线安装 $ sdk install gradle 8.5Homebrew is “the missing package manager for macOS”. $ brew install gradle手动安装 安装包下载 安装 $ mkdir /opt/gradle $ unzip -d /opt/gradle gradle-8.5-bin.zip $ ls /opt/gradle/gradle…