When you open http://localhost:9090 in your browser, you're accessing your local machine on port 9090, where Prometheus is running. Since the browser runs on your host machine, it works as expected.
However, when Grafana, running inside a Docker container, tries to access http://localhost:9090, it does not refer to your local machine. Instead, localhost inside a Docker container refers to the container itself, meaning Grafana is looking for Prometheus inside its own container. Since Prometheus is running in a separate container, Grafana cannot find it this way.
The correct approach is to use the Docker service name instead of localhost. In Docker Compose, each service is assigned a hostname that matches its service name from docker-compose.yml. So, replacing http://localhost:9090 with http://prometheus:9090 works because Grafana can now find Prometheus within the Docker network.
Summary:
http://localhost:9090 works in your browser because the browser runs on your local machine.
http://localhost:9090 does not work inside Grafana’s container because localhost refers to the Grafana container, not the host machine.
http://prometheus:9090 works because Docker provides internal DNS resolution, allowing containers to communicate using service names.
✅✅✅✅✅✅✅✅✅
Pro tip: When connecting services within Docker, always use service names instead of localhost.