零,缘起

1,在用grafana展示loki日志的时候,想到用可视化的方式来呈现更直观,于是网上查找,找到一篇《如何用Loki来绘制Ingress Nginx监控大屏》被复用多次,按照其过程实践引用了12559的面板,但效果与原文描述的不一致,可能是gf版本,或者插件版本变更等原因造成。尝试了几次终能正常显示部分数据。

一,用到的插件面板数据等

插件: worldmap panel(在线安装或手工下载安装)需要持久化grafana的插件目录,修改grafana.ini文件。显示地图上面的位置可以使用经纬度或geohash,此例用经纬度,依赖于geoip2中的数据库。内部或局域网地址解析出来的结果为空可忽略。

插件:geomap,只支持到国家地区。

nginx模块:geoip2(禁用geoip),geoip数据库,需要持久化/etc/nginx/geoip目录以保存数据。

二,步骤过程

此处使用的是ingress-nginx,nginx-ingress和其它的与此操作会有所不同。

1,ingress-nginx修改配置文件

配置文件最好写在一行内,在日志中呈现会比较容易看,json解析时可能会因为换行等问题失败。注意去掉#号及注释内容。

1.1,停用geoip启用geoip2 1.2,修改日志格式转为json,并指定要获取数据的字段,第4行 geoip_country_code,latitude,longitude,geoip_city_code其后对应的变量都是从geoip2中获取。 1.3,启用ingress真实IP转发 前三行

位于ingressnginx的命名空间中的configmap:ingress-nginx-controller-nginx,字段名称定义和面板查询中的字段名要保持一致。

apiVersion: v1

data:

  compute-full-forwarded-for: 'true' #ingress转发真实客户端IP

  forwarded-for-header: X-Forwarded-For #ingress转发真实客户端IP

  log-format-escape-json: 'true' #ingress转发真实客户端IP

  log-format-upstream: >-

    {"timestamp": "$time_iso8601", 

    "requestID": "$req_id",

    "proxyUpstreamName": "$proxy_upstream_name",

    "host": "$host",

    "proxyAlternativeUpstreamName": "$proxy_alternative_upstream_name",

    "upstreamStatus": "$upstream_status",

    "geoip_country_code": "$geoip2_city_country_code",  #从城市库中取国家

    "latitude": "$geoip2_latitude",     #从城市库中取经度

    "longitude": "$geoip2_longitude",     #从城市库中取纬度

    "geoip_city_code": "$geoip2_city",    #从城市库中取城市名拼音

    "upstreamAddr": "$upstream_addr",

    "request_time": "$request_time",

    "httpRequest":{

      "requestMethod": "$request_method",

      "requestUrl": "$request_uri", 

      "status": $status,

      "requestSize": "$request_length", 

      "responseSize": "$upstream_response_length",

      "userAgent": "$http_user_agent",

      "remote_addr": "$remote_addr",   #获取客户端IP,有些版本此值不对

      "referer": "$http_referer",

      "latency": "$upstream_response_time",

      "protocol":"$server_protocol"

    }

    }

  use-forwarded-headers: 'true'

  use-geoip: 'false'   #关闭geoip

  use-geoip2: 'true'   #启用geoip2

kind: ConfigMap

……

2,下载geoip2对应的三个库

放到nginx-ingress容器中的/etc/nginx/geoip下面。持久化该目录挂载后再改上面的配置,否则会提示找不到这些文件。

2.1,官网注册后下载:Thank You | MaxMind 

2.2,github上面下载(注意版本,建议去原仓库找最新版本)

https://github.com/P3TERX/GeoLite.mmdb/releases/download/2024.01.22/GeoLite2-ASN.mmdb

https://github.com/P3TERX/GeoLite.mmdb/releases/download/2024.01.22/GeoLite2-City.mmdb

https://github.com/P3TERX/GeoLite.mmdb/releases/download/2024.01.22/GeoLite2-Country.mmdb

GeoLite2-ASN.mmdb 区域? GeoLite2-City.mmdb  城市 GeoLite2-Country.mmdb 国家

2.3,修改完后观察ingress日志,是否有错误如找不到对应的变量,找不到数据库文件等。在运行正常后从公网访问该服务器查看访问日志中是否正确携带出来地区,经纬度信息,如果有表示配置完成。

3,loki收集ingress-nginx日志略

