尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
K8s上的Flask论坛监控实战:Prometheus+Grafana从埋点到告警
这是我那套K8s上的Flask论坛项目的第四篇。前三篇分别讲了容器化改造、持久化存储和Ingress路由一直写到服务能稳定对外提供访问本来以为到这一步就算毕业了。结果有一次凌晨用户发帖开始转圈我们早上才从反馈里发现问题当时看任何机器指标都还是绿的。这次事故直接催生了这套PrometheusGrafana监控方案也才有了这篇记录。这篇里不会有那种高大上的云原生理念更多是我实际踩过的坑和最后沉淀下来的配置。适合两类人看一是服务已经上了K8s但还没装监控想快速补上观测能力的同学二是已经装了监控但发现面板一大堆、告警一大堆真出问题时不知道先看哪个的人。读完你至少能把这套论坛从资源指标到业务指标全部串起来遇到告警也能按图索骥。1. 为什么这个项目必须补上监控这块1.1 一次“无声事故”逼出来的监控出事那天晚上服务没有崩进程活着数据库连接也正常但用户发帖就是慢。我们当时还停留在上一套监控思维里登到机器上top一下看看CPU、内存、磁盘一切正常就以为没事了。真正的问题出在Flask应用里一个第三方接口的超时重试把请求线程全部堵住了而这种问题根本不会在操作系统指标上表现出来。这件事让我意识到K8s环境下的监控痛点不是“指标不够多”而是“观测对象变了”。以前单机部署主机IP固定进程PID固定写个脚本定期采集就行。到了K8s里Pod随时会被重建副本数会被HPA拉来拉去节点也会扩缩容再去盯一台固定机器根本没有意义。监控系统必须能动态发现服务按标签去聚合数据。另外还有一个很隐蔽的问题以前一台机器上跑一个论坛机器指标基本就等于业务指标。现在请求打到哪个Pod、哪个副本上完全随机光看平台层的CPU内存根本不知道用户体感是什么。要么在Flask里埋点要么继续当睁眼瞎。我选择了前者。1.2 为什么偏偏是Prometheus Grafana选型时我也看过Zabbix、云厂商监控、ELK这些方案最后定下PrometheusGrafana不是因为它们名字响而是因为架构匹配。Zabbix这种传统监控更适合物理机、虚拟机这种长期稳定的对象在Pod频繁重建的K8s里你需要不停更新主机列表维护成本很高。云厂商监控对自建集群的支持比较尴尬能采集一些基础指标但应用层指标还是得自己想办法而且多云环境下很容易被绑住。ELK那套更适合处理日志不太适合做指标这种需要实时聚合和告警的用途。Prometheus的做法更像“抄表员定期上门”它每隔一段时间主动来拉你的指标而不是等你打电话上报。这个拉取模型在K8s里优势很明显Pod漂了、IP换了、副本多了它通过服务发现自动找到新地址只要标签没变就能继续抓。加上K8s生态里很多组件原生吐Prometheus格式指标几乎零额外适配。Grafana则负责把Prometheus里的数据变成人看得懂的图面板生态和告警可视化都够用。两者一个藏数据、一个展示配合起来很顺。2. 监控方案的整体拆解先定指标再谈工具2.1 分清平台指标和应用指标监控方案落地前我先把指标分成了两层。很多人第一步容易搞混一上来就装组件装完发现图是有了但全是平台层的业务出问题根本看不出端倪。平台层指标主要来自K8s本身比如container_cpu_usage_seconds_total、container_memory_working_set_bytes这类由kubelet里的cAdvisor对外暴露Prometheus装上之后默认就能抓到。这一层回答的是“机器累不累、Pod撑不撑得住”。应用层指标需要自己在Flask里埋点回答的是“用户请求有没有被正确处理”。我根据这个论坛项目的实际业务整理了一张清单指标名类型来源说明forum_http_requests_totalCounterFlask累计HTTP请求数forum_http_request_duration_secondsHistogramFlask请求耗时分布forum_login_totalCounterFlask累计登录成功次数forum_active_usersGaugeFlask当前在线用户数container_cpu_usage_seconds_totalCounterK8s容器CPU累计使用container_memory_working_set_bytesGaugeK8s容器内存使用量这些指标不是闭眼拍出来的。我当时的思路是先想清楚“如果今晚论坛出问题我从哪几个图开始看”。最后收敛到三个核心指标请求量、延迟、错误率。再叠加一个业务状态指标“在线用户数”用来判断是不是真的有人在用。2.2 延迟、QPS、错误率这些指标的口径怎么定监控指标里最容易踩坑的是“延迟到底怎么算”。我当时差点就直接统计平均耗时后来发现根本不能用。原因很简单平均值的方差极大某个接口如果偶尔有一个超慢请求平均值瞬间被拉高但其实99%的用户完全没感知。这就像“平均工资”一样一个极高值能把整体拉起飞。正确做法是用直方图加分位数把请求耗时按区间分桶再通过PromQL里的histogram_quantile算出P99、P95。这样能看到真实的尾部延迟而不是一个被稀释的平均数。这里我列一下Flask侧创建直方图时的分桶设置from prometheus_client import Histogram REQUEST_TIME Histogram( forum_http_request_duration_seconds, HTTP请求耗时, buckets(0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10) )分桶不是越细越好要贴近业务实际。论坛接口大部分在100毫秒左右所以100毫秒前后我分得比较细超过2.5秒就属于异常区间了。如果分桶太粗P99计算出来会和真实值偏差很大。错误率口径也值得说。我一开始只统计5xx状态码后来发现还应该把超时、熔断这类异常算进去。最简单可靠的统计口径还是HTTP状态码5xx是服务端错误4xx不算错误率那是用户输入问题。SLO如果定义成“错误率不超过5%”对应的可用性就是95%。如果你们团队对可用性要求是99.5%那一天的不可用时间大约是7.2分钟你自己算一下就会发现这个要求并不低。提示关于SLO我的建议是先用“错误率延迟”两个维度定义上线跑一个月之后再回头看往往比一开始拍脑袋定的合理得多。2.3 存储策略与数据保留Prometheus默认用本地存储数据保留多久是个需要提前想清楚的问题。我当时第一反应是“保留越久越好”后来算了一下磁盘预算发现真不能拍脑袋。大概估一下假设每秒采集1000个样本每个样本约16字节一天的数据量就是1000乘86400乘16约1.4GB。论坛项目规模不大但加上平台层指标样本量轻松到每秒几千个一天5到10GB很正常。如果直接设retention为30天磁盘压力就上来了查询也越来越慢。我最后选择保留7天热数据。原因是K8s环境本身变化很快7天的指标足够覆盖绝大多数故障复盘。如果需要更长时间的趋势分析建议走长期存储方案而不是把本地retention无限拉长。别指望Prometheus单机既能实时告警又能当数据仓库那不现实。3. Flask侧埋点不侵入业务代码的接法3.1 接入Prometheus客户端与配置Flask应用接入Prometheus最推荐的方式是用prometheus_flask_exporter这个库。它的好处是能自动采集每个路由的请求数、耗时、状态码不需要在每个接口里手动埋点。我在项目里是这样用的from flask import Flask from prometheus_flask_exporter import PrometheusMetrics app Flask(__name__) metrics PrometheusMetrics(app)启动后访问/metrics就能看到类似flask_http_request_duration_seconds_bucket这样的指标。每一个请求会自动带上method、route、status这些标签已经覆盖了QPS、延迟和错误率三大核心。对于论坛特有的业务指标比如在线用户数、登录次数我单独注册了自定义指标from prometheus_client import Gauge, Counter active_users Gauge(forum_active_users, 当前在线用户数) login_total Counter(forum_login_total, 累计登录成功次数)埋点的位置也有讲究。以登录次数为例不要在登录成功的业务方法里写一行login_total.inc()就完事那样一旦业务代码里提前return指标就漏了。我习惯放在Flask的after_request钩子里统一处理状态码和耗时采集再用业务逻辑判断是否计数。这样即使后续重构接口监控代码也不会跟着散落得到处都是。注意prometheus_flask_exporter默认暴露在/metrics路径采集间隔我设为15秒一次。实际测试下来每个请求多增加的开销不到1毫秒对论坛这种量级的应用完全可以忽略。3.2 暴露/metrics端点的安全考量/metrics端点一旦上K8s就绕不开安全这个问题。我见过不少项目为了省事把Ingress规则直接配成/转发到Service结果/metrics也跟着暴露到公网了。别人不仅能知道你论坛的访问量还能看到延迟分布式等于把底裤亮出来了。我的做法是/metrics只在集群内部可达。Service照常创建Prometheus通过集群内DNS去抓但Ingress上绝对不配置这条路径。如果你们的监控组件和业务不在同一个命名空间建议用NetworkPolicy限制来源只允许监控命名空间的Pod访问业务Pod的采集端口。另外节点上通过NodePort暴露时也要注意防火墙别把采集端口暴露到公网。这里有个容易被忽略的细节很多团队希望Grafana从办公室直接访问于是把Grafana的Ingress直接暴露这个没问题。但一定要给Grafana加一个基础鉴权别裸奔。我见过直接暴露Grafana、连密码都不设的那数据安全就是一张纸。4. Kubernetes侧部署与完整实操4.1 两种部署方案的对比K8s里部署Prometheus和Grafana有两条路线我都走过这里直接说结论。第一种是只部署单机Prometheus用Pod注解prometheus.io/scrape: true来做服务发现。优点是轻量适合临时验证。缺点是每次新增采集目标都要改注解没又无统一管理告警规则也散落在各处。第二种是用kube-prometheus-stack这个Helm包里自带Prometheus、Grafana、Alertmanager还有ServiceMonitor这个CRD。ServiceMonitor可以理解为一层“采集目标声明”只需要在YAML里声明要监控哪个ServicePrometheus Operator会动态生成采集配置。适合需要长期维护、上了规模就停不下来的项目。我最终选择了第二种原因很实际告警规则、Grafana面板、采集目标都可以用Git管理团队成员改起来有迹可循。部署命令很简单helm repo add prometheus-community https://prometheus-community.github.io/helm-charts helm repo update helm install monitoring prometheus-community/kube-prometheus-stack \ --namespace monitoring --create-namespace部署完等所有Pod变成RunningGrafana和Prometheus就已经在monitoring命名空间里了。默认Grafana服务是ClusterIP想访问就在Ingress里加一条或者临时kubectl port-forward出来看。4.2 ServiceMonitor的标签匹配与配置文件写法用kube-prometheus-stack之后Prometheus不会自动抓论坛Pod需要先建ServiceMonitor。这里最容易翻车的就是标签匹配。我写了一个最简版本apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: name: forum-monitor namespace: default spec: selector: matchLabels: app: forum endpoints: - port: http-metrics path: /metrics interval: 15s这里有两个关键点。第一selector.matchLabels匹配的是Service的标签不是Pod的标签。我一开始就在这里卡了很久一直给Pod打标签ServiceMonitor死活不生效。第二endpoints.port对应Service里的端口名必须是http-metrics端口类型是ClusterIP就行。如果端口名写成http或者metricsPrometheus会报“找不到端口”。如果你们不用Operator也可以回到第一种方案在Deployment的Pod模板里加注解annotations: prometheus.io/scrape: true prometheus.io/path: /metrics prometheus.io/port: 8000两种方式各有利弊但千万别混用。混用会出现两种情况要么同一个指标被重复采集Prometheus磁盘和内存白白浪费要么标签冲突查询结果翻倍。线上环境统一用ServiceMonitor管理annotation只留作临时调试。4.3 Grafana面板的查询与配置Prometheus部署好了Grafana面板才是打交道最多的地方。我这里直接给出论坛项目最常用的几条PromQL都是实际跑过的。每秒请求数也就是一般说的QPSsum(rate(forum_http_requests_total[5m]))P99延迟histogram_quantile(0.99, sum by(le) (rate(forum_http_request_duration_seconds_bucket[5m])) )5xx错误率sum(rate(forum_http_requests_total{status~5..}[5m])) / sum(rate(forum_http_requests_total[5m]))这几条查询建议建在同一个Dashboard里每条一个Panel别把所有指标塞进一张图。面板多了之后维护麻烦没有重点的图等于没有图。Grafana里有个常用技巧右上角时间范围选择器旁边可以调整刷新频率我习惯设为30秒。Prometheus拉取间隔是15秒这个刷新频率能保证你看到的图延迟不会太大也不至于把Grafana卡死。Grafana默认时区是UTC国内团队看着会很不习惯建议在设置里把时区改成Asia/Shanghai否则排查问题时每次都要自己加8小时还容易出误会。4.4 告警规则怎么配才不容易半夜误报告警是监控系统里最需要克制的一环。我当时配规则时也踩过坑刚开始一个接口一抖动就告警半夜手机响个不停。后来总结出两个原则一是所有告警都要加for持续条件二是要区分“服务真的不可用”和“服务只是抖了一下”。这里的核心PC核心是PrometheusRule的写法。我给的错误率告警是这样的apiVersion: monitoring.coreos.com/v1 kind: PrometheusRule metadata: name: forum-alerts namespace: default spec: groups: - name: forum-alerts rules: - alert: ForumHighErrorRate expr: | sum(rate(forum_http_requests_total{status~5..}[5m])) / sum(rate(forum_http_requests_total[5m])) 0.05 for: 5m labels: severity: critical annotations: summary: 论坛5xx错误率超过5%那个for: 5m意思是错误率持续超过阈值5分钟才触发告警。这样做的好处是偶发的一两个5xx不会打扰你但如果真的持续出问题5分钟后一定会响。另外还有一个非常容易踩的坑如果论坛的全部Pod都挂了这个告警反而不会触发因为完全没有新样本进来Prometheus里forum_http_requests_total这个序列就消失了表达式计算结果为空。所以要额外加一个“服务完全失联”的告警比如absent(up{appforum})这个表达式在目标全部down掉时返回1配合15分钟的for就能覆盖“服务挂了但没告警”的尴尬场景。5. 常见问题与排查技巧实录5.1 指标抓取不到的排查路径这个项目跑了两个多月我遇到最多的问题就是“Prometheus Targets页面显示down”。排查顺序很重要别一上来就怀疑Prometheus配置按下面这四步走效率会高很多。第一步先排除应用侧问题。用kubectl port-forward把Pod端口映射到本地然后直接访问/metrics确认Flask能吐指标。如果本地都访问不了问题在应用不在K8s。第二步确认Service端口名。用kubectl get svc看Service的端口名是不是和ServiceMonitor里的port字段一致。这个错误我在4.2节里就踩过端口名不匹配是最常见原因。第三步看Prometheus的Targets页面。如果状态是down点开后会显示具体错误比如连接超时、认证失败、404等等错误信息基本能定位问题。第四步检查标签选择器。可以用kubectl get svc -l appforum确认Service标签再用kubectl get servicemonitor -n default forum-monitor -o yaml对比选择器。标签这地方肉眼很难看出来建议复制出来对比别直接在命令行里扫。实操心得我后来养成了一个习惯新加采集目标时先看Targets页面再看Grafana最后才看告警。顺序反了很容易被一堆噪音带偏方向。5.2 Pod重启导致监控曲线断层论坛服务如果遇到OOM或者探针失败Pod重启后Prometheus里的Counter指标会从0重新开始累计。如果你直接用原始的forum_http_requests_total画图会看到一条突然跌到0的断崖非常吓人。解决办法很简单查询时永远用rate()或者increase()不要直接看Counter裸值。rate()会把累计值转换成每秒增量Pod重启的影响就不会在图上造成断崖。另外如果多个Pod副本频繁重建按instance维度去聚合会看到一条条断裂的曲线。这时候用sum()去掉instance维度只保留业务维度的标签看起来就平滑多了。这也是为什么我推荐在设计指标时就严格限制标签维度别把Instance这种动态标签作为主要分组条件。5.3 标签基数爆炸标签基数爆炸是Prometheus运维里的头号杀手。论坛项目里最容易犯的错误就是把user_id、session_id、IP地址这些高基数维度放进了指标标签。实测过一个场景在线用户数一万人如果不小心把user_id当标签那一万个用户在线就会产生一万条独立的指标序列Prometheus内存压力直线上升查询也越来越慢。正确的做法是标签维度控制在method、route、status这几个固定枚举值。需要按用户维度统计分析时走日志链路把日志丢到日志系统里再聚合不要让指标系统承担这种维度的数据量。指标是“聚合后的观测”不是明细数据。5.4 Grafana时间显示偏移Grafana时区问题看起来小实际害人不浅。默认情况下Grafana显示的是UTC时间对国内用户来说就是差8小时。我遇到过一次晚上十点看告警面板显示故障时间是第二天凌晨两点再看延迟曲线怎么都对不上折腾了半天才发现是时区问题。这个项目里我直接在Grafana设置里的Preferences改成Asia/Shanghai。改了之后所有面板和告警时间都按本地时间展示排查效率明显提升。另外Prometheus本身存储的是时间戳不关心时区改Grafana设置就够了不要去动Prometheus的时间配置。6. 最后分享一点监控落地的个人体会6.1 先把SLO想清楚再画图整套方案做完我最大的体会是监控不是“装个工具出几张图”而是“先想清楚什么东西不能挂再想怎么测它”。如果一开始就盲目抄别人面板图会很多但真出事的时候你根本不知道该看哪一张。这个论坛项目我把SLO收敛到了三条首页和发帖接口的可用性、P99延迟在2秒以内、5分钟错误率不超过5%。所有面板和告警都围绕这三条展开。这样每次看监控我只需要回答三个问题现在请求正常吗延迟是不是变大了有没有报错问题定位快很多。6.2 告警里带上面板链接最后分享一个很小的技巧在告警规则的注解里加上Grafana面板的链接。示例annotations: summary: 论坛5xx错误率超过5% dashboard: https://grafana.example.com/d/forum收到告警后直接点链接进面板不用再去翻哪个Dashboard对应哪个服务能省下很多排查时间。团队协作时这个习惯尤其重要。监控这种事前期多做一点点设计后期能省下一大堆“半夜爬起来看面板”的时间。希望这篇能把你的K8s服务从“裸奔”状态拉回到可视化的安全区。
RELATED

