# Prometheus 在 Nginx 反向代理下的路由与路径配置 ## 背景 公司小组一个端到端的容器化测试环境,位于不同的子路径下,通过 Nginx 代理: * 比如用户 A 在 `/a/` 下:`/a/prometheus/` * 比如用户 B 在 `/b/` 下:`/b/prometheus/` 想要达到的效果除上述不同子路径的区别下,需要在容器内部没有这个区分:即容器内可直接访问 `prometheus:9090` 请求 Prometheus。 TLDR: 如果你也有这样的需求,太长不想看可直接跳到最后的总结。 ## Prometheus 的路径和路由配置 从 Prometheus 的命令行参数中可以看到其提供了以下两个选项来控制路径与路由配置: * **`--web.external-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=`** 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/`。 下面来实测看看: ```sh $ docker run -it --rm -p 9090:9090 prom/prometheus --config.file /etc/prometheus/prometheus.yml --web.route-prefix=/ --web.external-url=/a/prometheus/ ``` 注:为方便说明,下面以 `nginx` 和 `prometheus` 分别代表这两个服务。 API 可访问: ```sh $ curl -s prometheus:9090/api/v1/query | cut -c-50 {"status":"error","errorType":"bad_data","error":" ``` 访问首页时被重定向到带前缀的路径下了: ```sh $ 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 Found. ``` 但是如果尝试访问这个重定向后的地址,会报错找不到: ```sh $ curl -s prometheus:9090/a/prometheus/graph 404 page not found ``` 是不是挺奇怪的?如果我直接请求不带前缀的路径,却能找到: ```sh $ curl -s prometheus:9090/graph | cut -c-50 ` 说明中“更深层次”的含义: **这个选项是用于控制反射代理前的路径,而 Prometheus 本身不需要这个路径,你应该在 nginx 中重写路径去掉。** ## 经 nginx 代理测试 Nginx 的配置: ```nginx location /a/prometheus/ { proxy_pass http://prometheus:9090; } ``` 尝试访问一下,意料之中不行,因为还没有重写路径: ```sh $ curl nginx:8080/a/prometheus/ 404 page not found ``` 尝试重写一下路径: ```nginx location /a/prometheus/ { rewrite ^/a/prometheus(.*)$ $1 break; proxy_pass http://prometheus:9090; } ``` 上面这么 `rewrite` 规则大致含义:将请求 `/a/prometheus/xxx` 重写成 `/xxx` 后再传递给被代理的服务器。 于是,Prometheus 接收到了不带前缀的请求。并且,发现可以了: ```sh $ curl nginx:8080/a/prometheus/ Found. $ curl -s nginx:8080/a/prometheus/graph | cut -c-50