Frontend Labs
⋯

Chapter 50 — Container networking: how containers talk to the world

In one sentence

By default, Docker creates a private, virtual network for your containers to talk to EACH OTHER by name, and you must explicitly publish a port to make a container reachable from OUTSIDE that network — both mechanisms are Chapter 37's networking concepts, applied inside a container's own network namespace.

Why this matters

"Why can't I reach my container from my browser" and "why can my two containers talk to each other by name" are both answered by understanding exactly what Docker's networking layer is doing.

How it actually works

   docker network ls                      # Docker creates a default
                                          # "bridge" network; you can
                                          # also make your own

   docker run -p 8080:80 nginx              # PUBLISH: map the HOST's
                                          # port 8080 to the
                                          # CONTAINER's port 80 --
                                          # WITHOUT this flag, the
                                          # container's port is only
                                          # reachable from OTHER
                                          # containers on the same
                                          # Docker network, never from
                                          # the host or outside world

   docker network create mynet               # a custom, USER-DEFINED
                                          # network
   docker run --network mynet --name web nginx
   docker run --network mynet --name db postgres
   # `web` can now reach `db` simply as "db" -- Docker runs a built-in
   # DNS resolver on user-defined networks, resolving CONTAINER NAMES
   # to their internal IP addresses automatically (Chapter 37's DNS
   # concept, provided for you)

   THE NETWORK DRIVERS, briefly:
     bridge (the default)    an isolated virtual network on this host;
                            containers on it can reach each other; the
                            outside world can reach IN only via
                            published ports.
     host                     the container uses the HOST's network
                            namespace DIRECTLY, no isolation at all --
                            faster, but loses the isolation Chapter 44
                            described.
     none                      no networking at all.
     overlay                    spans MULTIPLE HOSTS -- the foundation
                            for Docker Swarm, and conceptually a
                            preview of what Kubernetes' networking
                            model (Part 16) does at a larger scale.

Real-world example

   The reason Docker Compose (Chapter 51) creates a DEDICATED,
   PROJECT-SPECIFIC network automatically, rather than putting
   everything on the shared default "bridge" network, is directly this
   chapter's DNS-by-container-name mechanism, made practical: Compose's
   own official documentation describes exactly this behaviour -- every
   service defined in a `docker-compose.yml` file can reach every OTHER
   service simply by its SERVICE NAME (e.g. an application container
   connecting to `postgresql://db:5432/...`, where `db` is just the
   name given to the database service in the same compose file), with
   NO manual IP address configuration, NO manual network creation, and
   NO hardcoded addresses anywhere -- because Compose automatically
   creates a user-defined network (this chapter's exact mechanism) for
   the whole project and gives every service that network's built-in
   name resolution for free.
   This is a genuinely practical, extremely common real pattern: almost
   every real multi-container local-development setup you'll encounter
   relies on this exact "reach the other service by its plain name"
   mechanism, and it stops feeling like magic the moment you know it's
   just Chapter 37's DNS resolution, running on a Docker-managed virtual
   network, automatically configured for you.

Try it yourself

# See the difference publishing makes
docker run -d --name unpub nginx
curl -s localhost:80 > /dev/null 2>&1 && echo "reachable" || echo "NOT reachable (expected -- no -p flag)"
docker rm -f unpub

docker run -d --name pub -p 8080:80 nginx
sleep 1
curl -s localhost:8080 > /dev/null 2>&1 && echo "reachable now!" || echo "still not reachable -- check Docker is running"
docker rm -f pub

# See container-name DNS resolution on a user-defined network
docker network create demonet
docker run -d --name pingtarget --network demonet alpine sleep 300
docker run --rm --network demonet alpine ping -c 2 pingtarget    # reaches
                                                                 # it BY
                                                                 # NAME
docker rm -f pingtarget
docker network rm demonet

Common mistakes

  • Forgetting -p and assuming a container should just be reachable. Without publishing, it's isolated on Docker's internal network — invisible from the host or outside world by design.
  • Confusing -p 8080:80 order. It's always HOST:CONTAINER — a common, easy-to-transpose mistake.
  • Putting everything on the default "bridge" network and wondering why name-based resolution doesn't work. Container-name DNS resolution only works on USER-DEFINED networks — create one (or let Compose do it for you).

Check yourself

  1. What does -p 8080:80 actually do, and what's reachable without it?
  2. Why can containers on a user-defined network reach each other by name, with no manual configuration?
  3. Why does the default "bridge" network NOT support this name-based resolution?

Further reading

  • Docs: Docker's own official "Networking overview" and "Networking with standalone containers" documentation.
  • Reference: docker network --help.
  • Guide: this wiki's networking/tcp-ip guide covers DNS resolution itself in far greater depth than this chapter's Docker-specific summary.

Generated from real-life-os-guide.md · 8 Oct 2026 16:36