Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

nginx proxyPass to prometheus using variable

I have the following nginx.conf

location /monitoring/prometheus/ {
  resolver 172.20.0.10 valid=5s;
  set $prometheusUrl http://prometheus.monitoring.svc.cluster.local:9090/;

  proxy_set_header Accept-Encoding "";
  proxy_pass $prometheusUrl;
  proxy_set_header Host $host;
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header X-Forwarded-Proto $scheme;

  sub_filter_types text/html;
  sub_filter_once off;
  sub_filter '="/' '="/monitoring/prometheus/';
  sub_filter 'var PATH_PREFIX = "";' 'var PATH_PREFIX = "/monitoring/prometheus";';

  rewrite ^/monitoring/prometheus/?$ /monitoring/prometheus/graph redirect;
  rewrite ^/monitoring/prometheus/(.*)$ /$1 break;
}

When I naviagte to https://myHost/monitoring/prometheus/graph I get redirected to /graph (https://myHost/graph)

When I don't use the variable and place the url directly to proxy_pass everything works as expected. I can navigate to https://myHost/monitoring/prometheus/graph and see prometheus.

location /monitoring/prometheus/ {
  resolver 172.20.0.10 valid=5s;

  proxy_set_header Accept-Encoding "";
  proxy_pass http://prometheus.monitoring.svc.cluster.local:9090/;
  proxy_set_header Host $host;
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header X-Forwarded-Proto $scheme;

  sub_filter_types text/html;
  sub_filter_once off;
  sub_filter '="/' '="/monitoring/prometheus/';
  sub_filter 'var PATH_PREFIX = "";' 'var PATH_PREFIX = "/monitoring/prometheus";';

  rewrite ^/monitoring/prometheus/?$ /monitoring/prometheus/graph redirect;
  rewrite ^/monitoring/prometheus/(.*)$ /$1 break;
}

Can anyone explain to me why using the variable leads to a different behaviour in terms of routing? I need to use variables to force nginx to resolve the dns name on each request.

like image 818
Yannic Klem Avatar asked Jul 19 '18 15:07

Yannic Klem


People also ask

What is proxy_set_header in Nginx?

Apart from proxy_pass, NGINX offers many other directives to handle requests to your server blocks. One of these directives is proxy_set_header, which lets you pass/rewrite headers to handle proxied requests. This tutorial can’t cover all headers, but you’ll go through some of the most common headers (Host, X-Forwarded-For, and X-Real-IP).

What is proxy_pass in Nginx?

A simple example A proxy_pass is usually used when there is an nginx instance that handles many things, and delegates some of those requests to other servers. Some examples are ingress in a Kubernetes cluster that spreads requests among the different microservices that are responsible for the specific locations.

How do I get metrics from nginx to Prometheus?

The first location block provides access to the Prometheus-formatted metrics. The second location block enables the NGINX Plus API, which generates the raw metrics and exposes them to Prometheus. Note: In production environments, we strongly recommend restricting access to the NGINX Plus API as described in our documentation.

How do I bypass Nginx's requirement for hosts to be available?

You can circumvent nginx's requirement for all hosts to be available at startup by using variables inside the proxy_pass directives. HOWEVER, for some unfathomable reason, if you do so, you require a dedicated resolver directive to resolve these paths. For Kubernetes, you can use kube-dns. kube-system here.


2 Answers

I just figured it out. As stated in the docs

When variables are used in proxy_pass:

location /name/ {
    proxy_pass http://127.0.0.1$request_uri;
}

In this case, if URI is specified in the directive, it is passed to the server as is, replacing the original request URI.

So the problem was that I specified a request uri in the variable (the trailing /). After removing this / everything worked fine.

Here the working config:

location /monitoring/prometheus/ {
  set $prometheusUrl http://prometheus.monitoring.svc.cluster.local:9090;

  proxy_set_header Accept-Encoding "";
  proxy_pass $prometheusUrl;
  proxy_redirect off;
  proxy_set_header Host $host;
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header X-Forwarded-Proto $scheme;

  sub_filter_types text/html;
  sub_filter_once off;
  sub_filter '="/' '="/monitoring/prometheus/';
  sub_filter 'var PATH_PREFIX = "";' 'var PATH_PREFIX = "/monitoring/prometheus";';

  rewrite ^/monitoring/prometheus/?$ /monitoring/prometheus/graph redirect;
  rewrite ^/monitoring/prometheus/(.*)$ /$1 break;
}
like image 165
Yannic Klem Avatar answered Oct 24 '22 01:10

Yannic Klem


I believe it's best to use the prometheus --web.external-url command line option.

This sandbox example shows a full working stack, complete with nginx config. https://github.com/prometheus-community/prometheus-playground/tree/master/nginx

Of note is the prometheus command section of the docker-compose.yml file.

command:
- --config.file=/etc/prometheus/prometheus.yml
- --web.route-prefix=/
- --web.external-url=http://example.com/prometheus
like image 1
Kevin Ortman Avatar answered Oct 24 '22 01:10

Kevin Ortman