Data and networking
Connect containers by name
Place services on a user-defined network and use Docker DNS instead of hard-coded container IP addresses.
Every container gets an IP address on Docker’s network. Don’t use it. Replace the container and the address can change. Hard-code 172.17.0.3 in your config and it’ll work until the day it doesn’t.
Use names instead.
User-defined networks come with DNS
When you create your own network, Docker adds a small DNS server to it. Every container on the network can reach the others by container name. Let’s see it:
docker network create notes-net
docker run --name database --network notes-net -e POSTGRES_PASSWORD=development-only -d postgres:17-alpine
docker run --rm --network notes-net alpine ping -c 1 database
The last command starts a throwaway Alpine container on the same network and pings database. The output shows something like PING database (172.18.0.2): Docker resolved the name to the container’s current address. Replace the database container tomorrow, let it get a new address, and the name still works. Nothing in your config changes.
The -e POSTGRES_PASSWORD flag is there because the official PostgreSQL image refuses to start without a password. Without it the container exits in a second, and a stopped container disappears from Docker’s DNS, so the ping would fail.
This only works on a network you created. The default bridge network Docker ships with doesn’t resolve container names, which is one reason to always create your own.
Which port to use
Inside a network, containers talk to each other’s internal port. PostgreSQL listens on 5432 inside its container, so the API connects to database:5432. Published host ports are irrelevant here. You don’t need -p 5432:5432 on the database for the API to reach it, and adding it only exposes the database to your machine and possibly beyond.
localhost means “me”
One more trap. Inside the API container, localhost is the API container. A connection string like postgres://localhost:5432/notes fails with ECONNREFUSED, because nothing listens on 5432 in the API container. Use the service name: postgres://database:5432/notes.
Names are discovery, not security
Docker DNS tells a container where another one is. It doesn’t check who is asking. Anyone on the network can resolve database and open a connection. So keep using database credentials, be selective about which containers join which network, and add TLS when the threat model calls for it.
Try this: create the network, run the ping, and check docker network inspect notes-net to see the containers attached. Then remove the practice container with docker rm -f database and the network with docker network rm notes-net.
Lesson completed