4,grafana安装及面板安装

grafana安装略

4.1,安装面板并持久化

持久化/var/lib/grafana/plugins目录(路径根据自己实际情况)

4.1.1,手工下载安装:下载worldmap panel插件手工放入到/var/lib/grafana/plugins/下面并解压,保持插件文件目录名并做成持久化挂载。目前下载到的是1.0.6 注意事项:1.0.6版本和grafana10有些冲突,会显示过时API,貌似不影响使用。

4.1.2,grafana在线安装,网络正常能访问到的可使用,默认安装应该是新版本

grafana-cli plugins install grafana-worldmap-panel

4.2,修改插件显示地图

因worldmap插件中原来的地图地址无法访问到所以需要修改,改worldmap module.js和module.js.map文件中的默认瓦片地图下载地址,指令没测试过,手工修改替换文件覆盖也可。

sed -i 's/https:\/\/cartodb-basemaps{s}.global.ssl.fastly.net\/light_all\/{z}\/{x}\/{y}.png/http:\/\/{s}.basemaps.cartocdn.com\/light_all\/{z}\/{x}\/{y}.png/' \

module.js \

module.js.map

sed -i 's/https:\/\/cartodb-basemaps-{s}.global.ssl.fastly.net\/dark_all\/{z}\/{x}\/{y}.png/http:\/\/{s}.basemaps.cartocdn.com\/dark_all\/{z}\/{x}\/{y}.png/'  \

module.js \

module.js.map 

4.3,未签名问题处理1

修改后需要删除原始签名信息 MANIFEST.txt 将其改名或删除,否则会在grafana重启后报签名不符。

4.4,未签名问题处理2

修改grafana.ini配置文件或添加环境变量以允许加载没有签名的面板:

grafana.ini中的位置

[plugins]

allow_loading_unsigned_plugins = grafana-worldmap-panel

或修改yaml或docker的环境变量配置(与INI字段对应关系)。

- name: GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS

  value: grafana-worldmap-panel

重启grafana启动日志中出现:Permitting unsigned plugin. This is not recommended即正常。

5,grafana中添加查询面板

添加loki数据源略5.1,logql示例:

 从ingress中过滤为json并排除错误解析,并格式化只要几个主要字段,根据城市,经纬度字段汇总。

sum by (geoip_city_code,latitude,longitude) (count_over_time({job=~"ingress-nginx/ingress-nginx-controller-nginx"} |json | __error__="" | line_format "{{.geoip_city_code}}  {{.latitude}} {{.longitude}} " [$__interval]))

5.2,数据转化处理

Transform将上述查询的结果从series转为row也就是table的格式。因为worldmap panel面板支持的几种格式中,只有这种和日志中获取到的经纬度比较好对应。其它如geohash等都不好处理。

transform在8.x和10.x的面板上面添加了也会无法编辑。于是复制面板中自带的json,这样就可以在table view视图中查看到查询结果便于调整。以下是转换的json,可直接复制替换到transformations位置使用。

注意最后的逗号,如果不是在最后位置就要添加。在最后可不添加。

"transformations": [

    {

      "id": "reduce",

      "options": {

        "reducers": [

          "sum"

        ],

        "labelsToFields": true  #显示字段出来便于查看

      }

    }

  ],

使用table view查看查询出来的数据和字段,和面板配置字段对应。

5.3,面板数据来源和字段映射配置

来源配置为table,取合字段设置为total;

字段映射,来源于logql查询的字段

字段映射配置 Map Data Options Location Data:    table Aggregation:  total

Field Mapping 字段映射 Table Query Format: coordinates #数据格式

Location Name Field: geoip_city_code  Metric Field: Total #名称 Latitude Field: latitude  #纬度 Longitude Field: longitude #经度

5.4,字段映射和json解析二级列表展开的情况

logql用json解析json内容时,出现有第二层级内容时,会将其展开,用上级名称_二级名称的形式体现。

所以在面板中可能存在用字段名取不到第二层值的情况,就需要在前面加上上一级名称。如:

httpRequest_status->对应原json中的 httpRequest: {status: 200}

6,完成

正常情况下如图所示结果:颜色,样式等细节再调整,还有可以汉化地图文字的没有尝试。

(没有图了图片违规,可能是地图插件的地图源里面有内容不符合要求)自己想象吧。

grafana面板ID:12559

好文链接

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。