相关推荐

趣博思AI:博士论文写不下去,可能因为你一直在用本科的方式“写”它

趣博思AI:博士论文写不下去,可能因为你一直在用本科的方式“写”它

大家好。 今天想聊一个很多博士在读的朋友私下吐槽过、但很少公开讨论的问题:用本科阶段养成的写作习惯去对付博士论文,几乎是必然要翻车的。 本科论文的核心是“说清楚一件事”。你找到一个具体的问题,用一两个方法验证它,得出结…

📅 2026/10/13 21:59:08
Android RecyclerView缓存机制详解:四级缓存与列表性能优化实践

Android RecyclerView缓存机制详解:四级缓存与列表性能优化实践

做Android列表优化绕不开的一个硬核话题,就是RecyclerView的缓存机制。很多人都在用RecyclerView,也听说过ViewHolder复用,但一旦被问到“RecyclerView到底有几层缓存?”“为什么同一个item滑回来还会执行onBindViewHolder&#x…

📅 2026/10/13 21:59:08
出海SEO自动化实战:用OpenClaw搭建10倍效率流水线

出海SEO自动化实战:用OpenClaw搭建10倍效率流水线

1. 出海 SEO 的自动化困局与破局思路做海外 SEO 的人都有一个共同的痛:内容生产、关键词监控、外链机会挖掘、竞品动态追踪,这些活儿单拎出来都不难,但架不住量大、重复、琐碎。一个站点还好,手上同时跑三五个站点的时候&#xff…

