Prometheus 在 Nginx 反向代理下的路由与路径配置

陪她去流浪 桃子 2022年03月12日 编辑 阅读次数:7622

背景

公司小组一个端到端的容器化测试环境,位于不同的子路径下,通过 Nginx 代理:

  • 比如用户 A 在 /a/ 下:/a/prometheus/
  • 比如用户 B 在 /b/ 下:/b/prometheus/

想要达到的效果除上述不同子路径的区别下,需要在容器内部没有这个区分:即容器内可直接访问 prometheus:9090 请求 Prometheus。

TLDR: 如果你也有这样的需求,太长不想看可直接跳到最后的总结。

Prometheus 的路径和路由配置

从 Prometheus 的命令行参数中可以看到其提供了以下两个选项来控制路径与路由配置:

  • --web.external-url=<URL>

    The URL under which Prometheus is externally reachable (for example, if Prometheus is served via a reverse proxy). Used for generating relative and absolute links back to Prometheus itself. If the URL has a path portion, it will be used to prefix all HTTP endpoints served by Prometheus. If omitted, relevant URL components will be derived automatically.

    这是 Prometheus 外部可达的地址(URL)(经反向代理后)。

    用于(在页面上或请求中)生成相对或绝对链接。

  • --web.route-prefix=<path>

    Prefix for the internal routes of web endpoints. Defaults to path of --web.external-url.

    Prometheus 内部 Web 请求的路由前缀。

    默认为 --web.external-url 中的路径。

直接访问测试

为了在容器内可直达 Prometheus 的 API。所以 --web.route-prefix 应该配置为 /

而对于 --web.external-url,由于其控制的是外部可访问的路径,以及页面中的相对链接生成。 所以这个地址应该配置成文章开始提到的路径(以用户 A 为例):/a/prometheus/

下面来实测看看:

1
$ docker run -it --rm -p 9090:9090 prom/prometheus --config.file /etc/prometheus/prometheus.yml --web.route-prefix=/ --web.external-url=/a/prometheus/

注:为方便说明,下面以 nginxprometheus 分别代表这两个服务。

API 可访问:

1
2
$ curl -s prometheus:9090/api/v1/query | cut -c-50
{"status":"error","errorType":"bad_data","error":"

访问首页时被重定向到带前缀的路径下了:

1
2
3
4
5
6
7
8
$ curl -si prometheus:9090
HTTP/1.1 302 Found
Content-Type: text/html; charset=utf-8
Location: /a/prometheus/graph
Date: Sat, 12 Mar 2022 09:26:58 GMT
Content-Length: 42

<a href="/a/prometheus/graph">Found</a>.

但是如果尝试访问这个重定向后的地址,会报错找不到:

1
2
$ curl -s prometheus:9090/a/prometheus/graph
404 page not found

是不是挺奇怪的?如果我直接请求不带前缀的路径,却能找到:

1
2
$ curl -s prometheus:9090/graph | cut -c-50
<!doctype html><html lang="en"><head><meta charset

所以应了 --web.external-url=<URL> 说明中“更深层次”的含义: 这个选项是用于控制反射代理前的路径,而 Prometheus 本身不需要这个路径,你应该在 nginx 中重写路径去掉。

经 nginx 代理测试

Nginx 的配置:

1
2
3
location /a/prometheus/ {
  proxy_pass http://prometheus:9090;
}

尝试访问一下,意料之中不行,因为还没有重写路径:

1
2
$ curl nginx:8080/a/prometheus/
404 page not found

尝试重写一下路径:

1
2
3
4
location /a/prometheus/ {
  rewrite ^/a/prometheus(.*)$ $1 break;
  proxy_pass http://prometheus:9090;
}

上面这么 rewrite 规则大致含义:将请求 /a/prometheus/xxx 重写成 /xxx 后再传递给被代理的服务器。

于是,Prometheus 接收到了不带前缀的请求。并且,发现可以了:

1
2
3
4
5
$ curl nginx:8080/a/prometheus/
<a href="/a/prometheus/graph">Found</a>.

$ curl -s nginx:8080/a/prometheus/graph | cut -c-50
<!doctype html><html lang="en"><head><meta charset

经查询 nginx 的 proxy_pass 文档发现:

  • 如果 proxy_pass不带 URL,则会直接把 nginx 接收的到原始 URL 原封不动地传递给被代理的服务器;
  • 如果 proxy_pass带有 URL,则会把 location 中的前缀去掉后追加到这个 URL 后再代理过去;

这样一来,上面的 nginx 配置可以再简化成下面这样:

1
2
3
location /a/prometheus/ {
  proxy_pass http://prometheus:9090/;
}

注意最后有一个 /

总结

  • Prometheus 的配置:

    • --web.external-url=/你的/前缀/
    • --web.route-prefix=/
  • Nginx 的配置:

    1
    2
    3
    4
    
    location /你的/前缀/ {
      # 注意后面的 / 。
      proxy_pass http://proemtheus:9090/;
    }
    

另外,PushGateway 和 Prometheus 有完全类似的配置。

希望可以帮到你。

标签:nginx · Prometheus