You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
For current Prometheus, it seems that the metrics address to be pulled must be a valid TCP hostname. If Prometheus supports to pull from HTTP over Unix socket, each metrics server won't use a dedicated port to serve for Prometheus.
And I found the related comment:
If my idea does not work, we should still scrape using HTTP (maybe allow unix socket on linux) because changing this would change a lot of the semantics around scraping. Originally posted by @roidelapluie in #9706 (comment)
Reacted by Marcus Wichelmann, D-Spirits, june ✿, Joe Grund, Yumekui, h7x4, Brian Picciano, Todd, Mynacol, Rob and 36 more
This interests me as well. In my case I am tunneling exporters via SSH to the machine running Prometheus, so it makes more sense to use UNIX sockets than ports for each machine.
HTTP over UNIX socket should work fine and very likely most of the underlying connection code won't care about the difference. I will take a look next week and possibly begin drafting a pull.
Hi @DaAwesomeP, I'm curious about how exactly HTTP over Unix socket would work in Prometheus. Would it be Unix+HTTP in the URL? Additionally, how would HTTPS work in this case? It seems to raise a lot of questions. Maybe @rfratto can provide some insights as well. Thanks!
A UNIX socket can almost always be treated functionally the same as any other TCP socket, minus the hostname and port. It's very common to see web applications expose their HTTP endpoints as a UNIX socket that then get reverse-proxied from something like Nginx or Apache.
But really this URL transformation is not accurate. In the case of the TCP socket, first the TCP layer opens the connection to my-host.xyz:80 and then the path /metrics occurs in the HTTP layer. Similarly for the UNIX socket first you open the connection to /path/to/socket.sock and then pass /metrics over the HTTP layer.
The handling of HTTP and HTTPS is 100% the same. The transport layer (TCP replaced with UNIX socket) is what changes.
This sounds good. I have some services with a builtin exporter at /metrics (e.g. gitea and hedgedoc), where the whole service is listening to a UNIX socket proxy forwarded by nginx. As a workaround, I have setup nginx to listen on localhost/metrics/<service> and proxy forward http://unix:/run/<service>/<service>.sock:/metrics, but it would be nice to be able to skip nginx and just gather metrics directly from the socket, since it's all on the same host.
Here's the relevant nginx config for anyone interested
http{upstream hedgedoc {server unix:/run/hedgedoc/hedgedoc.sock;}upstream gitea {server unix:/run/gitea/gitea.sock;} # Metric endpointsserver{listen127.0.0.1:80;listen [::1]:80;location /metrics/gitea {proxy_passhttp://gitea/metrics;}location /metrics/hedgedoc {proxy_passhttp://hedgedoc/metrics;}} # Example of normal endpointserver{listen0.0.0.0:443;listen [::0]:443;server_name hedgedoc.example.com; # Misc SSL config # ...location / {proxy_passhttp://hedgedoc;}}}
This sounds good. I have some services with a builtin exporter at /metrics
(e.g. gitea and hedgedoc), where the whole service is listening to a UNIX
socket proxy forwarded by nginx. As a workaround, I have setup nginx to
listen on localhost/metrics/<service> and proxy forward http://unix:
/run/<service>/<service>.sock:/metrics, but it would be nice to be able
to skip nginx and just gather metrics directly from the socket, since it's
all on the same host.
Here's the relevant nginx config for anyone interested
http {
upstream hedgedoc {
server unix:/run/hedgedoc/hedgedoc.sock;
}
upstream gitea {
server unix:/run/gitea/gitea.sock;
}
# Metric endpoints
server {
listen 127.0.0.1:80;
listen [::1]:80;
location /metrics/gitea {
proxy_pass http://gitea/metrics;
}
location /metrics/hedgedoc {
proxy_pass http://hedgedoc/metrics;
}
}
# Example of normal endpoint
server {
listen 0.0.0.0:443;
listen [::0]:443;
server_name hedgedoc.example.com;
# Misc SSL config
# ...
location / {
proxy_pass http://hedgedoc;
}
}
}
—
Reply to this email directly, view it on GitHub
<#12024 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AACHHJX35DD4E4ZY4HWN3G3XRZLV7ANCNFSM6AAAAAAVI5MMVU>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
I cannot find what you are referencing. I've grepped through release notes, docs, and the codebase, but I didn't see any relevant mentions of systemd nor sockets?
@roidelapluie it is currently possible for the exporter-toolkit to listen on a UNIX socket via a Systemd socket activation, but it is not currently possible for Prometheus to query these socket directly (unless I missed a commit/pull somewhere).
In my own installations I have also used socat to convert a UNIX socket to a TCP port listener, but that method has its own flaws/issues similar to using Nginx as a reverse proxy (accomplishes same goal).
Discussed at the bug-scrub:
We felt that something in target config would be needed to flag that a Unix socket should be used, and then the scraping code would be changed to interpret that config and use Unix sockets or TCP sockets as required.
I am using the Docker socat workaround in production. The caveat is if you need multiple connections to the socket. To handle this you must put socat in fork mode, which means that it won't restart/detect if a UNIX socket closes and reopens (i.e. providing service restarts or SSH tunnel reconnects). To solve this I additionally have a Systemd path unit watching the UNIX sockets with the PathModified flag that then restarts the socat containers when a UNIX socket is reopened. I never tried using Nginx for this (I should have thought of that!), so it might handle UNIX socket reconnection better. An advantage of many socat containers is that each has its own hostname (scales easily instead of many ports or having to adjust URL paths).
It was a lot to set up, but with this I am successfully and reliably able to reverse SSH tunnel exporters from another machine without polluting the port listeners on the Prometheus machine. Native UNIX socket support would simplify this a lot.
For implementation, it could be as simple as differentiating between a URL starting with http://, https://, and unix:// (or could just look for paths starting with a /). There would also need to be a way to manually provide a hostname (not required for the connection but for how it is represented in Prometheus). I solved this by naming my socat containers.
HTTP over unix socket would be pretty useful for stuff like HAProxy stats. I'd imagine syntax should look something like unix:///file/path.sock?path=/metrics" or 'unix+http:// if we want to differentiate vs raw TCP usage.
Other option would be something like unix://[/file/path.sock]/metrics.
I'm not sure how often passing other headers to unix socket would be required but simplistic solution could be just having header argument in url when there user can do whatever they need to do
unix:/var/run/test.sock is real target address, http://127.0.0.1/api/test is a fake request address for proxied service environment
Activity
DaAwesomeP commentedon Mar 3, 2023
This interests me as well. In my case I am tunneling exporters via SSH to the machine running Prometheus, so it makes more sense to use UNIX sockets than ports for each machine.
HTTP over UNIX socket should work fine and very likely most of the underlying connection code won't care about the difference. I will take a look next week and possibly begin drafting a pull.
roidelapluie commentedon Mar 6, 2023
Hi @DaAwesomeP, I'm curious about how exactly HTTP over Unix socket would work in Prometheus. Would it be Unix+HTTP in the URL? Additionally, how would HTTPS work in this case? It seems to raise a lot of questions. Maybe @rfratto can provide some insights as well. Thanks!
DaAwesomeP commentedon Mar 6, 2023
A UNIX socket can almost always be treated functionally the same as any other TCP socket, minus the hostname and port. It's very common to see web applications expose their HTTP endpoints as a UNIX socket that then get reverse-proxied from something like Nginx or Apache.
A URL like:
becomes
But really this URL transformation is not accurate. In the case of the TCP socket, first the TCP layer opens the connection to
my-host.xyz:80and then the path/metricsoccurs in the HTTP layer. Similarly for the UNIX socket first you open the connection to/path/to/socket.sockand then pass/metricsover the HTTP layer.The handling of HTTP and HTTPS is 100% the same. The transport layer (TCP replaced with UNIX socket) is what changes.
I need to explore how exactly to do this in Go, but the Dialer just works with UNIX sockets in place of TCP: https://pkg.go.dev/net#example-Dialer-Unix
h7x4 commentedon Jul 24, 2023
This sounds good. I have some services with a builtin exporter at
/metrics(e.g. gitea and hedgedoc), where the whole service is listening to a UNIX socket proxy forwarded by nginx. As a workaround, I have setup nginx to listen onlocalhost/metrics/<service>and proxy forwardhttp://unix:/run/<service>/<service>.sock:/metrics, but it would be nice to be able to skip nginx and just gather metrics directly from the socket, since it's all on the same host.Here's the relevant nginx config for anyone interested
roidelapluie commentedon Jul 24, 2023
h7x4 commentedon Jul 24, 2023
I cannot find what you are referencing. I've grepped through release notes, docs, and the codebase, but I didn't see any relevant mentions of systemd nor sockets?
DaAwesomeP commentedon Jul 26, 2023
@roidelapluie it is currently possible for the exporter-toolkit to listen on a UNIX socket via a Systemd socket activation, but it is not currently possible for Prometheus to query these socket directly (unless I missed a commit/pull somewhere).
In my own installations I have also used socat to convert a UNIX socket to a TCP port listener, but that method has its own flaws/issues similar to using Nginx as a reverse proxy (accomplishes same goal).
maxant commentedon Nov 2, 2024
As a work around, you can run the following docker container, and access metrics from inside the network or from the host exposed port:
or without docker:
test it with:
bboreham commentedon Nov 5, 2024
Discussed at the bug-scrub:
We felt that something in target config would be needed to flag that a Unix socket should be used, and then the scraping code would be changed to interpret that config and use Unix sockets or TCP sockets as required.
DaAwesomeP commentedon Nov 5, 2024
I am using the Docker socat workaround in production. The caveat is if you need multiple connections to the socket. To handle this you must put socat in
forkmode, which means that it won't restart/detect if a UNIX socket closes and reopens (i.e. providing service restarts or SSH tunnel reconnects). To solve this I additionally have a Systemdpathunit watching the UNIX sockets with thePathModifiedflag that then restarts the socat containers when a UNIX socket is reopened. I never tried using Nginx for this (I should have thought of that!), so it might handle UNIX socket reconnection better. An advantage of many socat containers is that each has its own hostname (scales easily instead of many ports or having to adjust URL paths).It was a lot to set up, but with this I am successfully and reliably able to reverse SSH tunnel exporters from another machine without polluting the port listeners on the Prometheus machine. Native UNIX socket support would simplify this a lot.
For implementation, it could be as simple as differentiating between a URL starting with
http://,https://, andunix://(or could just look for paths starting with a/). There would also need to be a way to manually provide a hostname (not required for the connection but for how it is represented in Prometheus). I solved this by naming my socat containers.XANi commentedon Nov 8, 2024
HTTP over unix socket would be pretty useful for stuff like HAProxy stats. I'd imagine syntax should look something like
unix:///file/path.sock?path=/metrics" or 'unix+http://if we want to differentiate vs raw TCP usage.Other option would be something like
unix://[/file/path.sock]/metrics.I'm not sure how often passing other headers to unix socket would be required but simplistic solution could be just having
headerargument in url when there user can do whatever they need to doShaeto commentedon Nov 20, 2024
apache uses this semantic:
ProxyPass unix:/var/run/test.sock|http://127.0.0.1/api/testunix:/var/run/test.sockis real target address,http://127.0.0.1/api/testis a fake request address for proxied service environmentanubis: export metrics over TCP
anubis: export metrics over TCP
metrics: init
metrics: init
chore(deps): update dependency prometheus/prometheus to v3.15.0
chore(deps): update dependency prometheus/prometheus to v3.15.0
chore(deps): update dependency prometheus/prometheus to v3.15.0
chore(deps): update dependency prometheus/prometheus to v3.15.0
chore(deps): update dependency prometheus/prometheus to v3.15.0
feat(container): update image quay.io/prometheus/prometheus (v3.14.0 …
feat(container): update image quay.io/prometheus/prometheus (v3.14.0 …