
干监控运维这行快十年Nagios 一直是我生产环境里最稳的这个角色没有之一。很多人一听 Nagios 就嫌它老界面土、配置折腾可真正在企业级环境里跑过几千台主机的人心里都有数它那套对象模型、状态机逻辑和插件生态放到今天依然扎实得很。这篇就用一个老兵的口吻把 Nagios 从部署架构、配置组织、插件开发到告警升级、踩坑排障的实战经验一次讲透适合刚从 Zabbix 或 Prometheus 转过来的朋友也适合还在用 Nagios 但想把它用得更顺手的人。1. 监控体系搭建前的整体设计思路1.1 为什么在大数据监控时代还选 Nagios先聊一个经常被问的问题Prometheus、Zabbix、Grafana 全家桶那么香为什么还要选 Nagios我的答案很朴素Nagios 的价值不在界面和存储而在它极致的“状态判定 告警”逻辑。它的核心模型非常简单——每个被监控对象只有 OK、WARNING、CRITICAL、UNKNOWN 四种状态配合重试机制决定是 SOFT 还是 HARD 状态再决定要不要触发通知。这套模型一旦理解了写出的监控项和告警规则会非常有条理不容易出现那种“告警风暴淹死人”的局面。另一个理由是生态兼容性。Nagios 的插件规范退出码 0/1/2/3 文本输出几乎成了监控界的事实标准市面上大量设备、应用、中间件都直接给 Nagios 插件格式的监控脚本。哪怕你最终要迁移到别的平台插件本身很多可以复用迁移成本很低。还有一点很实际Nagios 是纯 C 实现不吃内存一台 2C4G 的虚拟机跑几百台主机的监控毫无压力。企业里如果只是做基础监控、巡检和告警Nagios Core 完全够用没必要上来就上重型平台。当然我也承认它的短板没有原生时序数据库历史数据需要借助插件写 rrd 或外接 InfluxDBUI 确实停留在上个时代。但这些都可以通过后续工程化手段补齐下面展开讲。1.2 企业级监控维度怎么拆解在企业里上监控第一件事不是装软件而是把“要监控什么”理清楚。我习惯分四层来拆。第一层是基础设施层CPU、内存、磁盘、网络流量、系统负载、进程存活、关键服务端口。这层用 Nagios 自带插件加 NRPE 就能覆盖是监控的地基。第二层是网络层交换机、路由器、防火墙的连通性、端口状态、丢包率、延迟。Nagios 通过 SNMP 协议配合 check_snmp 插件来做能拿到设备自己上报的状态比单纯 ping 靠谱得多。第三层是应用层Nginx、MySQL、Redis、Tomcat、消息队列等中间件的存活状态、连接数、慢查询数、主从同步延迟。到了这层没有现成插件就只能自己写脚本或者去社区找别人封装好的插件再改。第四层是业务层接口响应时间、订单成功率、支付回调延迟、注册转化率等真正和业务 KPI 挂钩的指标。这一层通常是监控的终极目标但也是最容易被忽略的。我之前带团队时要求所有核心接口必须有 Nagios 监控项业务方一旦上线新接口首先要过监控评审这一关否则不许进生产。这四层拆完每个层级的监控对象、插件选型、告警级别就都有了明确归属配置起来才不会乱。2. 企业级部署架构与配置组织2.1 单机、主从还是分布式Nagios 的部署架构要跟着企业规模走我基于实际经验给三档建议。小型环境几十台主机内单机部署 Nagios Core配置全部放本机NRPE 代理部署到被监控端。简单直接省一台机器。中型环境几百台主机建议做一主一备多节点。主节点负责调度和通知备用节点每天同步配置和状态遇到主机宕机或主进程挂掉能快速顶上来。同步用 rsync 加 cron 就够不需要搞太复杂。Nagios 的配置文件是文本形式rsync 天然友好。大型环境几千台主机以上单实例撑不住多地区网络的巡检延迟建议拆成多个“巡检区域”。每个区域独立部署一台 Nagios 实例负责本地主机的监控和原始告警区域实例再把告警汇总到一个中央 Nagios。汇总不是靠 Nagios 对 Nagios而是通过 NSCA 协议把区域的告警结果推给中央节点中央节点统一做通知和报表。这样既分散了巡检压力又保留了全公司统一的告警出口。另一个部署细节是 Web 端与核心分离。Nagios Core 本身只出 CGI建议在上面套 Nginx PHP-FPM把 Web 界面做成内网独立域名配合 LDAP 认证接入统一权限体系。这套组合实测很稳几台机器同时刷新状态页也不卡。2.2 配置目录设计别把所有东西塞一个文件企业级 Nagios 最忌讳的就是所有配置堆在 nagios.cfg 里改一行都要全局 reload。我从第一天就强制推行按目录拆分目录结构长这样/usr/local/nagios/etc/ ├── nagios.cfg # 主配置只做基础参数 ├── objects/ │ ├── templates.cfg # 通用模板 │ ├── contacts.cfg # 联系人、联系人组 │ ├── contactgroups.cfg # 联系组按业务线拆分 │ ├── timeperiods.cfg # 监控与通知时间窗 │ ├── commands.cfg # 插件命令定义 │ ├── hosts/ # 按业务域分文件 │ │ ├── web.cfg │ │ ├── db.cfg │ │ └── middleware.cfg │ └── services/ # 服务监控项 │ ├── host-alias.cfg │ ├── app-services.cfg │ └── custom-checks.cfg主配置文件里只要用cfg_dir指向目录每加一组机器就新建对应配置文件绝不修改既有文件。这样做的直接好处是报障时能秒级定位是哪个业务域出了问题而不是在一堆几千行的配置文件里 CtrlF。还有一个关键习惯对象继承要用好。Nagios 的模板继承能省掉大量重复定义比如我定义一个linux-server-host模板define host { name linux-server-host check_command check-host-alive check_interval 2 retry_interval 1 max_check_attempts 3 notifications_enabled 1 notification_interval 60 notification_options d,u,r register 0 }每加一台新主机只要use linux-server-host然后覆盖host_name、alias、address三个属性就行。团队里实习生都能快速上手加监控不会因为漏写一个参数导致配置起不来。2.3 监控项的命名与状态定义规范监控项命名这事看着小真到了几十上百个监控项的时候命名混乱能把人逼疯。我自己定了一套规则团队一直沿用。[业务域]-[主机短名]-[指标类型]_[具体内容]比如web-api-01-disc_usage /表示 web-api-01 的根分区磁盘使用率db-mysql-master-replication_delay表示 MySQL 主从延迟。这个命名规则在我前公司服务了几百个监控项出问题时谁都能一眼看懂在监控什么。然后是新机器接监控的标准动作先连得上、再管资源、再看应用。拆成三条连通性check_ping、check_ssh、check_tcp 保证机器活着、端口通。基础资源check_cpu、check_load、check_mem需要插件、check_disk、check_swap。应用服务应用端口、进程数、日志关键词日志用 check_log 插件。每接一台机器先把这三层的监控项过一遍再交付不要只加个 ping 就算监控完成那样等于没有监控。3. 插件体系与自定义监控脚本编写3.1 自带插件哪些最常用Nagios 自带的监控插件集中在/usr/local/nagios/libexec/目录每个都是一个独立可执行文件统一遵守“退出码 输出文本”的规范。我常用的清单如下插件名监控内容常用参数典型场景check_pingICMP 连通性-H -w -c -p跨机房节点连通性check_sshSSH 端口存活-H -p系统层服务存活check_httpHTTP 接口状态-H -u -w -c -s网站/API 健康检查check_tcpTCP 端口连通-H -p中间件端口探测check_disk磁盘空间使用率-w -c -e -p分区容量预警check_load系统负载-w -cCPU 过载监控check_procs进程数量与状态-C -a -c应用进程守护check_swap交换分区-w -c内存水位辅助check_snmpSNMP 指标采集-H -o -w -c网络设备监控这里面最容易被低估的是check_tcp和check_procs。很多中间件故障并不是端口不通而是连接数异常堆积check_tcp配合-t超时就能发现问题苗头进程监控则要注意 Zombie 进程的堆积那往往是代码层内存泄漏的先兆。3.2 自定义脚本的写法与退出码约定没有现成插件是常事Nagios 的自定义监控脚本才是真正拉开运维水平差距的地方。插件协议其实很简单脚本退出码 0 表示 OK1 表示 WARNING2 表示 CRITICAL其他值归为 UNKNOWN脚本向 stdout 输出一行文本说明当前值和阈值关系如果要画图还能在文本后用|分隔输出性能数据perfdata。我拿一个 Java 应用 GC 暂停时间的监控脚本举例这是我在生产环境里写过的#!/bin/bash # check_full_gc_time.sh —— 监控 Java Full GC 耗时 LOG_FILE${1:-/var/log/app/gc.log} WARN${2:-500} CRIT${3:-1500} # 取最近一次 Full GC 的耗时单位毫秒 FGC_TIME$(grep Full GC $LOG_FILE | tail -1 | awk -F [()] {print $2} | awk -F sec {print $1} | awk {print $1*1000}) if [ -z $FGC_TIME ]; then echo UNKNOWN - No Full GC record found exit 3 fi if [ $(echo $FGC_TIME $CRIT | bc) -eq 1 ]; then echo CRITICAL - Full GC took ${FGC_TIME}ms (threshold ${CRIT}ms) exit 2 elif [ $(echo $FGC_TIME $WARN | bc) -eq 1 ]; then echo WARNING - Full GC took ${FGC_TIME}ms (threshold ${WARN}ms) exit 1 else echo OK - Full GC took ${FGC_TIME}ms exit 0 fi脚本里有两个细节值得展开。第一阈值用参数传入而不是写死在代码里这样做的好处是同一套脚本可以应用到不同的业务场景改阈值不用改代码。第二性能数据没有输出如果你想接 Grafana 或 PNP4Nagios 画趋势图需要在返回文本后面加上|分隔OK - Full GC took 120ms | fgc_time120ms;500;1500Nagios 会把|后面的内容作为性能数据存下来交给后续绘图组件处理。性能数据是监控数据资产的核心等讲到数据扩展时再展开。3.3 NRPE 主被动监控模式怎么取舍Nagios 对主机的资源监控最经典的方式是 NRPE 代理模式Nagios 服务器通过check_nrpe命令去调用被监控主机上的 NRPE 守护进程NRPE 再执行我们预先定义好的插件把结果返回给服务器。这是“拉取”模式是主流的默认选择。NRPE 之外还有两个常见协议NRDPNagios Remote Data Processor和 NSCANagios Service Check Acceptor。NRDP 被设计为替代 NRPE 的新协议支持加密和被动传输NSCA 则是典型的“推送”模式被监控端主动把结果推给 Nagios 服务器。以我的实战经验推荐这样组合内网资源监控用 NRPE 拉取简单稳定防火墙也好控制。云端临时实例或外网节点用 NRDP 或 NSCA 推送避免服务器主动出外网引发安全审查问题。定时任务类检查比如每天凌晨跑的备份脚本脚本跑完后主动用 NSCA 把结果推给 Nagios值班人员早上只需要看告警有没有来不需要人工翻备份日志。开头提到 Nagios 的生态兼容性其实 NRPE 规范也被 Zabbix、Open-Falcon 等后来者借鉴熟练 NRPE 的插件对接方式后到其他平台上迁移监控项时思路是一样的。4. 告警分级、通知降噪与升级机制4.1 SOFT 和 HARD 状态搞懂它就不怕告警风暴刚入门 Nagios 的人最容易忽视的是状态判定里的 SOFT 和 HARD。简单说当监控项第一次返回非 OK 状态时Nagios 不会立刻确认故障先标记为 SOFT。它会按retry_interval反复检查直到连续失败次数达到max_check_attempts才确认这是一个 HARD 状态。HARD 状态一旦确立才会真正触发通知逻辑。这个机制非常像人判断问题只看一次异常不慌连续多次仍是异常才算故障。我在生产环境里最常用的参数组合是max_check_attempts3、retry_interval1也就是一分多钟内连续失败三次才真正报警。如果一次抖动立马告警半夜就会被拉起来处理一些其实已经自愈的问题投诉率极高。有一个反面案例之前维护过一个老系统Redis 瞬时连接数偶尔飙升到临界值又落下当时配了max_check_attempts1结果晚上 11 点到凌晨 2 点连续收到八次“Redis 连接数过高”告警最终核实全是业务瞬时高峰引起的误报。把尝试次数调到 3 以后告警声音几乎消失真正出问题时服务层面也早已有多个监控项同时报红。4.2 联系人与升级策略怎么设Nagios 的通知体系是按联系人和联系人组发散出去的通知的“分寸感”很吃配置。我把自己的策略分享出来。第一按业务线建联系人组杜绝全局轰炸。比如订单组、支付组、基础设施组每个组只管自己业务相关的监控项基础设施故障机房断电、核心交换机挂掉通知给全体值班组。第二在联系人定义里用can_submit限制权限配合host_notification_period和service_notification_period限制通知时间。非核心业务可以在工作时间段09:00-19:00通知核心业务 7x24 小时通知。第三升级机制要“先一线后二线”。我常用的联系方式定义define contact { contact_name oncall-1 alias 值班一线 service_notification_options w,u,c,r host_notification_options d,u,r service_notification_period 24x7 host_notification_period 24x7 service_notification_command notify-service-by-email host_notification_command notify-host-by-email }一线收到告警后如果 5 分钟仍未确认/fix就需要有一个“自动升级”的动作。Nagios 原生的通知重复机制notification_interval只会在同一联系人内重复发并没有真正跨不同级别升级。我实际的解法是写一个外部脚本监听 Nagios 的 notification 事件日志如果同一对象的 HARD 状态持续时间超过 5 分钟就调用二次通知脚本去呼叫二线负责人微信或电话。这套方案用 Python 脚本 cron 实现逻辑简单可靠。4.3 通知通道邮件、微信、企业机器人Nagios 原生支持的通知命令就是notify-service-by-email等几个宏替换把主机名、服务名、当前状态、附加输出填充到邮件模板里。我的默认模板会包含以下核心信息主机名$HOSTNAME$、地址$HOSTADDRESS$服务描述$SERVICEDESC$状态$SERVICESTATE$和输出$SERVICEOUTPUT$出现时间$LONGDATETIME$持续时间$SERVICEDURATION$把这些字段做成 HTML 模板值班手机端也能快速判断故障类型。邮件之外现在企业普遍用企业微信或钉钉机器人。实现也不难Nagios 通知命令本质是一个 shell 命令我写了一个 webhook 脚本放到/usr/local/nagios/libexec/notify_wecom.sh#!/bin/bash WEBHOOK_URLhttps://qyapi.weixin.qq.com/cgi-bin/webhook/send?keyYOUR_KEY TEXT【Nagios告警】${hostname} / ${servicedesc} 状态: ${servicestate} 输出: ${serviceoutput} 时间: ${datetime} curl -s -X POST $WEBHOOK_URL \ -H Content-Type: application/json \ -d {\msgtype\: \text\, \text\: {\content\: \$TEXT\}} /dev/null实际生产环境里我把 webhook 脚本封装了一层先判断一条告警在 10 分钟内是否已推送过如果推过则直接跳过。因为notification_interval会重复发不做防抖的话值班群容易被刷屏。这个防抖逻辑我用的是/tmp/notify_wecom_last_time.txt记录时间戳简单有效。5. 生产环境常见问题与排查手册5.1 NRPE 连接超时与解决思路我在多个集群里遇到最多的坑就是check_nrpe报Connection refused或Connection timed out。这类问题 90% 是三个原因第一被监控端 NRPE 服务没起来或配置有误。先在被监控机本地跑systemctl status nrpe或service nrpe status并确认nagios用户有执行插件的权限。再直接本机执行/usr/local/nagios/libexec/check_nrpe -H 127.0.0.1排除网络因素。第二防火墙拦截了 5666 端口。很多发行版默认启用 firewalld 或 UFW光在 NRPE 配置里允许 IP 没用系统防火墙端口不开照样不通。检查firewall-cmd --list-ports或iptables -L -n后放行 5666 或者只允许监控服务器 IP 访问。第三NRPE 配置的allowed_hosts没有包含监控服务器地址。注意 NRPE 只认“IP”如果监控服务器有多个网卡出口 IP要把所有可能的出口 IP 都加上。我甚至踩过一次Nagios 服务器挂在交换机后面出网 IP 是防火墙的 NAT 地址被监控端只填了内网 IP结果调试了一下午。另一个高频坑是check_nrpe时报NRPE: Unable to read output。这个多半是插件执行超时或插件输出异常。NRPE 默认command_timeout是 60 秒如果某个脚本执行超过 60 秒就会被杀掉报无输出。遇到这种优先把监控脚本的执行时间控制在 10 秒以内如果实在需要长时间探测单独调大对应 command 的 timeout 参数而不是全局改。5.2 磁盘监控误报与 inode 问题check_disk是生产环境里最大的一类误报源原因主要是分区挂载点的覆盖和 inode 耗尽。先讲挂载点覆盖。Nagios 的 check_disk 默认会监控所有挂载分区但容器或虚拟化场景里/tmp、/var/lib/docker等目录会重复挂载导致同一个后端存储被统计多次明明磁盘余量充足却报 CRITICAL。我经验里的解法是显式指定要监控的分区不要让它自动扫/usr/local/nagios/libexec/check_disk -w 15% -c 8% -p / -p /data只监控“业务数据实际落在上面”的分区/ 和一个数据盘其余的一律不管。之后所有新机器接入监控都执行这个标准磁盘误报率显著下降。再讲 inode 耗尽这个更隐蔽。磁盘空间够但 inode 用完了应用依然写不了文件。Nagios 的check_disk如果不加-i参数不会监控 inode所以我给每台主机的磁盘监控都加了一个独立监控项专门查 inode/usr/local/nagios/libexec/check_disk -w 15% -c 8% -i -p /一旦出现大量小文件日志没有轮转、队列文件堆积的场景这个监控项能让你提前几天发现问题而不是等故障发生时一脸懵。5.3 大规模巡检性能优化企业级环境里 Nagios 采一场遍的要花很久主要瓶颈是 check 调度的串行机制。默认 Nagios 一次只能并发执行上限数量的检测需要调大并发参数。nagios.cfg里三个参数是我每次优化必改的max_concurrent_checks64 check_result_reaper_frequency10 event_broker_options-1max_concurrent_checks控制同时发起的检测数调大后能显著缩短巡检周期。但不是越大越好首先要保证监控服务器 CPU 和文件描述符够用其次被监控端 NRPE 默认并发连接能力有限调到 128 甚至 256 时NRPE 端容易因为大量并发连接而拒绝服务。另一个细节是check_external_commands和command_file队列。外部命令如果频繁写入会积压建议把command_check_interval设小一点比如command_check_interval5s或者-1持续监听。还有状态文件读写Nagios 每次状态变化都会写status.dat机器多了以后这个文件会越来越大。我有一次遇到过 status.dat 超过 200MB每次 Web 刷页面都卡成狗。解法是定期清理过期状态或者把status_update_interval适当调大status_update_interval30再配合一个 nightly cron 压缩备份 status.dat 文件从那次以后 Web 界面从来没有因为状态文件卡过。5.4 配置变更与 reload 的坑Nagios 的配置校验是全量校验nagios -v命令建议每个配置修改后都执行一遍避免带上错误进生产环境。团队里有新人想跳过我这一步直接 reload结果退了两次配置。我的习惯流程是/usr/local/nagios/bin/nagios -v /usr/local/nagios/etc/nagios.cfg # 确认 Total Warnings: 0 / Total Errors: 0 后再执行 systemctl reload nagios注意 reload 之前的校验是在临时状态下验的正式 reload 时 Nagios 会用nagios.cfg里的实际配置重新验证一遍。但我实测中总会自己先跑一遍-v既能提前发现问题也能熟悉配置项之间的依赖关系这个习惯我一直保留。6. 监控数据的后续扩展与自动化管理6.1 从 Nagios 到可视化报表的衔接很多团队只把 Nagios 当“告警器”其实它的性能数据是很有价值的时间序列资产。我建议从第一天就开启 perfdata 导出process_performance_data1然后在 Nagios 服务里配置 perfdata 写到指定目录再用 PNP4Nagios 打开图形入口。PNP4Nagios 的部署不算难它靠模板扫描 perfdata匹配到主机服务后自动生成 rrd 图Web 里点一下就能看到走势。曾经我们靠 PNP 的磁盘增长曲线提前预判了一次数据库磁盘容量危机那周值班的人印象深刻。如果你想上真正的时序数据库可以把 perfdata 交给 Logstash InfluxDB 清洗入库Grafana 出图。Nagios 作为采集和告警层Grafana 作为可视化层这两者的组合完全能撑起一个中型公司的监控展示需求。这个方案在 Nagios 社区里非常成熟可行性很高。6.2 配置批量生成与自动化脚本最后聊聊 Nagios 和自动化配置管理如 Ansible、SaltStack的结合。手工在配置文件里添加几百台服务器的监控效率极低而且容易漏、容易错。我后期的做法是维护一份 CMDB 源数据用 Ansible 的 template 模块自动生成 hosts 配置和 services 配置再通过 handler 调用 nagios -v 校验和 reload。模板思路大概是CMDB 里每个主机带着 sayhost_typeweb、business_domainorderAnsible 渲染时自动把app-services.cfg里对应服务模板套用上生成配置、校验、reload、检查 NRPE 连通性一条流水线走完。这套流程带来的改变是新机器从交付到被监控从原来的半天压缩到 10 分钟而且不留历史手改痕迹。还有一个自动化细节监控项上线前建议统一跑一遍check_nrpe -H 新机器IP -c 监控命令来验证 agent 侧插件是否工作正常。把这个“预检”也写进自动化里能避免配置下发后 Nagios 报一堆 UNKNOWN 的尴尬情况。6.3 新项目接入 Nagios 的评审清单根据我多年的观察很多监控事故不是 Nagios 本身问题而是“新项目接入监控”这个流程没走好。我整理了一份接入检查清单每次新服务上线都按它过一遍服务是否至少有一个 TCP 端口存活监控项。依赖资源磁盘、内存、CPU是否指标齐全。应用业务层是否有自定义脚本或日志关键字检查。监控项是否设置了合适的重试次数和告警时间窗。联系人组是否匹配业务线的值班团队。通知渠道是否做了防抖和升级策略。性能数据是否已开启并能保存到历史存储。这套清单在老东家执行了三年接入的 300 余个服务没有因为“漏配监控”出过 P0 级事故。回头看看准备好比修一堆告警更重要。我个人在实际操作中还有一个习惯每隔一段时间会主动拉取 Nagios 报来的 UNKNOWN 状态监控项逐个排查为什么是 UNKNOWN而不是放着不管。UNKNOWN 状态往往意味着插件权限不对、路径没配对或者脚本本身有 bug这些隐患如果不处理等到真正出故障时它会变成盲区。监控平台本身也需要被监控、被呵护Nagios 带来的价值才真正完整。