概述
通常服务部署成功之后,对服务进行实时监控是一件很正常的事情,之前只用过别人搭建好的grafana。这篇博客中我自己来尝试完成这一整套流程。
首先对环境进行部署,然后编写一个简单的代码来在go程序中使用prometheus监控数据,通过prometheus服务端的采集,然后在grafana上进行展示。
prometheus和grafana部署
关于rancher的部署,在我之前的博客中已经写过了rancher+k3s的高可用部署以及k3s集群的导入
对于prometheus和grafana,这两个东西不使用容器,直接部署很简单,下载下来配置一下运行就好了。我这里环境中既然有rancher,那就直接使用rancher来部署,这样方便我进行服务管理。
方法一,在rancher的应用商店中部署
首先进入到应用商店中,选择启动:
在其中找到prometheus:
点进去进行部署前的设置,我这里首先改了一下名称,选择了一下命名空间:
我这里选择不使用默认镜像,因为我使用默认镜像后,发现默认镜像的prometheus版本太低了,根本不支持basic auth
,安全性没有任何保证,所以这里把prometheus改成了官方的最新镜像:
这里为prometheus启用了ingress,这个比直接端口映射方便,不过图中的.xip.io这个域名网站已经不能用了,后面换一下就好:
然后我关闭了我不需要的alert和push功能,开启了需要的grafana,同样为grafana启用了ingress:
点击部署之后,可以在应用商店中找到它:
点进这个应用,首先去改一下ingress规则,将.xip.io
这个域名换成.nip.io
:
现在就可以通过域名直接访问到这两个服务了:
到这里为止,服务部署已经完毕。
方法二,使用rancher直接部署
本来我用应用商店部署,发现用不了basic auth
,当时没有发现可以修改docker版本,于是重新部署了一个最新版本的prometheus,整半天才加上basic auth
。
首先,直接在工作负载中,选择部署服务:
改一下名字,选一下镜像和命名空间(新创建也行),然后直接部署即可:
这时服务已经启动了,但是没有向外暴露服务,所以我们是访问不了的。
手动添加一下ingress规则,选择负载均衡->添加规则,修改规则名,选择命名空间,工作负载,内部服务端口(prometheus默认是9090端口):
同样的,还是要修改一下域名,将.xip.io
这个域名换成.nip.io
:
这样就出现了访问端口80,可以直接点击它来访问到prometheus服务:
到这里直接部署已经完成。
应用商店中prometheus启用基本认证
在上面rancher部署完毕之后,可以发现现在prometheus是没有启用basic auth
的。
通过官方文档SECURING PROMETHEUS API AND UI ENDPOINTS USING BASIC AUTH可以知道,最新的prometheus是可以直接支持认证的,而不是像以前一样要加个反向代理来曲线救国。
依据官方文档所述,现在可以额外添加一个web.yml
文件来指定连接时的用户名和账号,格式如下:
1 | basic_auth_users: |
这里的密码是test,经过bcrypt算法hash之后得到$2b$12$hNf2lSsxfm0.i4a.1kVpSOVyBCfIB51VRjgBUyv6kdnyTlgWj81Ay
。
因为这个文件需要我们自己生成,也就意味着这个密码的hash过程得我们自己实现。
这里提供一个golang生成bcrypt进行hash之后的密码的简单代码:
1 | package main |
在运行prometheus时,通过指定这个文件来启用认证:
1 | prometheus --config.file=/etc/prometheus/prometheus.yml --web.config.file=/etc/prometheus/web.yml |
当然现在我们是通过rancher来启动得prometheus,所以需要通过修改rancher的配置来让prometheus容器启动时,运行如上命令。
应用商店中prometheus启用基本认证
首先,还是同样的在应用商店中对prometheus进行管理,添加配置映射,在其中加入我们的web-auth.yml
:
然后,配置一下容器启动时命令,选择工作负载,在启动对入口命令进行修改:
上面的命令(CMD)中本来是如下内容:
1 | --storage.tsdb.retention.time=15d --config.file=/etc/config/prometheus.yml --storage.tsdb.path=/data --web.console.libraries=/etc/prometheus/console_libraries --web.console.templates=/etc/prometheus/consoles --web.enable-lifecycle |
添加--web.config.file=/etc/config/web-auth.yml
到其中,(注意这里的配置文件是prometheus-server-configmap-reload
这个服务来映射的,在/etc/config/
路径下,而默认配置文件在/etc/prometheus/
路径下):
1 | --storage.tsdb.retention.time=15d --config.file=/etc/config/prometheus.yml --web.config.file=/etc/config/web-auth.yml --storage.tsdb.path=/data --web.console.libraries=/etc/prometheus/console_libraries --web.console.templates=/etc/prometheus/consoles --web.enable-lifecycle |
点击升级之后,容器开始重启,但是这里我发现重启失败了,原因是健康检查没有通过,因为其默认使用的是http认证,但是启用认证之后,普通的http请求会直接403,所以健康检查无法通过。这里改成端口检查即可:
修改之后,prometheus服务健康启动,查看界面,可以发现需要输入密码了:
输入刚才所设置的用户名和密码,即可登录成功。
直接部署的prometheus启用基本认证
使用rancher直接部署的prometheus,由于是单个的独立服务,并没有其它的服务来辅助进行配置文件的管理,所以每次重新部署服务,之前容器都会被摧毁。
所以这里需要我们自己来对配置文件进行管理,最开始我试用了主机目录映射的方法,然后发现两个k3s节点有一个有这个目录,有一个没有,这样就有可能部署会失败。于是换用了挂载pvc卷的方法,pv卷底层选择了nfs。
首先选择一台机器192.168.88.60
来安装nfs:
1 | sudo yum install -y nfs-utils |
修改nfs配置文件:
1 | vim /etc/exports |
因为nfs没有太多的安全性可以配置,所以这里配置时指定了能够访问的ip以及权限,这两个ip就是两个k3s节点。这里将/home/lrm/rancher-pv
目录进行分享。
启动nfs:
1 | sudo systemctl start nfs |
另外的一些常用命令:
1 | // 查看当前向外提供的挂载目录 |
然后就可以到rancher上配置pv卷。选择集群(但是不选择具体项目),可以看到存储,选择其中的持久卷,然后点击添加pv:
修改持久卷名字,选择卷插件NFS Share
,填写容量大小,路径是我们刚才分享的目录/home/lrm/rancher-pv
,分享的机器192.168.88.60
:
添加完成pv卷后,来到刚才部署好的long-prometheus
这个服务中进行升级,选择数据卷->添加卷->添加新的pvc,然后选择使用现有的持久卷,也就是刚才创建的pv卷long-nfs-pv
:
我这里将它映射到容器内路径/etc/prometheus/myconfig
下:
添加好数据卷后,点击升级,服务会重启。完成之后,进入容器内命令行,可以看到目录已经成功映射进来:
剩下的事情就很简单了,在这个目录中编写好我们的配置文件prometheus.yml
和web-auth.yml
,然后配置容器启动时命令,指定prometheus使用这两个配置文件启动即可:
我这里将启动命令配置为:
1 | --config.file=/etc/prometheus/myconfig/prometheus/prometheus.yml --web.config.file=/etc/prometheus/myconfig/prometheus/web-auth.yml |
服务重启之后,prometheus的基本认证就成功启用了。
使用prometheus监控go程序
一个简单的测试程序编写如下:
1 | package main |
这里模拟了三种通常使用的统计类型Gauge,counter和Histogram,监听在192.168.88.60的12345端口,修改prometheus配置,让它从此进程中抓取数据,修改prometheus.yml配置文件:
1 | scrape_configs: |
在scrape_configs
加入上面的配置,在prometheus的界面上可以看到新的target已经加入:
可以在prometheus界面上查询到采集的值,以及看到简单的图形:
到这里就完成了prometheus对go程序监控数据的采集。
使用grafana展示监控数据
首先在grafana中添加datasource,将prometheus服务器添加进来。添加datasource->选择prometheus,填写prometheus服务器的url,打勾basic auth
,填写prometheus的用户名密码:
点击save&test
,出现Data source is working
表明添加数据源成功。
下一步,添加面板。
很多时候我们使用prometheus监控的都是一些常用服务,对于这些服务,我们可以直接到grafana的官方中找到别人分享的面板来直接使用https://grafana.com/grafana/dashboards,然后直接import它的编号或者url就可以了:
这里由于是我们自己写的程序,所以并没有现成的面板可以用,那么就只能自己创建了,选择New dashboard
,右上+号创建新panel,然后可以对新panel进行编辑:
上面的go程序中模拟采集了5个数据:
- promTestUsageFunc:模拟cpu实时占用。
- promTestUsage:同上。
- promTestCounter:模拟cpu累计占用时间长度。
- promTestMemUsage:模拟Memory实时占用大小。
- promTestHist:模拟http请求响应时长统计。
首先对promTestUsageFunc数据(promTestUsage数据一样的)进行展示,因为它是cpu实时占用数据,所以编写的promQL很简单:
promQL语句为:
1 | long_test_usage_func{program_name="test"} * 100 |
也就是直接查询出来,再乘上100变成百分数即可。这里的program_name="test"
是上面go代码里面写的,对于同样的代码的不同进程,可以使用不同的标签来进行区分,例如test1
、test2
等。
显示效果:
promTestCounter数据模拟的是cpu累计占用时长,这种数据在统计单个程序的cpu占用时很常见。它是一个无限递增的值,稍微进行一下处理,就可以把它变为cpu占用率:
promQL语句为:
1 | rate(long_test_counter{program_name="test"}[1m]) * 100 |
这里的[1m]
就是查询一分钟之内的所有long_test_counter
数据:
1 | 1111 @1632453001.599 |
前面就是long_test_counter
的值,后面则是时间点,我这里每10秒采集一次,所以正好6个值。
rate函数则会去计算变化率,其实也就是每秒钟的变化量,官网文档可以参考FUNCTIONS。
显示效果:
promTestMemUsage数据模拟的是实时的内存占用,这个值一般我们也不看它的变化情况,就单纯看一下当前占用了多少:
上面调了一下背景颜色,用4和8作为界限,也就是4一下背景为绿色,4到8之间背景为橙色,8以上为红色。
promQL语句为:
1 | long_test_mem_usage{program_name="test"} |
显示效果:
promTestHist数据模拟http请求响应时长,一般情况我们会关心分位数,例如P95,也就是95%的请求延迟在多少以下:
promQL语句为:
1 | histogram_quantile(0.95, sum(rate(long_test_hist_bucket{program_name="test"}[60s])) by (le)) |
这里使用了histogram_quantile
函数来计算分位数,le
就是每个桶的边界值,是自带的标签。
显示效果:
也许我们不想看分位数,就想看到当前的延迟分布情况,这个时候可以使用grafana的heatmap
来实现:
promQL语句为:
1 | sum(increase(long_test_hist_bucket{program_name="test"}[2m])) by (le) |
很简单的统计了一下增量,但是需要调整一下Legend
和Format
,显示效果如下:
可以通过颜色深浅来看出当前请求大部分落在了哪个范围之中。
最终效果:
添加变量来方便切换数据源
上面的promQL语句中,我们将program_name="test"
这句话给写死了,但是如果我们启动了一个test2
程序,岂不是还得去改语句?
使用变量就可以不需要再去修改语句:
然后修改一下promQL语句,将之前写死的test换成$program_name
:
1 | long_test_usage_func{program_name="$program_name"} * 100 |
这样在界面上就可以看到这个变量值:
修改这个变量值,就可以看到来自其它程序的统计情况,例如这里我又启动了一个test1
程序(当然prometheus也需要修改抓取配置):
2021-09-26问题:修改promethues.yml配置文件后,服务没有自动重新加载
针对应用商店部署的promethues应用,它带有一个prometheus-server-configmap-reload
服务来对prometheus配置文件进行管理,可以看到它启动时的命令行参数--volume-dir=/etc/config --webhook-url=http://127.0.0.1:9090/-/reload
,这里的volume-dir
是配置文件映射到prometheus容器内的路径,而webhook-url
,则是当它发现配置文件有修改时,会访问这个url来触发prometheus服务重新加载配置文件。
思考一下就知道为什么重新加载配置文件失败了,因为这里给prometheus服务添加了http basic auth
,所有的http请求都要带有认证信息才行。
按照http basic auth
的规则,修改一下url为--webhook-url=http://user:password@127.0.0.1:9090/-/reload
,即可。
参考
PromQl中的的rate与irate内部是如何计算的(源码与计算)