Network troubleshooting
A method for "it can't connect".
Container connectivity problems yield to a method, not guesswork: work outside-in and stop at the first “no.” Is the container running? Is it attached to the network you think? Does the name resolve? Is the target port actually open and listening? Is it published, if you are reaching from the host? Each question has a one-line check, and the first that fails is your answer.
$ docker inspect -f '{{ json .NetworkSettings.Networks }}' web # which networks + IP?$ docker network inspect appnet -f '{{ range .Containers }}{{ .Name }} {{ end }}'web db # are BOTH actually attached to appnet?
A toolbox on the network
Minimal images lack ping, curl, and dig, so the fastest move is a throwaway toolbox (nicolaka/netshoot) on the same network. nslookup a name to test DNS, curl the name and port to test reachability, and ss inside the target to see whether the app is even listening. This cleanly separates “DNS is broken” from “the port is closed” from “the app is not listening at all.”
$ docker run --rm -it --network appnet nicolaka/netshoot# nslookup db # DNS: does the name resolve to an IP?# nc -zv db 5432 # reachability: is the port open?# curl -m3 http://web:3000/healthz
Scenario: "web cannot reach db"
The single most common failure. Walk it: are web and db on the same user-defined network (not the default bridge, which has no DNS)? Does nslookup db resolve? Does the port connect? Is db actually listening? Nine times out of ten the answer is that the two containers are on different networks, so the name never resolves.
$ docker inspect -f '{{range $k,$v := .NetworkSettings.Networks}}{{$k}} {{end}}' webappnet$ docker inspect -f '{{range $k,$v := .NetworkSettings.Networks}}{{$k}} {{end}}' dbbridge # <- there it is: db is on the default bridge, not appnet$ docker network connect appnet db # fix: put db on the same network
Scenario: "cannot reach my published port from the host"
The container is up and -p looks right, but curl localhost:8080 refuses. First confirm the mapping with docker port; then check the sneaky one — the app inside the container bound to 127.0.0.1 instead of 0.0.0.0, so it is listening only to itself and no host mapping can ever reach it. ss inside the container shows the truth.
$ docker port web8080/tcp -> 0.0.0.0:8080 # mapping is fine$ docker exec web ss -tlnpState Local Address:PortLISTEN 127.0.0.1:80 # the bug: bound to localhost, not 0.0.0.0# fix the app config to listen on 0.0.0.0 and it becomes reachable