免费云服务器巡检自动化实战:几十台机器,只看一份日报

举报
yd_242888859 发表于 2026/11/07 15:53:48 2026/11/07
【摘要】 免费云服务器、免费容器、试用主机,单看每一台都不难管。难的是数量上来以后:这台 48 小时要续期一次,那台连续运行 24 小时会被平台强制停止,还有的面板上写着 Running,服务其实早就访问不通了。靠人每天逐个登录面板检查,不现实,也必然漏检。我这段时间的做法,是把巡检做成一套自动化的闭环:定时探测、按规则判断、能自动修的小故障直接修,修不了的才汇总成一份日报推给我。下面把这套思路和可直...

免费云服务器、免费容器、试用主机,单看每一台都不难管。难的是数量上来以后:这台 48 小时要续期一次,那台连续运行 24 小时会被平台强制停止,还有的面板上写着 Running,服务其实早就访问不通了。

靠人每天逐个登录面板检查,不现实,也必然漏检。我这段时间的做法,是把巡检做成一套自动化的闭环:定时探测、按规则判断、能自动修的小故障直接修,修不了的才汇总成一份日报推给我。下面把这套思路和可直接改造的代码分享出来。

巡检不能只看面板状态

这是我踩坑最多的一点:面板状态不等于服务可用。

有的平台接口长期返回 starting,实际进程已经稳定运行;有的平台显示 Running / Healthy,公网地址却完全连不上;还有的服务对 GET 请求返回 404,对 HEAD 请求才是正常的存活响应。如果只采集面板字段就下结论,误报和漏报都会很多。

可靠的巡检至少要做三层验证:

  • 面板或接口层:读取实例状态、到期时间、资源用量,判断是否临近续期或已被暂停。
  • 网络层:对公网地址或业务入口做真实请求,看状态码是否符合预期,而不是只看端口开不开。
  • 业务层:请求一个固定的健康路径(例如 /health),校验返回内容,确认进程不只是活着,而是真的在提供服务。

三层里任意一层异常,都先记录现场再处置,不要看到状态不对就立刻重启。先留证据,后面复盘才知道是平台停机、进程崩溃,还是网络问题。

一套可落地的三层巡检架构

我的巡检拆成三层,互不耦合:

层级

做什么

典型实现

采集层

拉取面板状态、发探针请求、读到期时间

平台接口、HTTP 请求

判断层

按规则分类为正常、临期、异常、真停机

阈值和状态机

处置层

自动重启、自动续期、汇总通知

接口调用、定时任务

这样拆的好处是:换一个平台,只需要改采集层的适配;判断和通知的逻辑可以一直复用。机器从 3 台涨到 30 台时,新增的只是一行配置,而不是一套新脚本。

核心巡检脚本示例

下面是一个精简版的巡检脚本。它读取一份机器清单,逐台做探针,把结果分成正常、临期和异常三类,最后输出一份可读的汇总。实际使用时,把平台的续期和重启接口补到处置环节即可。

import urllib.request
import urllib.error
from datetime import datetime, timezone

# 机器清单:名称、健康检查地址、可接受的状态码、到期时间(ISO 格式,可为空)
HOSTS = [
    {
        "name": "host-a",
        "health_url": "https://example.com/health",
        "ok_codes": [200],
        "expire_at": "2026-11-20T00:00:00+00:00",
    },
    {
        "name": "host-b",
        "health_url": "https://example.com/health",
        "ok_codes": [200, 400],  # 有些服务以 400 表示“已到达业务层”
        "expire_at": None,
    },
]

WARN_HOURS = 24  # 到期前多少小时开始提醒


def probe(url: str, timeout: int = 10) -> int:
    """返回 HTTP 状态码,连不上返回 -1。用 HEAD 优先,个别服务可用 GET 替换。"""
    req = urllib.request.Request(url, method="HEAD")
    try:
        with urllib.request.urlopen(req, timeout=timeout) as resp:
            return resp.status
    except urllib.error.HTTPError as e:
        return e.code
    except Exception:
        return -1


def check_host(host: dict) -> str:
    code = probe(host["health_url"])
    if code not in host["ok_codes"]:
        return f"[异常] {host['name']} 探针返回 {code},疑似停机或网络不通"

    if host.get("expire_at"):
        expire = datetime.fromisoformat(host["expire_at"])
        left_hours = (expire - datetime.now(timezone.utc)).total_seconds() / 3600
        if left_hours < 0:
            return f"[过期] {host['name']} 已过期,请立即处理"
        if left_hours <= WARN_HOURS:
            return f"[临期] {host['name']} 剩余约 {left_hours:.1f} 小时,请及时续期"

    return f"[正常] {host['name']} 探针 {code}"


