使用Prometheus监控Nginx Ingress网关

本文介绍如何使用Prometheus监控Nginx Ingress网关。

重要

20240901日起,该功能不再支持新增接入。您可以在接入中心页面检索Nginx或者Nginx Ingress Controller卡片尝试接入相关能力。

Nginx Ingress网关监控指标模型

对于已经接入的Nginx Ingress网关监控能力,您可以查看Nginx Ingress网关监控指标模型。

通用请求量指标(ingress_requests)

  • 指标名:ingress_requests

  • 指标类型:Gauge

  • 聚合周期:30s

  • 指标说明:表示一个聚合周期内在标签对应维度上被统计到的请求量数值。

  • 指标标签:

    标签名称

    说明

    示例值

    ingress_cluster

    Nginx Ingress控制器 (Controller)Deployment名称。

    nginx-ingress-controller

    ingress_cluster_instance

    Nginx Ingress控制器(Controller)Pod名称。

    nginx-ingress-controller-6fdbbc5856-pcxkz

    ingress_cluster_namespace

    Nginx Ingress控制器(Controller)所在命名空间。

    kube-system

    host

    请求头携带的Host名,可识别流量是从哪个Ingress路由规则进来的,如果是不合规的请求,该值为“_”。

    my.otel-demo.com

    service

    请求转发的后端服务名,如果是不合规的请求,该值为空。

    default-my-otel-demo-frontend-8080

    uri

    收敛后的URL路径。

    /(.+)

    method

    请求方法。

    GET

    status_code

    响应状态码。

    200

基于地理的请求量指标(ingress_geoip_requests)

  • 指标名:ingress_geoip_requests

  • 指标类型:Gauge

  • 聚合周期:30s

  • 指标说明:表示一个聚合周期内在标签对应维度上被统计到的请求量数值,标签中富化了地理信息。

  • 指标标签:

    标签名称

    说明

    示例值

    ingress_cluster

    Nginx Ingress控制器 (Controller)Deployment名称。

    nginx-ingress-controller

    ingress_cluster_instance

    Nginx Ingress控制器(Controller)Pod名称。

    nginx-ingress-controller-6fdbbc5856-pcxkz

    ingress_cluster_namespace

    Nginx Ingress控制器(Controller)所在命名空间。

    kube-system

    host

    请求头携带的Host名,可识别流量是从哪个Ingress路由规则进来的,如果是不合规的请求,该值为“_”。

    my.otel-demo.com

    service

    请求转发的后端服务名,如果是不合规的请求,该值为空。

    default-my-otel-demo-frontend-8080

    country_codeC

    请求来源IP所在国家编码。

    CN

    country_name

    请求来源IP所在国家名称。

    China

    region_name

    请求来源IP所在省份名称。

    Zhejiang

    city_name

    请求来源IP所在城市名称。

    Hangzhou

    timezone

    请求来源IP所在时区名称。

    Asia/Shanghai

    说明

    这里刻意裁剪了标签中URI、Method、Status Code等几个维度信息,该指标常见的使用场景中,请求路径的粒度至服务(Service)级即可满足,更细的粒度需要更昂贵的存储,且使用价值较低。

基于设备的请求量指标(ingress_user_agent_requests)

  • 指标名:ingress_user_agent_requests

  • 指标类型:Gauge

  • 聚合周期:30s

  • 指标说明:表示一个聚合周期内在标签对应维度上被统计到的请求量数值,标签中富化了设备信息。

  • 指标标签:

    标签名称

    说明

    示例值

    ingress_cluster

    Nginx Ingress控制器 (Controller)Deployment名称。

    nginx-ingress-controller

    ingress_cluster_instance

    Nginx Ingress控制器(Controller)Pod名称。

    nginx-ingress-controller-6fdbbc5856-pcxkz

    ingress_cluster_namespace

    Nginx Ingress控制器(Controller)所在命名空间。

    kube-system

    host

    请求头携带的Host名,可识别流量是从哪个Ingress路由规则进来的,如果是不合规的请求,该值为“_”。

    my.otel-demo.com

    service

    请求转发的后端服务名,如果是不合规的请求,该值为空。

    default-my-otel-demo-frontend-8080

    browser_family

    请求来源的浏览器类型,如果无法正确识别,该值为“<null>”。

    Chrome

    device_category

    请求来源的设备类型,如果无法正确识别,该值为“<null>”。

    mobile

    os_family

    请求来源的操作系统类型,如果无法正确识别,该值为“<null>”。

    iPhone

    说明

    这里刻意裁剪了标签中URI、Method、Status Code等几个维度信息,该指标常见的使用场景中,请求路径的粒度至服务(Service)级即可满足,更细的粒度需要更昂贵的存储,且使用价值较低。

