8

To monitor a small home server, I run prometheus and node_exporter (and grafana, and several more things) on docker (similar to https://github.com/stefanprodan/dockprom). I run prometheus on a bridged docker network. For node_exporter, I have two options, which affect the node_network_transmit_bytes_total metric.

  • Using the same bridged docker network as prometheus
    • Pro: nodeexporter can be addressed directly by name, thanks to docker's internal DNS
    • Con: The node_network_transmit_bytes_total metric only has docker's virtual internal NIC, not the physical NIC of the box being monitored. This is depsite bind-mounting /proc from the host into /host/proc in the container (specifically my physical interface is eno0, visible in /proc/net/dev on the host):
      $ docker exec -it nodeexporter2 cat /host/proc/net/dev | awk '{print $1}'
      Inter-|
      face
      eth0:
      lo:
      
  • Using host-mode networking for nodeexporter
    • Pro: All NICs, including the physical host NIC, are visible
    • Con: There does not appear to be a clean way for prometheus to address nodeexporter:
      • localhost means prometheus itself
      • Hostname of host seems inaccessible? Running docker exec -it prometheus wget -O - http://actual-hostname:9100/metrics works (and uses my host's LAN IP, 192.168.x.x), but configuring actual-hostname:9100 as a prometheus target gives an error (Get "http://actual-hostname:9100/metrics": dial tcp 127.0.1.1:9100: connect: connection refused). I'm not sure why they're resolving differently.
      • What I ended up doing is emulating the host.docker.internal feature available for docker-on-windows and docker-on-mac, by adding this to my docker-compose.yml:
        extra_hosts:
        - "host.docker.internal:172.18.0.1"
        
        That's very brittle, however: That 172.18 was just recently 172.19; I believe it changed on reboot or docker version upgrade. I'd love to do be able to set the extra_hosts to a result of running some script on the host to determine the correct network name, but that wouldn't automatically be re-run on boot.

Any advice?

lutzky
  • 598
  • 5
  • 12

1 Answers1

7

Late edit: Thanks to thomas, turns out there's a magic host host-gateway that does this, so extra_hosts: ["host.docker.internal:host-gateway"] should do the trick. undocumented, but apparently it's implemented here. and already live in docker 20.10.6 (and likely earlier).


I ended up solving this by manually configuring the network:

networks:
  monitor-net:
    driver: bridge
    ipam:
      driver: default
      config:
        - subnet: 172.23.0.0/16
          ip_range: 172.23.5.0/24
          gateway: 172.23.5.254

# ...

services:
  nodeexporter:
    network_mode: host
    # ...
  prometheus:
    networks:
      - monitor-net
    extra_hosts:
      - "host.docker.internal: 172.23.5.254"

Then prometheus has the target of host.docker.internal for node_exporter, and the address should be stable.

lutzky
  • 598
  • 5
  • 12
  • 4
    In newer docker versions you can use `extra_hosts: - "host.docker.internal:host-gateway"` and don't have to configure the network manually. – Thomas Aug 31 '21 at 20:23
  • 2
    Huh, cool! It's undocumented, but apparently it's implemented [here](https://github.com/docker/docker-ce/commit/9895d90167354f11c34787d9be850c21b087f5d9) and already live in docker 20.10.6 (and likely earlier). – lutzky Sep 01 '21 at 20:27