1.4 · Networks: making containers talk to each other

Level 1 · Containers: images, volumes, networks

1.4Networks: making containers talk to each other

Goal: connecting two containers together on a dedicated network, without exposing the database.
Estimated time: 12 min · self-paced reading · If you only have 5 min: read “The essentials in 30s” + the diagram.

The essentials in 30 seconds

  • The default bridge isolates without naming: each container has a private IP, but names do not resolve there — you tinker with IPs that change.
  • One network per application: docker network create monapp then --network monapp on each run — from the web, the database is reached by its --name (bdd:5432).
  • Published frontend, internal database: publish (-p) only the web; the database stays invisible from the outside but reachable from the inside — inspect and ping prove the wiring.

Running mini-case — Idir wires web + database

Idir's demo grows: his frontend must talk to the database by name, not by an IP noted on a sticky note. He creates a monapp network, relaunches bdd on it without publishing its port, then relaunches web on it with -p 8080:80. From the web, he pings bdd: it answers by name. When a colleague suggests « publishing the database to test », Idir refuses: exposing Postgres to the whole machine for a test installs a dangerous habit.

Continuation of cases 1.1-1.3 — Idir moves from isolated containers to a wired application.

1. The default network isolates

Each container gets a private IP on the default bridge network, but names do not resolve there: you tinker with IPs that change on each relaunch. Hard-coding an IP in the config programs the next outage.

The good practice is to create a dedicated network per application: Docker enables name resolution there.

2. One network per application

docker network create monapp then --network monapp on each service run: from the web, the database is reached by its --name (bdd:5432). Publish (-p) only the frontend; the database stays invisible from the outside but reachable from the inside.

This « one network, one published frontend » pattern is exactly what Compose will automate at level 3.

3. Seeing is believing: inspect and ping

docker network ls and inspect show who is plugged where. From a container, ping bdd or a connection proves resolution. Method: create, plug, prove — in that order.

If two containers cannot see each other, first check they share the same network, then that you reach the name and not an IP.

Common misinterpretation: « Staying on the default bridge with IPs is enough, and publishing the database helps debugging ». No. Without a dedicated network, no DNS by name: IPs change and the config breaks. And publishing the database « to test » exposes it to the whole machine — one forgotten cleanup leaves Postgres open. Dedicated network + names + unpublished database.
Dedicated network: wiring an app One network per app: published frontend, internal database monapp network create,one per appPublished web -p Reachedfrom the outsideInternal bdd :5432 Reached byname, never published
One network per app: published frontend, internal database
Text version of the diagram (SEO / screen readers / translation): 1) Create: Idir creates the monapp network — one per application, clearly named. 2) Plug: bdd relaunched on it without -p (invisible outside), web relaunched on it with -p 8080:80 (the only frontend). 3) Prove: ping bdd from web — name resolution answers. Lesson: publishing the database would have exposed Postgres to the whole machine; the name bdd:5432 stays valid even if the IP changes.

🔎 Concrete example — 🔎 Concrete example — Web + database on a private network

Idir's wired application: one frontend, one invisible database.

docker network create monapp
docker run -d --name bdd --network monapp -e POSTGRES_PASSWORD=secret postgres:16.4
docker run -d --name web --network monapp -p 8080:80 nginx:1.27
docker exec web ping -c2 bdd

Reading: ping succeeds by name, without publishing the database.

Lesson: publishing the database would have exposed Postgres to the whole machine.

Section vocabulary

Bridge
Default isolated network driver between containers and host; no name resolution.

Simple example: The default network where Idir tinkered with IPs.

What it is not: an application network with DNS by name.

Reflex: default = temporary, app = dedicated network.

Dedicated network
Network created per application (network create), with DNS name resolution between its containers.

Simple example: monapp, where web reaches bdd:5432.

What it is not: one network per container.

Reflex: separate by app, not by service.

Name resolution
Reaching a container by its --name rather than its changing IP.

Simple example: ping bdd from web, valid after each relaunch.

What it is not: an IP hard-coded in the config.

Reflex: always the name, never the IP.

Frontend
The only service published to the outside (the web); everything else stays internal.

Simple example: web on 8080:80, bdd unpublished at Idir's.

What it is not: every service published « just in case ».

Reflex: only one published: the frontend.

In practice — In practice — Wiring a mini-app

  1. Create a monapp network.
  2. Launch the database on it, WITHOUT port publishing.
  3. Launch the web on it, WITH 8080:80 publishing.
  4. From the web (exec), ping the database by name.
Your services talk by names, with a minimal exposed surface.

Script ready to say — wiring two containers (30 s)

« I create one network per app: network create monapp. I plug the database on it without publishing its port, and the web on it with -p 8080:80. From the web, I ping the database by name: bdd. The frontend is published, the database never is. »

Say while typing create then both runs; finish with the successful ping.

Copy-paste template — two-service app

docker network create monapp
docker run -d --name bdd --network monapp -e POSTGRES_PASSWORD=secret postgres:16.4
docker run -d --name web --network monapp -p 8080:80 nginx:1.27
docker exec web ping -c2 bdd   # proof by name
docker network ls              # check the connections

Idir's app

As above: monapp, internal bdd, published web — the pattern Compose will automatically reuse at level 3.

Two apps coexist

monapp and compta, two separate networks: each app's bdd is reached by name without seeing across apps.

Outage diagnosis

Two deaf containers: check network inspect on both sides — nine times out of ten, they do not share the same network.

Refusing to publish the database

« To test »: no — test from the web with exec and ping, the database stays closed to the outside. Dangerous habit refused.

✓ Best practices

  • One network per application, clearly named.
  • Publish only the frontend.
  • Reach by name, never by IP.

✗ Common pitfalls

  • Staying on the default bridge (no DNS).
  • Publishing the database « to test » then forgetting it.
  • Hard-coding IPs in the config.

Key takeaways

  • The dedicated network enables DNS by name.
  • Database internal, published frontend: the rule.
  • inspect and ping prove the wiring.
  • Compose will reuse this pattern automatically.

48h challenge — apply tomorrow

Create monapp, plug bdd (no -p) and web (8080:80) into it, then ping bdd by name from web. Check with network inspect who is plugged where.

Section exit checklist
  • I create a dedicated network per application.
  • I publish only the frontend, the database stays internal.
  • I reach services by name and prove with ping.
Self-assessment 1-5: is my database reachable by name without being published?can I prove the wiring (inspect, ping)?

Frequently asked questions

Why can't two containers see each other?

Often they do not share the same network, or you try an IP instead of the name. Check network inspect on both sides, then reach the --name.

One network per container?

No: one network per application (web + database + cache together). Separate by app, not by service.

Check your understanding

On a dedicated network, how should the web reach the database named 'bdd'?

Additional resources (optional, to go further)

Level 1 examFresh, harder questions to test what you've learned