ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

用Codex快速搭建Linux服务器CPU内存磁盘监控面板

用Codex快速搭建Linux服务器CPU内存磁盘监控面板 在实际服务器运维里“能看到趋势”和“只能敲命令”是两种完全不同的体验。CPU、内存、磁盘的瞬时值可以用top、free -h、df -h看但要判断“过去十分钟内存是不是一直在涨”“磁盘是不是周期性写满”还是得靠一张持续刷新的监控面板。Codex 这类 AI 编码助手很适合用来加速这种轻量级面板开发它能快速生成采集脚本、Web 接口和图表页面但监控口径、采集频率、安全边界这些决策仍然要由人来确认。这篇文章从一个真实、可复现的案例出发先用 Codex 生成 CPU、内存、磁盘采集模块再补一个 Flask 服务把指标通过 API 暴露出来最后用 Chart.js 画成可视化页面并把它注册为 systemd 服务常驻运行。读者按顺序操作后会得到一套运行在 Linux 服务器上的轻量级监控面板如果只需要临时使用也可以只采用采集脚本部分把 JSON 输出接到其他监控系统里。1. 先判断场景Codex 适合当脚手架不适合替你决定监控口径1.1 临时查看命令的问题在哪里服务器出问题时第一反应通常是登录机器看top或free -h。这种方式能解决“此刻发生了什么”却不能回答几个更关键的问题CPU 是从什么时候开始升高的内存占用有没有持续增长的趋势磁盘空间是在什么时间段被消耗掉的我离开终端后又发生了哪些变化要回答这些问题需要一份带历史记录的可视化数据。可选的方案很多Prometheus 配合 Grafana 是业界常见组合但对于一台只需要看 CPU、内存、磁盘的小型服务器部署和运维成本偏高。更轻量的做法是写一个采集脚本定期把指标写入内存或文件再提供一个网页展示。代码量不大但涉及 psutil、Flask、前端图表、systemd 等多个知识点。这类“中小型脚手架 定制脚本”的任务正是 Codex 比较擅长的类型。1.2 Codex 在真实开发里的分工边界Codex 不是一行一行帮你从零规划架构的工具而是适合在明确边界内快速产出代码。以监控面板为例可以交给 Codex 的任务包括根据需求描述生成psutil采集代码。把采集结果整理成固定结构的 JSON。生成 Flask 路由和页面静态文件。编写 Chart.js 折线图画法。生成 systemd 服务单元文件。不能交给 Codex 直接决定的事情包括监控哪些挂载点跳过哪些伪文件系统。采集间隔是 5 秒还是 30 秒。历史数据保留多久存在内存还是数据库。服务绑定到哪个地址是否允许外来访问。进程以哪个 Linux 用户运行读取哪些目录。这些决策与业务、服务器配置、安全和运维策略强相关。AI 生成的代码只能作为实现载体不能替代人工做技术判断。1.3 我们最终要做成什么样文章以一个运行在 Ubuntu 22.04 测试服务器上的案例为例代码在 CentOS、Rocky Linux 等系统上同样能运行只是安装 Python 相关依赖的包管理器命令不同。最终产物如下模块作用实现要点采集层读取 CPU、内存、磁盘数据使用 psutil间隔采样API 层为前端提供最新数据和历史数据Flask 提供/api/metrics和/api/history展示层可视化展示指标Chart.js 折线图 分区表格常驻层服务开机自启、异常重启systemd 管理安全层限制访问范围默认只绑定 127.0.0.1通过防火墙限制来源整个链路强调“最小可运行”生产环境要在此基础之上继续补充认证、告警和数据持久化。2. 环境准备和目录设计先统一运行环境再让 Codex 写代码2.1 Python 与依赖准备项目中 Python 代码依赖psutil和Flask。推荐使用虚拟环境避免污染系统 Python也方便 systemd 使用确定性的解释器路径。在 Ubuntu / Debian 系系统上先执行sudo apt update sudo apt install -y python3 python3-venv python3-pip在 CentOS / Rocky Linux 8 上可以使用sudo yum install -y python38 python38-venv python38-pip如果你使用的发行版自带 Python 3系统包的名称可能略有不同。这里以/opt/server-monitor作为项目目录先创建虚拟环境sudo mkdir -p /opt/server-monitor sudo chown $USER /opt/server-monitor cd /opt/server-monitor python3 -m venv venv source venv/bin/activate pip install --upgrade pip pip install flask psutil依赖使用建议写入requirements.txt便于以后复现。flask3.0 psutil5.9注意这里的版本号表示建议起点不一定是当前最新版。安装完成后用pip show flask psutil或python -c import flask, psutil; print(flask.__version__, psutil.__version__)查看实际版本。2.2 先确定 CPU、内存、磁盘的采集口径很多监控面板“看起来能用数据却不准确”问题出在一开始没有定义清楚采集口径。对下面的指标需要分别明确CPU文章中采集整体使用率、每核使用率、系统负载loadavg和 CPU 核心数。top里看到的 CPU 使用率通常是某段时间内的平均值所以采集时不能只读一次瞬时值。psutil 的cpu_percent(interval1)会等 1 秒返回这段时间内的平均使用率更接近人类理解的“CPU 占用”。内存要区分物理内存总量、可用内存、已用内存和 swap。Linux 的可用内存在语义上不等于free因为 page cache 等内存在内存压力下通常可以回收。psutil 的virtual_memory()返回了available实际排查时更适合使用它判断是否“内存不够”。磁盘遍历磁盘分区而不是只查根分区。同时要把squashfs、overlay、/snap这类路径过滤掉否则面板上会出现一堆奇怪的只读挂载点百分比也容易让人误解。2.3 建议的项目目录结构/opt/server-monitor/ ├── requirements.txt ├── server_metrics.py ├── app.py ├── static/ │ ├── index.html │ ├── chart.umd.js │ └── monitor.jsserver_metrics.py负责采集数据并支持命令行直接运行app.py是 Flask 入口同时启动后台采集线程静态目录里放前端页面、Chart.js 和页面脚本。这样做的优点是采集逻辑与 Web 逻辑分离后续如果要把采集结果写入 InfluxDB 或推送到企业告警平台不需要改动 Web 层。3. 用 Codex 生成采集模块让 CPU、内存、磁盘输出结构化 JSON3.1 给 AI 写清楚需求比让它自由发挥更重要使用 Codex 生成采集脚本时可以把下面这段描述作为一个提示词模板。它不会一次性解决所有问题但能保证生成的代码覆盖主要采集项请用 Python 3 写一个采集服务器状态的脚本使用 psutil 库。CPU采集整体使用率、每核使用率、系统负载 loadavg、核心数。内存采集 total、available、used、free、percent 和 swap 信息。磁盘遍历磁盘分区跳过 squashfs、overlay 等伪文件系统返回挂载点、设备名、文件系统类型、total、used、free、percent。最终在终端打印一个 JSON 字符串包含当前时间戳 unix 秒数。代码要能在 Linux 上直接运行。AI 返回的代码大概率可以运行但需要人工检查两个地方磁盘过滤是否完整CPU 采集是否真正做了区间采样。下面给出满足上述需求的完整采集脚本。3.2 采集脚本server_metrics.py#!/usr/bin/env python3 # -*- coding: utf-8 -*- 采集 CPU、内存、磁盘指标并打印 JSON 到标准输出。 import json import time import psutil def collect_cpu(): # interval1 表示等待 1 秒返回这段时间内的平均使用率 percent psutil.cpu_percent(interval1) per_core psutil.cpu_percent(interval1, percpuTrue) loadavg psutil.getloadavg() return { percent: percent, per_core: per_core, loadavg: [round(x, 2) for x in loadavg], cores: len(per_core), } def collect_memory(): mem psutil.virtual_memory() swap psutil.swap_memory() return { total: mem.total, available: mem.available, used: mem.used, free: mem.free, percent: mem.percent, buffers: getattr(mem, buffers, None), cached: getattr(mem, cached, None), swap_total: swap.total, swap_used: swap.used, swap_percent: swap.percent, } def collect_disk(): partitions [] for part in psutil.disk_partitions(allFalse): # 跳过伪文件系统和无挂载信息的设备 if part.fstype in (, squashfs, overlay, tmpfs, devtmpfs): continue if part.mountpoint.startswith((/snap, /boot/efi, /dev, /proc, /sys)): continue usage psutil.disk_usage(part.mountpoint) partitions.append({ device: part.device, mountpoint: part.mountpoint, fstype: part.fstype, total: usage.total, used: usage.used, free: usage.free, percent: usage.percent, }) return partitions def collect_once(): return { timestamp: int(time.time()), cpu: collect_cpu(), memory: collect_memory(), disk: collect_disk(), } if __name__ __main__: print(json.dumps(collect_once(), ensure_asciiFalse, indent2))关键点写在注释里interval1让 CPU 采样有实际意义磁盘过滤让返回数据更干净。psutil.disk_usage()在读取某些系统挂载点时可能报PermissionError如果这台服务器使用了特殊权限控制需要在 Web 服务运行时分配合理的读取权限。注意这段脚本的第一行 CPU 采集会等待 1 秒所以运行一次需要约 2 秒左右这是正常现象不是程序卡死。3.3 命令行验证 JSON 输出切换到虚拟环境后执行cd /opt/server-monitor source venv/bin/activate python server_metrics.py预期输出结构类似{ timestamp: 1735000000, cpu: { percent: 12.3, per_core: [8.0, 15.0, 20.0, 6.0], loadavg: [0.5, 0.3, 0.1], cores: 4 }, memory: { total: 8388608000, available: 4000000000, used: 3500000000, free: 1200000000, percent: 53.2, buffers: 200000000, cached: 2000000000, swap_total: 2147483648, swap_used: 0, swap_percent: 0.0 }, disk: [ { device: /dev/vda1, mountpoint: /, fstype: ext4, total: 53687091200, used: 20000000000, free: 30000000000, percent: 38.0 } ] }看到这个 JSON 后采集这一层就可以关闭了。如果这里报错不要继续写 Web 层因为上游数据错误会一路传导到页面。这一层最常见的坑有没有激活虚拟环境直接运行会出现ModuleNotFoundError: No module named psutil因为系统 Python 环境没有安装依赖。等待时间过长被误认为卡死interval1会真实等待连续执行两个不同 CPU 指标时整个脚本需要约 2 秒。磁盘过滤过严或过松过滤掉/boot会导致看不到独立启动分区不过滤 overlay 又会产生大量无意义数据。规则需要结合服务器实际挂载情况调整。4. 让 Codex 补上 Flask 服务和图表页面把 JSON 变成面板4.1 第二次提示词要强调接口契约采集脚本只负责“生成数据”Web 层需要解决三件事后台定时采集并缓存最新指标。前端每次轮询/api/metrics不需要等待 1 秒实时计算。保留最多 120 条历史数据前端可以加载最近 10 分钟左右的趋势。如果继续用 Codex提示词可以写成请用 Python Flask 写一个轻量监控 Web 服务。 后台线程每 5 秒调用一次采集函数把最新指标和最近 120 条历史指标存到内存里。 提供两个接口/api/metrics 返回最新数据/api/history 返回全部历史数据。 根路径返回 static/index.html。Flask 服务启动时要支持 --host 和 --port 参数默认 127.0.0.1:8080。这个提示词定义了“接口契约”和“数据流”比笼统说“帮我写监控面板”更容易得到可改代码。内存历史记录重启会丢失这一点要在代码注释或设计说明里写清楚避免误以为它具备持久化能力。4.2 Flask 主程序app.py#!/usr/bin/env python3 # -*- coding: utf-8 -*- 轻量服务器监控面板 Flask 入口。 import argparse import threading import time from flask import Flask, jsonify import server_metrics as sm app Flask(__name__, static_folderstatic, static_url_path/static) DEFAULT_INTERVAL 5 DEFAULT_HISTORY_LIMIT 120 _cache_lock threading.Lock() _latest_metric {} _history [] def generate_snapshot(): return { timestamp: int(time.time()), cpu: sm.collect_cpu(), memory: sm.collect_memory(), disk: sm.collect_disk(), } def background_collect(interval: int, history_limit: int): global _latest_metric while True: snapshot generate_snapshot() with _cache_lock: _latest_metric snapshot _history.append(snapshot) if len(_history) history_limit: del _history[0] time.sleep(interval) app.route(/) def index(): return app.send_static_file(index.html) app.route(/api/metrics) def api_metrics(): with _cache_lock: return jsonify(_latest_metric) app.route(/api/history) def api_history(): with _cache_lock: return jsonify(list(_history)) def parse_args(): parser argparse.ArgumentParser(descriptionServer monitor dashboard) parser.add_argument(--host, default127.0.0.1) parser.add_argument(--port, typeint, default8080) parser.add_argument(--interval, typeint, defaultDEFAULT_INTERVAL) parser.add_argument(--history-limit, typeint, defaultDEFAULT_HISTORY_LIMIT) return parser.parse_args() if __name__ __main__: args parse_args() thread threading.Thread( targetbackground_collect, args(args.interval, args.history_limit), daemonTrue, ) thread.start() # 仅在开发或内网演示使用生产环境应使用 waitress/gunicorn 等 WSGI 服务器 app.run(hostargs.host, portargs.port, debugFalse, threadedTrue)这里有一个容易被忽略的设计/api/metrics返回的是后台线程缓存的最新快照而不是在请求里临时调用collect_cpu()。否则每次前端刷新都要等待 CPU 采样 1 秒接口明显变慢。后台采集线程与请求线程用锁保护共享数据避免多线程情况下列表和字典写入不一致。4.3 前端静态页面先在static/index.html中写入页面骨架!DOCTYPE html html langzh-CN head meta charsetutf-8 meta nameviewport contentwidthdevice-width, initial-scale1 title服务器监控面板/title style body { font-family: system-ui, -
返回列表