if __name__ == "__main__":
    lines = [check_host(h) for h in HOSTS]
    print("\n".join(lines))
    # 这里可以接你的通知通道:把非“正常”的行汇总后推送,避免逐条打扰

几个细节值得注意:

  • 可接受状态码要按服务实测来定,不要一律认为只有 200 才算活着。有些 WebSocket 或代理类服务,探针返回 400 恰恰说明请求已经到达业务层。
  • 探针要有超时。没有超时的巡检,一台机器卡住,整轮巡检都会被拖死。
  • 到期提醒的阈值要留足余量。周期 48 小时的免费续期,我一般提前 24 小时就进提醒名单,给网络波动和人工处理留时间。

自动修复的边界要先划清

巡检发现问题就自动处理,效率确实高,但边界必须在写代码之前就定死。我的划分原则只有一条:可逆的自动做,不可逆的先问人。

可以直接自动执行的:

  • 服务进程退出时按原参数拉起
  • 接口确认停机后调用平台的 Start / Restart
  • 到期前在免费额度内自动续期
  • 临时文件、日志轮转等不影响数据的清理

必须停下来人工确认的:

  • 任何涉及付费、升级套餐的动作
  • 删除实例、删除数据、重装系统
  • 修改密码、密钥、令牌等凭据类操作

这条边界不是保守,而是算账:一台免费机器误重启一次,代价是几分钟不可用;误删除或误付费一次,代价可能是整台机器和里面的部署全部重来。自动化省的是重复劳动,不该替人做不可逆的决定。

还有一个容易忽略的点:自动重启之后必须再次探针验证。重启接口返回成功,只代表指令发出去了,不代表服务恢复了。我的流程是重启后等待一小段时间,重新走一遍三层探针,通了才把事件标记为已恢复,没通就升级为人工处理。

调度、去重与通知

调度上,我用的是最朴素的组合:系统定时任务负责触发,脚本本身负责判断。周期按平台特性分开设置,快过期的平台查得勤一点,长期稳定的平台一天一次足够。

通知最容易做错的,是把每一条异常都单独推一条消息。机器一多,一次网络抖动就是几十条报警,看的人很快就会麻木,真正的故障反而被淹没。我的做法是三点:

  • 汇总推送:一轮巡检只发一份汇总,正常项一行带过,异常项展开写清机器、现象和已执行的处置。
  • 去重限频:同一台机器的同一类异常,在未恢复前只提醒一次,恢复后再发一条恢复通知。持续故障靠日报兜底,不靠刷屏。
  • 静默正常项:全部正常时只发一句结论。巡检的价值是让人不用看,而不是每天制造阅读负担。

凭据管理上还有一条硬规矩:接口密钥、令牌只放在机器本地的受限文件里(权限 600),不写进脚本、不提交到代码仓库、不出现在日志和通知内容里。巡检脚本一旦要分享或开源,先把配置抽到环境变量或独立配置文件,这一步不能省。

踩过的坑

  • 只信控制台:有一次控制台连续几天打不开,我以为机器出事了,后来发现是平台自己的 Web 端故障,机器一直在正常运行。所以巡检结论要多源交叉验证,单一来源不可用时只能记为“未核实”,不能直接判故障。
  • 探针方法选错:同一个健康路径,用 GET 是 404、用 HEAD 是 200,差点误判停机去重启一台好机器。每个服务接入巡检时,先手动把探针方法试对,再写进配置。
  • 虚拟机或运行环境被更换后,定时任务丢失:托管环境重建后,脚本文件还在,但系统级的定时单元没有了,巡检静默停摆。教训是巡检本身也要被巡检——加一个简单的存活心跳,长时间没有新一轮结果时主动报警。
  • 只看助手侧探针就宣布恢复:探针通了,只能证明从巡检机这个网络位置能访问。最终是否真的可用,还要以实际使用端的连接结果为准,尤其是网络路径差异很大的场景。

写在最后

免费资源的玩法,拼的从来不是谁找到的机器多,而是谁的机器能长期稳定地活着。把续期、探活、重启、通知这四件重复的事交给脚本,人只处理真正需要判断的异常,几十台机器的运维量可以压缩到每天看一份日报。

上面这套方案没有用任何重型框架,一个 Python 脚本加定时任务就能起步。等机器再多起来,再考虑把结果落库、做趋势统计也不迟——先跑起来,比先设计完美更重要。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。