分类:监控(monitoring) 标签: 监控、netdata、Prometheus、Grafana、Alertmanager、告警、Kubernetes 摘要: 一套完整监控体系怎么从零搭起来?本文从”为什么要监控”讲起,实操 netdata 快速上手、Prometheus + Grafana 全链路,再到 Prometheus 告警规则 + Alertmanager 邮箱通知的完整闭环。
一、先想清楚:监控到底监控什么?
我觉得,监控就回答三个问题:
- 机器还活着吗?(CPU / 内存 / 磁盘 / 网络)
- 服务还正常吗?(进程在不在、接口通不通、有没有报错)
- 出问题能提前知道吗?(指标异常 → 告警 → 通知处理)
围绕这三点,监控有两类做法:
- 轻量级:netdata —— 开箱即用,看个实时状态。
- 体系化:Prometheus + Grafana + Alertmanager —— 能存历史、能告警、能发通知,适合生产。
我做的时候先装 netdata 快速看全貌,再用 Prometheus 全家桶搭一套完整的含告警的体系,两套都实践了,对比看着才有体会。
二、第一套:netdata(一分钟上手的实时监控)
netdata 是我在阿里云服务器上通过 Docker 部署的,装完立刻能看机器实时状态。
部署
docker run -d --name netdata --network host \
-v /proc:/host/proc:ro \
-v /sys:/host/sys:ro \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
netdata/netdata:latest
为什么用 Docker 部署 netdata?(而不是直接 apt install)
一句话:Docker 就是一个”集装箱”,好处是干净、好搬、好管理。
- 直接
apt install netdata= 把东西直接堆在客厅地上:装了一堆依赖、配置散落在系统各处,哪天不要了卸载也卸不干净,还容易和系统里其他程序冲突。 - 用 Docker 跑 = 把 netdata 装进一个独立的集装箱里:宿主机客厅干干净净,东西全在箱子里,不要了把箱子一扔就清空。
具体好处:
- 不污染宿主机:依赖和运行环境全在容器里,不影响系统其他程序。
- 开箱即用、零配置环境:镜像里该有的都配好了,
docker run一条命令就跑起来。 - 好管理、好统一:
docker ps一眼看到所有服务(netdata、jenkins、mysql… 一起管),统一的启停/升级/删除方式。 - 可移植:这台服务器上配好的,拿到别的机器一条命令就能复制。
- 升级/回滚方便:换镜像 tag 升级,出问题回退旧镜像。
但有个特例要解决:netdata 装在 Docker”集装箱”里,它还怎么监控宿主机?——这就是下面要讲的
--network host和挂载卷的作用:虽然 netdata 住在箱子里,但我给它开了门,让它能探头看外面的宿主机。
这里有一个很关键的知识点:我用了 --network host(host 网络模式)。先看两种网络模式的差别:
- bridge +
-p:容器有自己的内网,要用-p 19999:19999把容器端口映射到宿主机。 - host:容器直接复用宿主机网络,占用宿主机的 19999 端口,不需要
-p映射。
① 为什么一定要给 netdata 用 host 模式?
netdata 要监控的不是容器自己,而是宿主机整台机器——CPU、内存、磁盘,尤其是网络流量。
- 用 host:容器和宿主机共享同一个网络,netdata 能直接看到宿主机真实的网卡(eth0、lo 等)和它的流量、端口、连接,看到的数据才是宿主机“真实”的。
- 用 bridge:容器用的是 Docker 虚拟出来的私有网卡,netdata 只能看到那个虚拟网卡的流量,看不到你服务器真实网卡的进出流量,监控就不准了。
所以 netdata 官方也是推荐 host 模式,原因就是它要完整监控宿主机。
② host 模式的代价(要用它就得知道)
- 端口直接暴露在宿主机:19999 直接占了宿主机的端口,如果宿主机某个程序已占用 19999 就会冲突。
- 隔离性差:容器和宿主机网络不隔离,不像 bridge 那样有独立内网。
③ 什么时候用哪个?(重要判断)
- 要完整监控宿主机(如 netdata、node-exporter)→ 用 host。
- 要隔离 + 端口映射、不想直接占宿主机端口(如你的 WordPress、MySQL)→ 用 bridge +
-p。
外网访问要过两层防火墙(容易踩的坑)
一开始访问 http://IP:19999 超时,排查后是两层防火墙都要放行:
ufw allow 19999/tcp # 第1层:系统 ufw
第2层:还要去云平台控制台(阿里云 → 轻量服务器 → 防火墙)放行 19999。
两层都通,外网才访问得到。这是云服务器新手最容易漏的一步。
netdata 上线后实时采集 4600+ 项指标,网页打开就能看 CPU、内存、网络、各容器实时曲线,零配置、纯看板。
三、第二套:Prometheus + Grafana(完整的监控链路)
netdata 只能看实时,存不了很久的历史、也做不了灵活告警。生产常用这条业界标准链路:
node-exporter(采集) → Prometheus(存储/抓取)→ Grafana(可视化)
- node-exporter:给机器”量体温”,暴露指标接口(默认 9100)。
- Prometheus:定期去抓指标存进数据库(默认 9090)。
- Grafana:把数据画成图形(默认 3000)。
我在本地 ans 虚拟机(Ubuntu + k3s)上用 kubectl 把这条链部署进集群。
① node-exporter.yaml —— 采集本机指标
apiVersion: apps/v1
kind: Deployment
metadata:
name: node-exporter
spec:
replicas: 1
selector: { matchLabels: { app: node-exporter } }
template:
metadata: { labels: { app: node-exporter } }
spec:
hostNetwork: true
containers:
- name: node-exporter
image: prom/node-exporter
ports: [ { containerPort: 9100 } ]
② prometheus.yaml —— 抓取并存储(配置主体)
这是纯监控的 Prometheus 配置,只负责抓取机器指标。
apiVersion: v1
kind: ConfigMap
metadata:
name: prometheus-config
data:
prometheus.yml: |
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'node'
static_configs:
- targets: ['192.168.47.10:9100']
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: prometheus
spec:
replicas: 1
selector: { matchLabels: { app: prometheus } }
template:
metadata: { labels: { app: prometheus } }
spec:
containers:
- name: prometheus
image: prom/prometheus
args: ["--config.file=/etc/prometheus/prometheus.yml"]
ports: [ { containerPort: 9090 } ]
volumeMounts:
- name: config
mountPath: /etc/prometheus/prometheus.yml
subPath: prometheus.yml
volumes:
- name: config
configMap: { name: prometheus-config }
---
apiVersion: v1
kind: Service
metadata: { name: prometheus }
spec:
type: NodePort
selector: { app: prometheus }
ports: [ { port: 9090, targetPort: 9090, nodePort: 30090 } ]
③ grafana.yaml —— 可视化大盘
apiVersion: apps/v1
kind: Deployment
metadata: { name: grafana }
spec:
replicas: 1
selector: { matchLabels: { app: grafana } }
template:
metadata: { labels: { app: grafana } }
spec:
containers:
- name: grafana
image: grafana/grafana
ports: [ { containerPort: 3000 } ]
---
apiVersion: v1
kind: Service
metadata: { name: grafana }
spec:
type: NodePort
selector: { app: grafana }
ports: [ { port: 3000, targetPort: 3000, nodePort: 30000 } ]
部署 & 验证
kubectl apply -f node-exporter.yaml
kubectl apply -f prometheus.yaml
kubectl apply -f grafana.yaml
kubectl get pods
- Prometheus
/targets:node 目标 UP ✅ - Grafana 加数据源
http://prometheus:9090连接成功 ✅ - CPU 曲线指标:
100 - avg(rate(node_cpu_seconds_total{mode="idle"}[1m]))*100✅
四、告警与通知(完整闭环,亲测)
这是让监控”会主动找上门”的关键一环,也是我完整亲手验证过的一段。链路:
Prometheus 规则(CPU>90%) → Alertmanager → 邮箱通知到手机
4.1 加告警规则
alerts.yml 的内容(CPU 使用率 持续超过 90%,for: 1m 维持 1 分钟 才触发 HighCPUUsage,避免短暂波动误报):
alerts.yml: |
groups:
- name: node_alerts
rules:
- alert: HighCPUUsage
expr: (100 - avg(rate(node_cpu_seconds_total{mode="idle"}[1m]))*100) > 90
for: 1m
labels:
severity: warning
annotations:
summary: "CPU usage high: {{ $value }}%"
修改prometheus.yaml文件
apiVersion: v1
kind: ConfigMap
metadata:
name: prometheus-config
data:
prometheus.yml: |
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'node'
static_configs:
- targets: ['192.168.47.10:9100']
alerts.yml: | #加在这里
groups:
- name: node_alerts
rules:
- alert: HighCPUUsage
expr: (100 - avg(rate(node_cpu_seconds_total{mode="idle"}[1m]))*100) > 90
for: 1m
labels:
severity: warning
annotations:
summary: "CPU usage high: {{ $value }}%"
---
要让这条规则生效,还要做 3 件事:
① 在 prometheus.yml 里加 rule_files,告诉它去哪加载规则:
rule_files:
- /etc/prometheus/rules/*.yml
修改prometheus.yaml文件
data:
prometheus.yml: |
global:
scrape_interval: 15s
rule_files: # 加在这里,告警规则
- /etc/prometheus/rules/*.yml
scrape_configs:
- job_name: 'node'
static_configs:
- targets: ['192.168.47.10:9100']
② 在 Deployment 里用 subPath 把 alerts.yml 挂到那个规则目录:
volumeMounts:
- name: config
mountPath: /etc/prometheus/prometheus.yml
subPath: prometheus.yml
- name: config
mountPath: /etc/prometheus/rules/alerts.yml
subPath: alerts.yml
③ 改 ConfigMap 不会自动重启,要重启加载:
kubectl apply -f prometheus.yaml
kubectl rollout restart deployment prometheus
最后浏览器打开 http://IP:30090/alerts,能看到 HighCPUUsage(状态 Inactive)就说明规则生效了。
4.2 部署 Alertmanager(负责把告警发出去)
新建 alertmanager.yaml,里面配了 QQ 邮箱 SMTP:
apiVersion: v1
kind: ConfigMap
metadata:
name: alertmanager-config
data:
alertmanager.yml: |
global:
smtp_smarthost: 'smtp.qq.com:465'
smtp_from: 'xxx@qq.com'
smtp_auth_username: 'xxx@qq.com'
smtp_auth_password: '16位授权码' # 不是登录密码
smtp_require_tls: false
route:
group_by: ['alertname']
group_wait: 10s
repeat_interval: 1h
receiver: 'email'
receivers:
- name: 'email'
email_configs:
- to: 'xxx@qq.com'
---
apiVersion: apps/v1
kind: Deployment
metadata: { name: alertmanager }
spec:
replicas: 1
selector: { matchLabels: { app: alertmanager } }
template:
metadata: { labels: { app: alertmanager } }
spec:
containers:
- name: alertmanager
image: prom/alertmanager
args: ["--config.file=/etc/alertmanager/alertmanager.yml"]
ports: [ { containerPort: 9093 } ]
volumeMounts: [ { name: config, mountPath: /etc/alertmanager } ]
volumes: [ { name: config, configMap: { name: alertmanager-config } } ]
---
apiVersion: v1
kind: Service
metadata: { name: alertmanager }
spec:
type: NodePort
selector: { app: alertmanager }
ports: [ { port: 9093, targetPort: 9093, nodePort: 30093 } ]
⚠️ QQ 邮箱发信的关键:邮箱 → 登录 → 设置 → 账号 → 开启 “IMAP/SMTP服务”,会生成16 位授权码。Alertmanager 里填的是授权码,不是登录密码。 ⚠️ 常见坑:QQ 邮箱如果开了”免打扰”,邮件不会弹提醒,容易以为没发出来——其实看收件箱就有。
4.3 让 Prometheus 把告警推给 Alertmanager
这一步要在 prometheus.yml 里加”告警转发”配置(alerting 块):
alerting:
alertmanagers:
- static_configs:
- targets: ['alertmanager:9093']
修改prometheus.yaml文件
data:
prometheus.yml: |
global:
scrape_interval: 15s
rule_files: # 告警规则
- /etc/prometheus/rules/*.yml
alerting: # 加在这,告警发给 alertmanager
alertmanagers:
- static_configs:
- targets: ['alertmanager:9093']
scrape_configs:
- job_name: 'node'
static_configs:
- targets: ['192.168.47.10:9100']
- 验证:加完
kubectl apply -f prometheus.yaml并kubectl rollout restart deployment prometheus,然后访问http://IP:30090/status→ Alertmanagers 一栏显示 Up 即成功。
4.4 触发验证(亲眼看到闭环)
for i in 1 2 3 4 5; do yes > /dev/null & done # 4核机器打满CPU
等 1 分多钟,会看到:
http://IP:30090/alerts→ HighCPUUsage 先 Pending,后 Firing(红)http://IP:30093(Alertmanager)→ 能查到这条告警,接收者 email- QQ 邮箱收到告警邮件 📧
测完关闭负载:
pkill yes # 告警随之回到 Inactive
我实际跑通了整个过程:CPU 打满 → Prometheus 判定 Firing → Alertmanager 收到并发送 → QQ 邮箱收到邮件。这就是完整的”采集 → 存储 → 展示 → 告警 → 通知”闭环。
4.5 更多通知方式(配置参考)
Alertmanager 不只是邮件,还能发到群机器人。以下是参考配置(我尚未亲手验证,实际接入时需按平台机器人规则微调):
钉钉群机器人
receivers:
- name: dingtalk
webhook_configs:
- url: 'https://oapi.dingtalk.com/robot/send?access_token=你的token'
send_resolved: false
飞书群机器人
receivers:
- name: feishu
webhook_configs:
- url: 'https://open.feishu.cn/open-apis/bot/v2/hook/你的token'
send_resolved: false
五、常见坑(快速查)
| 坑 | 现象 | 解决 |
|---|---|---|
| 外网访问不到 | 浏览器超时 | ufw 和云平台安全组两层都要放行 |
| 改配置不生效 | 加了规则/alerting 但没反应 | 改 ConfigMap 后要 rollout restart deployment |
| 采集目标 Down | /targets 里 node 是 DOWN | 查 IP:port 对不对、目标服务起没起、IP 变没变(Pod 重建 IP 会变,优先用 Service 名) |
| 只画图不告警 / 告警轰炸 | 从没收到提醒,或整天响 | 阈值和 for 时长要调好,别让瞬时波动误报 |
| 收不到邮件 | 告警已 Firing 却收不到 | ① 查 Alertmanager 日志 ② 检查 SMTP 授权码 ③ 看 QQ”免打扰”是否吞了提醒 |
| 时间不同步 | 监控数据对不上、触发时机怪 | 宿主机同步 NTP(timedatectl) |
| Grafana 拉镜像失败 | ContainerCreating/ImagePullBackOff | k3s 配国内镜像加速或 ctr 手动 pull |