📅 2026/10/13 21:59:08
MORE NEWS

更多资讯

📰

51单片机矩阵键盘与数码管动态显示:完整电路、代码与调试指南

矩阵键盘按键识别加数码管动态显示,这个组合在51单片机学习里属于“怎么绕都绕不开”的项目之一。很多人第一次看到“矩阵键盘”“数码管”“动态显示”这几个词凑在一起就有点慌,觉得既要读键盘又要刷新屏幕,逻辑会不会很乱。其实这个项目的…

📰

全球柯本气候区划SHP数据:GIS空间分析的气候语义锚点

简介:本资源为全球柯本气候区划矢量数据集,面向地理信息、环境科学、气候研究及城乡规划领域的科研人员、高校师生与GIS应用工程师,用于支撑气候空间分析、生态区划建模、农业适应性评估及气候变化教学实践。数据以标准Shapefile格式为核心&a…

📰

OP-TEE最小测试工程实战:TA/CA通信与QEMU部署避坑指南

简介:OP-TEE_my_test 是一份面向嵌入式安全开发者的实践型代码包,聚焦 ARM 架构下可信执行环境 OP-TEE 中自定义 Trusted Application(TA)与 Client Application(CA)的集成与验证,适合已具备 C …

📰

QMI8658国产六轴IMU驱动移植与姿态解算实战指南

简介:QMI8658驱动参考是一份面向嵌入式开发者的国产IMU(惯性测量单元)驱动资源,覆盖STM32与51单片机两种平台,以C语言实现底层硬件访问与数据读取。压缩包共2个文件,含STM32F103库文件及imualgo_axis9.lib、…

📰

Statsmodels一元OLS实战:从拟合到残差诊断的完整指南

1. 从一次"翻车"的拟合说起:为什么Statsmodels的OLS值得单独拎出来讲很多人第一次接触线性回归,都是从scikit-learn的LinearRegression开始的。几行代码,.fit()一下,.coef_和.intercept_就出来了,干净利落。…

📰

C++ 进程内解压实战:用 7z SDK 替代外部 7z.exe

简介:这份资源面向需要在 C 项目中集成 7-Zip 解压能力的开发者,尤其适合使用 Visual Studio 环境、希望直接调用 7z SDK 而非依赖外部命令行工具的中高级程序员。资源包共 488 个文件,以 186 个 .h 头文件与 136 个 .cpp 源文件为核心&#…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