准备知识
Ingress-nginx-controller 实际上是ingress controller 的一种实现方案,而且是k8s官方维护的项目。当然也有其他实现方案,比如Traefik,Voyager,F5 BIG-IP Controller 等。他们的作用都是为了将k8s内部应用暴露给外界使用。如官方文档所示:
internet
|
[ Ingress ]
--|-----|--
[ Services ]
通过名字就可以看出ingress-nginx-controller 实际上就是ngixn,该组件的配置也与nginx一致,可以查看一下配置说明 。了解ngixn的都知道,通过access.log 可以获得当前应用的访问量,谁访问的,请求方法是什么,延迟是多少等重要信息,对于分析应用本身的行为,排查应用问题原因有很大的帮助。本文结合实际应用来讲解如何利用ingress-nginx-controller 的access.log 日志来监控应用,并实现一个prometheus 的exporter。
遇到问题
调研过ingress-nginx-controller项目的同学应该知道,ingress-nginx已经帮用户实现了一个exporter,但是需要prometheus 也是k8s的应用。一般生产环境中,并不会是监控组件(prometheus)依赖监控项(k8s),正所谓鸡蛋不能放到一个篮子里,因此prometheus独立于k8s集群单独运行。
prometheus部署在k8s 集群外部就导致 prometheus 配置较为复杂,而且还可能暴露证书等重要信息,因此很容易想到通过实现prometheus exporter来直接把指标暴露给prometheus。前期实现的方案很简单,就是通过程序tail access.log 文件,将指标解析好,写入到exporter,来一条日志写一个指标。一开始应用比较少的时候,prometheus 还可以承受,当应用越来越多,指标自然也会增长,而access.log 本身的日志量就很大,最终导致prometheus查询24小时,甚至12小时的指标图表时 OOM,因此逐条将access.log 内解析的指标写到prometheus是行不通的。
另外exporter本身并没有打时间戳,而是当prometheus 主动拉取的那一刻打上时间戳,这就导致可能会收到重复数据,如果想获得应用每秒的访问量,得到的并不是准确值。用户对应用的访问量,服务本身的响应延时等指标对于应用的后期维护作用不言而喻,因此要尽量保证准确性。
解决方案
最终实现方案是exporter对access.log 内的指标先在一个周期内聚合比如30s,并打上时间戳(时间戳为周期的最后一秒),最后prometheus拉取指标都不会重复。首先 exporter本身是支持给指标打时间戳的,但是目前提供的demo项目并不多,通过查看prometheus 源码可以知道调用 NewMetricWithTimestamp()方法即可返回一个带时间戳的指标。废话不多说,核心代码如下,例子中紧紧统计了应用访问量: