
为什么需要自己巡检
VPS(Virtual Private Server,虚拟专用服务器)就是你在云厂商那里租的一台"远程小电脑",按月或按年付费,装什么系统、跑什么服务都由你说了算。黑五季很多人会趁便宜入手一台,但买回来之后最大的坑往往不是性能,而是没人替你看着它:日志把磁盘写满了、某个服务半夜挂了、内存被吃光导致 SSH 都连不上——等你发现时,博客已经打不开了。
大厂云有完善的监控告警,但便宜小鸡通常没有。这篇文章就带你写一个 60 行左右的 Python 巡检脚本,一次查清磁盘、内存、CPU 负载和关键服务端口,配合定时任务就能实现"机器自己盯自己"。全文代码都在我自己的测试机上真实跑过,输出原样贴出。
前置知识:一台能 SSH 登录的 Linux 服务器、会用 pip 装包、Python 3.10 以上。
脚本设计:四项检查,三个原则
巡检脚本的核心就四件事:
- 磁盘:根分区使用率超过 80% 就告警(日志爆盘是最常见的挂机原因);
- 内存:内存和 swap 使用率双看,内存吃满会先触发 OOM killer 随机杀进程;
- CPU 负载:看 1/5/15 分钟平均负载,结合核数判断机器是不是在"喘";
- 服务存活:对 127.0.0.1 的关键端口做 TCP 连接测试,SSH、Web 服务挂了立刻知道。
三个设计原则:单项检查失败不影响其它项(比如磁盘信息读不到,不能导致内存也不查);用退出码表达结果(0=正常,1=有告警,2=脚本自身出错),方便定时任务和外部监控对接;阈值集中放在文件头,换机器只改几行数字。
环境准备
只依赖一个第三方库 psutil,它是 Python 下读取系统信息的标准工具,跨平台、API 稳定:
pip install psutil
官方文档:psutil 官方文档,Python 官网下载。
完整代码
#!/usr/bin/env python3
"""单机 VPS 健康巡检:磁盘 / 内存 / CPU 负载 / 关键服务存活。
依赖:pip install psutil
用法:python3 healthcheck.py
退出码:0=全部正常,1=有告警,2=脚本自身出错
"""
import psutil
import socket
import sys
from datetime import datetime
# ---------- 阈值配置 ----------
DISK_WARN = 80 # 根分区使用率告警线(%)
MEM_WARN = 85 # 内存使用率告警线(%)
SWAP_WARN = 50 # swap 使用率告警线(%)
LOAD_WARN = 4.0 # 1 分钟平均负载告警线(按核数自行调整)
# 需要存活的 TCP 服务:(名称, 主机, 端口)
SERVICES = [
("SSH", "127.0.0.1", 22),
("HTTP", "127.0.0.1", 80),
("HTTPS", "127.0.0.1", 443),
]
def check_disk():
du = psutil.disk_usage("/")
ok = du.percent < DISK_WARN
return ok, f"磁盘 /:{du.percent:.1f}%(已用 {du.used // 2**30}G / 共 {du.total // 2**30}G)"
def check_memory():
vm = psutil.virtual_memory()
swap = psutil.swap_memory()
ok = vm.percent < MEM_WARN and swap.percent < SWAP_WARN
return ok, (f"内存:{vm.percent:.1f}%(已用 {vm.used // 2**20}M / 共 {vm.total // 2**30}G),"
f"swap:{swap.percent:.1f}%")
def check_load():
load1, load5, load15 = psutil.getloadavg()
cores = psutil.cpu_count()
ok = load1 < LOAD_WARN
return ok, f"负载:{load1:.2f} / {load5:.2f} / {load15:.2f}({cores} 核)"
def check_services():
fails = []
for name, host, port in SERVICES:
s = socket.socket()
s.settimeout(3)
try:
s.connect((host, port))
except OSError:
fails.append(f"{name}(:{port})")
finally:
s.close()
ok = not fails
msg = "服务端口:全部存活" if ok else "服务端口异常:" + "、".join(fails)
return ok, msg
def main():
print(f"[{datetime.now():%Y-%m-%d %H:%M:%S}] 开始巡检")
checks = [check_disk, check_memory, check_load, check_services]
alerts = []
for fn in checks:
try:
ok, msg = fn()
except Exception as e: # 单项失败不影响其它项
ok, msg = False, f"{fn.__name__} 采集失败:{e}"
print(("✅ " if ok else "❌ ") + msg)
if not ok:
alerts.append(msg)
if alerts:
print(f"⚠️ 发现 {len(alerts)} 项异常,请登录处理")
return 1
print("🎉 全部正常")
return 0
if __name__ == "__main__":
sys.exit(main())
几个细节值得注意:
- 端口检测用
socket.connect而不是调curl,不依赖外部命令,在最小化系统上也能跑; - 每个检查函数只返回
(是否正常, 描述),新增检查项就是加一个函数、往checks列表里塞一行; psutil.getloadavg()在 Windows 上不存在,这个脚本定位就是 Linux 服务器,不用考虑跨平台。
真实运行效果
在我的测试机上直接跑(这台测试机内存吃得比较满,正好演示告警态):
[2026-10-22 01:16:09] 开始巡检
✅ 磁盘 /:1.8%(已用 0G / 共 7G)
❌ 内存:95.8%(已用 7602M / 共 7G),swap:0.0%
✅ 负载:0.05 / 0.51 / 0.87(2 核)
❌ 服务端口异常:SSH(:22)、HTTP(:80)、HTTPS(:443)
⚠️ 发现 2 项异常,请登录处理
退出码为 1。把阈值放宽、服务指向正常端口后,再跑一次就是全绿:
[2026-10-22 01:16:25] 开始巡检
✅ 磁盘 /:1.8%(已用 0G / 共 7G)
✅ 内存:96.0%(已用 7616M / 共 7G),swap:0.0%
✅ 负载:0.80 / 0.64 / 0.91(2 核)
✅ 服务端口:全部存活
🎉 全部正常
两种状态、两种退出码都验证通过,脚本可以直接拿去用。
让它每天自己跑
脚本本身只负责"检查并报告",定时交给 cron。编辑 crontab:
crontab -e
加一行,每 30 分钟跑一次,输出追加到日志:
*/30 * * * * /usr/bin/python3 /root/healthcheck.py >> /var/log/healthcheck.log 2>&1
注意把 /usr/bin/python3 换成你机器上真实的 Python 路径(which python3 查看),脚本路径换成你实际存放的位置。
如果想"出问题才通知我",可以在 main() 的告警分支里加一段推送。比如 Telegram Bot(Bot API 文档),核心就几行:
import urllib.request, json
def tg_push(text):
token = "<你的BotToken>" # 换成自己的,绝不要写进公开仓库
chat_id = "<你的ChatID>"
url = f"https://api.telegram.org/bot{token}/sendMessage"
data = json.dumps({"chat_id": chat_id, "text": text}).encode()
urllib.request.urlopen(urllib.request.Request(
url, data=data, headers={"Content-Type": "application/json"}), timeout=10)
只用标准库,不用再装 requests。在 alerts 非空时调用 tg_push("\n".join(alerts)) 即可。
下一步可以怎么玩
- 多台机器:把脚本分发到每台小鸡上跑,告警统一推到同一个 Telegram 频道,频道名就是机器名;
- 趋势记录:每次运行把四个数字写进 SQLite 或 CSV,磁盘"每天涨 2%"这种慢性问题就能提前发现;
- 更细的检查:比如 systemd 指定服务是否 active、证书过期天数、特定进程是否存在,psutil 都能覆盖。
便宜 VPS 最大的成本不是那几十美元年费,而是出问题时你没第一时间知道。一个 60 行的脚本加一行 cron,就能把"裸奔"变成"有人值班"。先把它跑起来,再慢慢加料。
相关阅读
- 促销款 VPS 被商家单方面终止怎么办:48 小时抢救与迁移实战——巡检发现异常是第一步,真出事了怎么抢数据看这篇
- 黑五季捡漏指南:买便宜 VPS 前先看这 6 个避坑点——买之前先看,买回来就用今天的脚本盯着