请求延迟分桶指标(ingress_request_time)

  • 指标名:ingress_request_time

  • 指标类型:GaugeHistogram

  • 聚合周期:30s

  • 指标说明:表示一个聚合周期内在标签对应维度上被统计到的请求延迟分桶值。

  • 指标标签:

    标签名称

    说明

    示例值

    ingress_cluster

    Nginx Ingress控制器 (Controller)Deployment名称。

    nginx-ingress-controller

    ingress_cluster_instance

    Nginx Ingress控制器(Controller)Pod名称。

    nginx-ingress-controller-6fdbbc5856-pcxkz

    ingress_cluster_namespace

    Nginx Ingress控制器(Controller)所在命名空间。

    kube-system

    host

    请求头携带的Host名,可识别流量是从哪个Ingress路由规则进来的,如果是不合规的请求,该值为“_”。

    my.otel-demo.com

    service

    请求转发的后端服务名,如果是不合规的请求,该值为空。

    default-my-otel-demo-frontend-8080

    uri

    收敛后的URL路径。

    /(.+)

    method

    请求方法。

    GET

    status_code

    响应状态码。

    200

    说明

    请留意当前指标类型并非常见的Histogram类型:每个桶的数值为计数器模型;而GaugeHistogram 类型:每个桶的数值为当前聚合周期内观察到的一种“瞬时值”,因此如果要对这种指标进行分位数计算,参考表达式:histogram_quantile(0.95, sum(sum_over_time(ingress_request_time_bucket{...}[1m])) by (le))。

入流量指标(ingress_request_size)

  • 指标名:ingress_request_size

  • 指标类型:Gauge

  • 聚合周期:30s

  • 指标说明:表示一个聚合周期内在标签对应维度上被统计到的请求报文总字节数。

  • 指标标签:

    标签名称

    说明

    示例值

    ingress_cluster

    Nginx Ingress控制器 (Controller)Deployment名称。

    nginx-ingress-controller

    ingress_cluster_instance

    Nginx Ingress控制器(Controller)Pod名称。

    nginx-ingress-controller-6fdbbc5856-pcxkz

    ingress_cluster_namespace

    Nginx Ingress控制器(Controller)所在命名空间。

    kube-system

    host

    请求头携带的Host名,可识别流量是从哪个Ingress路由规则进来的,如果是不合规的请求,该值为“_”。

    my.otel-demo.com

    service

    请求转发的后端服务名,如果是不合规的请求,该值为空。

    default-my-otel-demo-frontend-8080

    说明

    这里刻意裁剪了标签中URI、Method、Status Code等几个维度信息,该指标常见的使用场景中,请求路径的粒度至服务(Service)级即可满足,更细的粒度需要更昂贵的存储,且使用价值较低。

出流量指标(ingress_response_size)

  • 指标名:ingress_response_size

  • 指标类型:Gauge

  • 聚合周期:30s

  • 指标说明:表示一个聚合周期内在标签对应维度上被统计到的响应报文总字节数,受Nginx Ingress实现限制,这里只能统计到响应体的字节数,不包含响应头的大小。

  • 指标标签:

    标签名称

    说明

    示例值

    ingress_cluster

    Nginx Ingress控制器 (Controller)Deployment名称。

    nginx-ingress-controller

    ingress_cluster_instance

    Nginx Ingress控制器(Controller)Pod名称。

    nginx-ingress-controller-6fdbbc5856-pcxkz

    ingress_cluster_namespace

    Nginx Ingress控制器(Controller)所在命名空间。

    kube-system

    host

    请求头携带的Host名,可识别流量是从哪个Ingress路由规则进来的,如果是不合规的请求,该值为“_”。

    my.otel-demo.com

    service

    请求转发的后端服务名,如果是不合规的请求,该值为空。

    default-my-otel-demo-frontend-8080

    说明

    这里刻意裁剪了标签中URI、Method、Status Code等几个维度信息,该指标常见的使用场景中,请求路径的粒度至服务(Service)级即可满足,更细的粒度需要更昂贵的存储,且使用价值较低。

