不用装Agent,SSH直连搞定服务器监控
几台宿主机跑着几十个 Docker 容器,怎么用一台服务器把它们全盯住?SSH + 定时任务 + 告警,不装 Agent,不买 Zabbix。
一、痛点:谁在看服务器?
我们公司的服务器上跑了几十个 Docker 容器------Nginx、MySQL、Redis、微服务......运维同事最怕的就是:服务挂了没人知道,等用户投诉了才发现。
之前的做法是手动 SSH 上去 top 看一眼,CPU 高不高、内存够不够、磁盘满了没。一台还好,几台轮着查就很烦了。更别说 Docker 容器------谁知道哪个容器偷偷把内存吃光了。
所以就有了这个需求:用一台服务器,定时采集所有机器的指标,异常自动告警。
二、整体思路
不复杂,就一条链路:
markdown
定时任务(5分钟一次)
→ SSH 连接目标主机
→ 执行采集命令(Windows用PowerShell,Linux用shell)
→ 解析结果入库
→ 前端实时展示 + 告警通知
不用在每台被监控的机器上装 Agent,就靠 SSH 直连。轻量、无侵入。
三、核心实现
3.1 跨平台 SSH 采集
SSH 连接用 JSch(Java 的 SSH 客户端库),不用装额外依赖:
java
JSch jsch = new JSch();
Session session = jsch.getSession(account, ip, 22);
session.setPassword(password);
session.setConfig("StrictHostKeyChecking", "no");
session.connect();
连上之后执行采集命令。这里要区分操作系统------Windows 和 Linux 命令完全不一样。
Windows 用 PowerShell + WMI:
powershell
$cpu = (Get-WmiObject Win32_Processor | Measure-Object -Property LoadPercentage -Average).Average
$os = Get-WmiObject Win32_OperatingSystem
$mem = [math]::Round(($os.TotalVisibleMemorySize - $os.FreePhysicalMemory) / $os.TotalVisibleMemorySize * 100, 1)
$disk = Get-WmiObject Win32_LogicalDisk -Filter 'DeviceID=''C:'''
if ($disk) { $du = [math]::Round(($disk.Size - $disk.FreeSpace) / $disk.Size * 100, 1) } else { $du = 0 }
echo CPU=$cpu; echo MEM=$mem; echo DISK=$du
关键细节:多核 CPU 必须用
Measure-Object -Average算均值,否则拿到的不是整体使用率。
Linux 用 shell 命令:
bash
top -bn1 | grep 'Cpu(s)' | awk '{printf "CPU=%.1f\n",100-$8}'
free -m | awk '/Mem:/{printf "MEM=%.1f\n",$3/$2*100}'
df -h / | awk 'NR==2{gsub(/%/,"");print "DISK="$5}'
不管是 Windows 还是 Linux,输出统一都是 CPU=xx MEM=xx DISK=xx 这种格式,Java 端解析就很方便了。
3.2 定时任务
用若依自带的定时任务框架,每 5 分钟执行一次:
java
@Component("kvmCollectTask")
public class KvmCollectTask {
@Autowired
private KvmCollectorService kvmCollectorService;
/** 每5分钟采集一次 */
public void collectMetrics() {
kvmCollectorService.collectAllHosts();
}
}
采集方法里遍历所有主机,逐个 SSH 采集,异常的主机自动标记为离线。
批量采集的时候注意: 接口里要开独立线程,不让前端点完按钮一直转圈:
java
new Thread(() -> kvmCollectorService.collectAllHosts(), "kvm-batch-collect").start();
3.3 告警系统
采集完不能只存起来,得在指标异常的时候主动通知。
三级阈值设计:
| 级别 | 条件 | 处理 |
|---|---|---|
| HEALTHY | CPU/内存/磁盘 全部 < 80% | 正常 |
| WARNING | 任一 ≥ 80% | 触发预警 |
| CRITICAL | 任一 ≥ 90% | 触发严重告警 |
告警去重是关键。 同一个主机的 CPU 一直 95%,不能每次采集都发一条告警,不然五分钟一条,一天就是 288 条。
用 dedupKey 做去重:
java
String dedupKey = "HOST_" + host.getId() + "_CPU";
KvmAlert existing = alertMapper.selectByDedupKey(dedupKey);
if (existing != null) {
// 已有同类告警,不重复发
return;
}
// 新告警,插入
alertMapper.insertKvmAlert(alert);
自动恢复: 指标降回正常范围后,不用人工处理,代码自动把告警状态改为 RESOLVED:
java
if (val < warn) {
existing.setStatus("RESOLVED");
existing.setResolutionNotes("指标恢复正常,自动解决");
alertMapper.updateKvmAlert(existing);
}
3.4 Docker 容器监控
宿主机指标看了还不够,上面的 Docker 容器也得监控。直接用 docker stats --no-stream 拿实时数据:
bash
docker stats --no-stream
输出大概长这样:
erlang
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O
abc123def456 nginx 1.50% 120MiB / 2GiB 5.86% 1.2MB / 0.8MB 0B / 0B
def456abc789 my-app 23.40% 512MiB / 4GiB 12.50% 50MB / 30MB 10MB / 5MB
Java 端解析 docker stats 的输出,按列拆分取 CPU%、MEM%、网络和磁盘 IO。
Windows 踩坑: Docker Desktop 在 Windows 上,SSH 直接执行 docker 命令会找不到,因为非交互式 SSH 不加载用户 PATH。加 cmd /c 前缀解决:
java
String wrap = isWin ? "cmd /c " : "";
String cmd = wrap + "docker stats --no-stream";
3.5 一个大坑:Docker 容器回连宿主机
这个问题卡了我半天。
场景是这样的:监控服务本身跑在 Docker 容器里,要 SSH 去采集宿主机的指标。宿主机 IP 是 192.168.2.42,容器里直接 ssh 192.168.2.42 连不上。
原因是 Windows Docker Desktop 的网络隔离------容器不能通过宿主机的外网 IP 回连。
解决办法:先试原 IP,失败后自动回退到 host.docker.internal:
java
for (String targetIp : new String[]{ip, "host.docker.internal"}) {
try {
return sshCollectRaw(targetIp, account, password, osType);
} catch (Exception e) {
log.debug("SSH采集 [{}] 失败,尝试下一个...", targetIp);
}
}
throw new RuntimeException("SSH采集失败: 所有地址均无法连接");
host.docker.internal 是 Docker Desktop 提供的特殊域名,容器里访问它会解析到宿主机的内部地址(192.168.65.254),完美绕过网络隔离。
四、前端展示
后端数据有了,前端做成监控页面:
- 指标卡片:CPU / 内存 / 磁盘使用率,红黄绿三色标识
- 告警列表:当前活跃告警 + 已恢复历史,一目了然
- Docker 容器列表:每个容器的 CPU/内存/网络 IO,实时更新
- 3 秒自动刷新:前端轮询后端接口,不用手动刷新页面
五、总结
这套方案的核心思想就一句话:不装 Agent,SSH 直连,定时采集,异常告警。
相比 Zabbix、Prometheus 这些重型监控系统,优势是:
| 传统监控 | 这套方案 | |
|---|---|---|
| 部署 | 每台机器装 Agent | 零侵入,SSH 即用 |
| 配置 | 复杂的 yaml 配置文件 | 填 IP、账号、密码就行 |
| 学习成本 | 高 | 会 SSH 就会用 |
| 适用规模 | 几十到上万个节点 | 几台到几十台 |
一个中小企业、一个运维外包团队、一台服务器------够用了。
同系列文章:
下一篇:Docker 部署避坑指南,敬请关注。