Nginx Ingress网关监控进阶指南

编辑CR扩展URI收敛规则

由于访问日志中的请求路径这类明细数据是不可枚举的,直接放入Ingress请求指标的标签中将导致维度发散,存储成本急剧上升,甚至影响指标查询。

因此,实现Nginx Ingress网关监控的采集器会根据一组URI收敛规则对请求路径做精简,每个收敛规则由两部分组成:

  • 匹配表达式:一个正则表达式,如果当前URI匹配命中,则进行收敛,如:$/api/product/(.+)$。

  • 收敛后文本:将URI收敛为另一个具备可读性的字符串,如:ProductItem。

采集器会在第一次启用时扫描当前K8s集群的Ingress资源,并根据已有的路由规则提供的Path信息组装收敛规则。如果这部分配置无法满足您的分析、统计需要,请参照下列步骤进行扩展。

  1. 执行命令 kubectl edit ingresslog -narms-prom ingresslog-<您的采集配置名>,进入这个自定义资源的编辑窗口,如:kubectl edit ingresslog -narms-prom ingresslog-default-ingress-nginx

  2. 找到spec.logParser.reduceUri.allowList字段,对其进行扩展。比如,它默认可能只有两条收敛规则:

        reduceUri:
          allowList:
            - pattern: ^/(.+)$
              reduced: /(.+)
            - pattern: ^/$
              reduced: /
    说明

    allowList字段为一个数组对象,它的每一个元素即表示一个收敛规则,每个收敛规则下的pattern字段表示匹配表达式,reduced字段表示收敛后文本。

  3. 根据您实际的业务场景,可按如下参考示例进行改写:

        reduceUri:
          allowList:
            - pattern: ^/api/cart$
              reduced: /api/cart
            - pattern: ^/api/checkout$
              reduced: /api/checkout
            - pattern: ^/api/data$
              reduced: /api/data
            - pattern: ^/api/data/\?contextKeys=(.+)$
              reduced: /api/data/?contextKeys=(.+)
            - pattern: ^/api/products/(.+)$
              reduced: /api/products/(.+)
            - pattern: ^/api/recommendations/\?productIds=(.+)$
              reduced: /api/recommendations/?productIds=(.+)
            - pattern: ^/(.+)$
              reduced: /(.+)
            - pattern: ^/$
              reduced: /
    说明

    这里请按照顺序,将最短匹配路径的规则放到列表末,如:^/$。保存该配置后等待2~3分钟,即可在大盘看到根据URI收敛规则扩展后的进一步细化的指标数据。

扩展URI收敛规则会细化您的时间线,导致生成的指标数量上升,影响计费,请及时关注指标量的变化。

重要
  • 请您及时在本地备份URI收敛规则,因为在卸载当前Nginx Ingress网关监控能力后,对应的 IngressLog自定义资源默认会被删除。

  • 请不要改动IngressLog自定义资源中的其他配置,否则将导致Nginx Ingress网关监控无法正常工作。

参考:Nginx Ingress网关监控实现方式

基于Exporter指标

Kubernetes基于开源Nginx实现的Nginx Ingress发行版一大特色是其每个进程都扮演着Exporter角色,实现遵循Prometheus协议格式的自监控指标,如:

nginx_ingress_controller_requests{canary="",controller_class="k8s.io/ingress-nginx",controller_namespace="kube-system",controller_pod="nginx-ingress-controller-6fdbbc5856-pcxkz",host="my.otel-demo.com",ingress="my-otel-demo",method="GET",namespace="default",path="/",service="my-otel-demo-frontend",status="200"} 2.401964e+06
nginx_ingress_controller_requests{canary="",controller_class="k8s.io/ingress-nginx",controller_namespace="kube-system",controller_pod="nginx-ingress-controller-6fdbbc5856-pcxkz",host="my.otel-demo.com",ingress="my-otel-demo",method="GET",namespace="default",path="/",service="my-otel-demo-frontend",status="304"} 111
nginx_ingress_controller_requests{canary="",controller_class="k8s.io/ingress-nginx",controller_namespace="kube-system",controller_pod="nginx-ingress-controller-6fdbbc5856-pcxkz",host="my.otel-demo.com",ingress="my-otel-demo",method="GET",namespace="default",path="/",service="my-otel-demo-frontend",status="308"} 553545
nginx_ingress_controller_requests{canary="",controller_class="k8s.io/ingress-nginx",controller_namespace="kube-system",controller_pod="nginx-ingress-controller-6fdbbc5856-pcxkz",host="my.otel-demo.com",ingress="my-otel-demo",method="GET",namespace="default",path="/",service="my-otel-demo-frontend",status="404"} 55
nginx_ingress_controller_requests{canary="",controller_class="k8s.io/ingress-nginx",controller_namespace="kube-system",controller_pod="nginx-ingress-controller-6fdbbc5856-pcxkz",host="my.otel-demo.com",ingress="my-otel-demo",method="GET",namespace="default",path="/",service="my-otel-demo-frontend",status="499"} 2
nginx_ingress_controller_requests{canary="",controller_class="k8s.io/ingress-nginx",controller_namespace="kube-system",controller_pod="nginx-ingress-controller-6fdbbc5856-pcxkz",host="my.otel-demo.com",ingress="my-otel-demo",method="GET",namespace="default",path="/",service="my-otel-demo-frontend",status="500"} 64
nginx_ingress_controller_requests{canary="",controller_class="k8s.io/ingress-nginx",controller_namespace="kube-system",controller_pod="nginx-ingress-controller-6fdbbc5856-pcxkz",host="my.otel-demo.com",ingress="my-otel-demo",method="GET",namespace="default",path="/",service="my-otel-demo-frontendproxy",status="200"} 59599
nginx_ingress_controller_requests{canary="",controller_class="k8s.io/ingress-nginx",controller_namespace="kube-system",controller_pod="nginx-ingress-controller-6fdbbc5856-pcxkz",host="my.otel-demo.com",ingress="my-otel-demo",method="GET",namespace="default",path="/",service="my-otel-demo-frontendproxy",status="304"} 15
nginx_ingress_controller_requests{canary="",controller_class="k8s.io/ingress-nginx",controller_namespace="kube-system",controller_pod="nginx-ingress-controller-6fdbbc5856-pcxkz",host="my.otel-demo.com",ingress="my-otel-demo",method="GET",namespace="default",path="/",service="my-otel-demo-frontendproxy",status="308"} 15709
nginx_ingress_controller_requests{canary="",controller_class="k8s.io/ingress-nginx",controller_namespace="kube-system",controller_pod="nginx-ingress-controller-6fdbbc5856-pcxkz",host="my.otel-demo.com",ingress="my-otel-demo",method="GET",namespace="default",path="/",service="my-otel-demo-frontendproxy",status="403"} 235
nginx_ingress_controller_requests{canary="",controller_class="k8s.io/ingress-nginx",controller_namespace="kube-system",controller_pod="nginx-ingress-controller-6fdbbc5856-pcxkz",host="e-commerce.

使用开源或阿里云Prometheus Agent配合服务发现策略即可完成指标抓取与上报,通过PromQL实现分析、告警配置,或通过Grafana实现指标数据可视化展现。但这种监控实现方式在生产实践中存在以下几点问题。

  • 问题1:暴露太多不实用的Histogram指标

    对生产或测试集群中的Nginx Ingress进行一次抓取,会发现它所展现的指标清单中,Histogram类型指标占据非常多数量,Histogram指标一般以<metric_name>_bucket命名,配合<metric_name>_count和 <metric_name>_count一起使用。并且,其中包含常见分析不会使用的指标, 如:

    • nginx_ingress_controller_request_size_bucket:对每个请求体大小的分桶采样。

    • nginx_ingress_controller_bytes_sent_bucket:对每个响应体大小的分桶采样。

    默认情况下,如果不在Prometheusmetric_relabel_configs采集配置中执行drop操作,这些指标都会被抓取、上报,占用大量带宽与存储资源。

  • 问题2:Pull模式拉取太多不活跃的时间线

    当第一个问题遇到Prometheus AgentPull模式,情况变得更加糟糕,如果某个访问频率不那么高的微服务,历史只要发生过一次请求,那么与它有关的所有时间线会在Nginx Ingress暴露的指标清单中一直出现。在每个抓取周期中,被不停采集、上报,资源浪费加剧。

    这个现象背后的本质问题是一个计数器类型指标在观察周期内无变化时,如何避免上报。

  • 问题3:Ingress Path不可扩展、下钻

    一般体现HTTP流量的监控指标,URL Path是个很难处理的对象,如果直接将每个请求的URL Path加入到指标标签作为分析用途,将产生可怕的“维度爆炸”问题,可如果不加入这个信息,又无法实现指标细粒度的下钻分析。

    Nginx Ingress暴露的指标中,通过path标签记录Ingress规则中对应的请求路径字段,如“/(.+)”、“/login”、“/orders/(.+)”,避免了URL Path明细不可枚举问题。但当用户想实现更细粒度的下钻分析时,如希望看到“/users/(.+)/follower”、“/users/(.+)/followee”两个不同URL Pattern的统计数据,无法扩展,预置在Nginx Ingress实现中的这部分指标计算逻辑不可编程。

  • 问题4:缺少地理、设备信息的分析

    通常,网站系统的运维人员更关注请求来源侧信息,如:

    • 访问网站的用户分布在全国哪几个省市,其中, Top10的城市是哪些。

    • 用户通过移动端还是PC端访问网站,其中,移动端有多少是iOS机型,有多少是Android机型。

    这些数据也是Nginx Ingress自身暴露的指标中所未体现的。

  • 问题5:Kubernetes官方Grafana大盘布局不够聚焦

    虽然与Nginx Ingress暴露的指标无关,但用户一般会搭配Kubernetes官方提供的Grafana大盘进行数据可视化展现,所以也作为一个问题记录。如下图所示为Kubernetes官方提供的基于Nginx Ingress产出自监控指标的Grafana大盘。er

    前面提到,在针对入口流量的监控场景中,我们一般关注“RED”指标:请求速率(Rate)、请求失败数(Errors)、请求延迟(Duration)。但面对这张大盘首屏,如果站在分析请求流量的用户视角,它的布局或者信息结构显得不是那么合理,因此,提供一张聚焦、好用的大盘,也是实现Nginx Ingress网关监控很重要的部分。

基于访问日志统计

综上所述,基于Nginx Ingress原生的自监控指标在生产实践中存在诸多问题,阿里云Prometheus监控提供的Nginx Ingress网关监控则采用另一种基于访问日志统计的方式。

与开源版的Nginx类似,Nginx Ingress会往它的Ingress Controller Pod标准输出中打印每一条请求的日志,这里称为访问日志(Access Log)。

目前ACK默认的Nginx Ingress所打印的访问日志包含以下信息:

  • 请求时间

  • 请求来源IP

  • 请求方法,如:GET

  • 请求路径,如:/api/cart

  • 响应状态码

  • 请求体长度

  • 响应体长度

  • 请求耗时

  • 请求上游服务名,如:default-my-otel-demo-frontend-8080。

  • 请求User-Agent,如:Mozilla/5.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/3.0)。

  • 请求头携带的Host / 域名,如:my.otel-demo.com,这有助于确定流量是从哪个Ingress路由规则进来的。

基于这些信息,只需在K8s环境里部署一个采集器,通过预聚合计算方式即可实现入口流量RED指标统计,并通过可控的技术手段规避基于Exporter指标实施监控的几大问题:

  • 暴露太多不实用的Histogram指标:制作一组精益指标,裁剪不需要的指标项,满足大部分统计分析场景需要。

  • Pull模式拉取太多不活跃的时间线:抛弃计数器模型,使用滚动窗口计算Gauge指标,窗口间数据独立,使用RemoteWrite方式推送,避免历史堆积时间线的重复上报。

  • Ingress Path不可扩展、下钻:预聚合逻辑可使用CR配置扩展,通过建立新的匹配规则实现下钻。

  • 缺少地理、设备信息的分析:预聚合过程通过GeoIP、UserAgent分析等手段实现数据富化。

  • Kubernetes官方Grafana大盘布局不够聚焦:建立新的入口观测大盘,优化布局与信息结构,提升大盘的价值与体验。