skip to content

Container Networking

Docker's network drivers (bridge, host, overlay, macvlan), the embedded DNS that resolves container names on a user-defined network, and what publishing a port changes on the host. Asked because the default bridge behaves unlike every network you create.

part ofDockeroverview, primer and where to startread it →
on this pageshow

questions

28

What is Docker's default `bridge` network (docker0), and why does Docker recommend creating your own bridge network instead?

level: juniorimportance: must knowfreq 74%

answer

  1. Two bridges, one is created for you
  2. Which containers share the segment?
  3. Name resolution exists on only one of them
  4. docker0 options are daemon-wide; a created network's are per-network
  5. docker network create, then --network on run

basics

~20 s

Every container started without --network lands on the shared default bridge, docker0, where peers can only be reached by IP address. A bridge you create with docker network create adds name-based discovery, membership-scoped isolation and per-network options.

solid answer

~50 s

The daemon creates a Linux bridge called `docker0` at start-up, and any container run without `--network` is attached to it through a veth pair, taking an address from the bridge's subnet. That makes docker0 one shared segment for every container on the host that did not ask for anything else, and on it containers can only address each other by IP — there is no name resolution. A network you create with `docker network create` uses exactly the same plumbing on a bridge of its own, but adds three things: Docker's embedded resolver, so attached containers reach each other by container name or alias; a membership boundary, so containers on other networks cannot reach in; and per-network options set at create time (`--internal`, `--opt com.docker.network.driver.mtu`, `--opt com.docker.network.bridge.enable_icc`) instead of daemon-wide settings that need a dockerd restart. The default bridge is kept for backwards compatibility and one-off commands.

code

bash · 8 lines
bash
# Default bridge: no name resolution between containers
docker run -d --name digest-redis redis:7
docker run --rm ruby:3.3-slim-bookworm getent hosts digest-redis || echo "no such name"

# A bridge you create: the container name resolves
docker network create digest-net
docker run -d --name digest-cache --network digest-net redis:7
docker run --rm --network digest-net ruby:3.3-slim-bookworm getent hosts digest-cache

go deeper

for a junior

Be ready to say that a container with no --network flag joins the default bridge, and that containers there can only reach each other by IP. Know the two commands: docker network create, then docker run --network.

for a middle

Explain the mechanics: a veth pair per container enslaved to docker0 or to br-<id>, addresses from that bridge's subnet, and the embedded resolver that only user-defined networks get. Know that a created network's options are fixed at create time.

for a senior

Show the operational consequences: docker0 is one shared segment for unrelated workloads, its settings are daemon-wide and need a dockerd restart, and network membership is not a substitute for controlling published ports.

for a principal

Own the convention for a fleet: one network per stack, never the default bridge for anything long-lived, and a documented place for per-network options so nobody reaches for a daemon-wide change to solve one team's problem.

## The three networks Docker gives you for free On a fresh engine, `docker network ls` lists three predefined networks: `bridge`, `host` and `none`. The `bridge` entry is what people call the **default bridge**. When dockerd starts it creates a Linux bridge device on the host named `docker0`, gives it an address, and attaches every container that is started without an explicit `--network` flag to it. None of the three predefined networks can be removed. ## What attachment actually looks like When a container joins any bridge network, the daemon creates a veth pair: one end stays on the host and is enslaved to the bridge device, the other is moved into the container's network namespace where it appears as `eth0`. The container gets an address out of that bridge's subnet and a default route pointing at the bridge's own address. A network you create — `docker network create digest-net` — gets exactly the same plumbing; the only visible difference on the host is that the bridge device is named `br-<first characters of the network id>` rather than `docker0`. So the *mechanism* is identical. What differs is scope, discovery, configuration and lifecycle. ## Difference 1 — who is on the segment The default bridge is a single shared segment. Every container on the host that did not ask for a network is a peer of every other one: your database, a colleague's debugging shell, a job container someone left running. A network you create is a membership list. Only the containers you attach are on it, and a container attached to a different bridge cannot reach in, because the daemon does not route between the two bridges. That is the isolation people mean when they say "put it on its own network". ## Difference 2 — discovery On a user-defined bridge Docker gives each attached container an embedded resolver, so container names and network aliases resolve to the peer's current address. On the default bridge there is no such resolution: you address peers by IP, or historically by declaring a `--link`. Since a container's address is handed out at start time and can be different after the next start, "IP only" is a fragile way to wire anything together. The internals of that resolver are a separate subject; the bridge-level fact to carry into an interview is that the feature exists only on networks you create. ## Difference 3 — configuration granularity Settings for docker0 are daemon-wide. `mtu`, `icc`, `bip` and the address pools live in `/etc/docker/daemon.json`, and changing one means restarting dockerd, which touches every container on the host. A network you create takes its settings at creation time and keeps them: `--subnet`, `--gateway`, `--internal`, and `--opt` keys such as `com.docker.network.driver.mtu`, `com.docker.network.bridge.enable_icc`, `com.docker.network.bridge.name` and `com.docker.network.bridge.enable_ip_masquerade`. Those options are immutable afterwards — to change one you create a replacement network and re-attach the containers — but the blast radius of a change is one network, not the whole engine. ## Difference 4 — lifecycle A running container can be attached to a network you created with `docker network connect`. For the default bridge, Docker's guidance is to recreate the container with `--network` rather than shuffling it around, because its networking was decided at creation. ## Difference 5 — legacy versus current `--link` only ever made sense on the default bridge, as a workaround for the missing name resolution. It is documented as legacy. On a user-defined network you simply use the peer's name. ## The failure everybody meets A stack that worked as a Compose project is re-run by hand as three `docker run` commands. Under Compose the containers were on a network of their own; run by hand they land on docker0, and the first thing that breaks is name resolution — a Ruby email-digest builder that opens `redis://digest-redis:6379` now dies with `getaddrinfo: Name or service not known`. The fix is a network, not hand-written `/etc/hosts` entries and not `--link`: ``` docker network create digest-net docker run -d --name digest-redis --network digest-net redis:7 docker run -d --name digest-worker --network digest-net digest:1.4 ``` ## What isolation does and does not mean Two caveats keep coming up as follow-ups. First, attaching to your own network isolates you from containers on *other* networks; it does not firewall peers on the *same* network from each other — that needs inter-container communication disabled explicitly. Second, none of this changes port publishing: `-p 8080:4567` maps a host port the same way whichever bridge the container is on, so "it is on a private network" is not an argument that it is unreachable from outside the host. ## When the default bridge is fine Throwaway commands. `docker run --rm -it ruby:3.3-slim-bookworm irb` does not need a network of its own. The moment a second container has to find the first one by name, create a network.

  • Can you change the subnet or MTU of the default bridge the way you can for a network you create?
    Not per network — docker0 is configured by the daemon, through keys such as `bip`, `mtu` and `icc` in `/etc/docker/daemon.json`, and the change only takes effect after restarting dockerd, which affects every container on the host. A network you create takes `--subnet`, `--gateway` and `--opt` values at creation time; they are fixed for that network's life, so changing one means creating a replacement network and re-attaching.
  • Can you move a container off the default bridge without recreating it?
    You can attach a running container to another network at any time with `docker network connect`, so it ends up on both. Docker's own guidance for getting it off the default bridge is to stop it and recreate it with `--network`, because its networking — address, resolver behaviour, any legacy links — was decided when the container was created.
  • Does putting containers on their own network change how you publish ports?
    No. `-p` publishes a container port on a host port regardless of which bridge the container is attached to, and it stays reachable from outside the host. The network only decides which other containers can address it directly. Treating "it is on a private network" as protection from external traffic is a common mistake.

The default bridge is the shared office Wi-Fi that every device joins by default and where you have to know each other's IP; a network you create is a small private VLAN with its own directory and its own settings.

saying these in an interview costs you the question

  • Says containers on the default bridge resolve each other by name
  • Thinks docker0 and a created bridge differ only in the device name
  • Believes a user-defined network hides published ports from outside
  • Claims --link is still needed on a user-defined network
  • Assumes a created network's options can be edited after creation
  • Cannot say which network a container without --network joins

context

open as a page

In Docker, how does one container reach another container by name, and why does that same lookup fail when both containers run on the built-in default `bridge` network?

level: juniorimportance: must knowfreq 68%

basics

~20 s

On a user-defined network Docker runs an embedded DNS server at 127.0.0.11 that resolves container names and network aliases to container IPs. The built-in default bridge network has no such DNS: there you only have raw IPs or the deprecated --link flag.

open as a page

Compare Docker's `bridge`, `host` and `none` network drivers: what does each do to a container's networking, and when would you choose each?

level: juniorimportance: must knowfreq 66%

basics

~20 s

bridge gives the container its own network namespace on a virtual switch with NAT for outbound traffic and published ports for inbound - the default. host puts the container directly in the host's network namespace: no isolation, no NAT, no port publishing. none gives a namespace with only loopback: no external networking at all.

open as a page

Walk through how you would put two containers on the same Docker network, attach a third container to that network after it is already running, and later detach it. What does membership in a Docker network give a container, and what keeps it isolated from containers on a different network?

level: juniorimportance: must knowfreq 68%

basics

~20 s

Run docker network create appnet, then start containers with --network appnet. A running container is attached later with docker network connect appnet NAME and removed with docker network disconnect. Membership gives an interface and IP on that bridge, so members reach each other on any port. Docker's isolation iptables rules block traffic between different bridges.

open as a page

Explain what docker run -p 8080:80 does: which number is which, how the capital -P flag differs, and what has to be true of the process inside the container for the mapping to work at all.

level: juniorimportance: must knowfreq 82%

basics

~20 s

The form is host:container, so -p 8080:80 sends traffic arriving at host port 8080 to port 80 in the container. Capital -P publishes every EXPOSEd port to a random free host port; docker port shows the result. The container process must listen on 0.0.0.0, not 127.0.0.1, or nothing reaches it.

open as a page

`docker run -p 9412:8080` fails with "port is already allocated" — how do you find what holds that host port?

level: juniorimportance: must knowfreq 64%

basics

~20 s

Something already owns that host port. Ask Docker first: docker ps -a plus docker port <name> shows whether another container publishes 9412, including one stuck restarting. Then ask the host: sudo ss -ltnp | grep :9412 names the owning process.

open as a page

Which subnet does Docker's default bridge docker0 use, and where do user-defined networks get their subnets?

level: middleimportance: must knowfreq 62%

basics

~20 s

Docker's docker0 bridge defaults to 172.17.0.0/16, with the host holding 172.17.0.1 as the gateway. Every network you create is carved from the daemon's built-in address pool list: 172.17.0.0/16 through 172.31.0.0/16, then 192.168.0.0/16 split into /20 blocks.

open as a page

Inside a Docker container, a connection to another service fails. How do you prove whether name resolution or the network path is at fault?

level: middleimportance: must knowfreq 71%

basics

~20 s

Resolve the name first: getent hosts <name> inside the container. No answer means a resolution problem — read /etc/resolv.conf and check which network the container is on. An answer followed by a refusal or a hang means the path or the peer's listener, not DNS.

open as a page

A Docker network is allocated 172.20.0.0/16, which the corporate VPN also routes. How do you fix the collision?

level: seniorimportance: must knowfreq 54%

basics

~20 s

Move Docker's addressing off the routed range. Set default-address-pools (and bip for docker0) in /etc/docker/daemon.json to a block nothing else routes, restart the daemon, then delete and recreate existing networks — pools apply only when a subnet is first allocated.

open as a page

Docker's embedded DNS server answers at 127.0.0.11 inside a container. Explain how queries actually reach it, and what it does with a name it does not recognise.

level: middleimportance: should knowfreq 42%

basics

~20 s

127.0.0.11 is a loopback address inside the container's own network namespace; NAT rules there redirect port 53 traffic to a listener the Docker daemon runs for that namespace. Container names are answered locally; unknown names are forwarded to the daemon's configured upstream resolvers.

open as a page

You attach three Docker containers to the same network, each with `--network-alias api`. What does a lookup of the name `api` return, and what are the limits of relying on that for load balancing?

level: middleimportance: should knowfreq 36%

basics

~20 s

The lookup returns all three container IPs, with the order shuffled per query, so clients spread naturally. It is DNS round-robin only: no health checking, no connection-level balancing, and client-side caching or long-lived connections can pin traffic to one container.

open as a page

What do you gain and what do you give up by running a container with Docker's `host` network driver on Linux?

level: middleimportance: should knowfreq 44%

basics

~20 s

You gain no NAT or veth hop (lower latency, no per-connection tracking entry, real client IPs, unrestricted port ranges). You give up network isolation, port independence (conflicts with the host and other host-mode containers), published-port mapping, and Docker network name resolution.

open as a page

A process inside a container needs to reach a service running directly on the Docker host, for example a database listening on the host's port 5432. Explain the special DNS name host.docker.internal: what it resolves to, where it works out of the box, and what you do on a platform where it does not exist.

level: middleimportance: should knowfreq 50%

basics

~20 s

host.docker.internal is a name Docker injects that resolves to the host from inside a container. It exists automatically on Docker Desktop (macOS/Windows). On plain Linux you must add it yourself with --add-host=host.docker.internal:host-gateway, and the host service must listen on an address the container can reach, not only 127.0.0.1.

open as a page

When you publish a container port on a Linux Docker host, what actually happens to a packet arriving at that host port? Describe the role of the bridge interface, the iptables NAT rules Docker installs, and the docker-proxy userland process.

level: middleimportance: should knowfreq 52%

basics

~20 s

Docker adds an iptables DNAT rule in the nat table's DOCKER chain that rewrites the destination to the container's bridge IP and port; the FORWARD chain permits it and conntrack rewrites replies. Outbound container traffic is source-NATed by a MASQUERADE rule. A small docker-proxy process covers cases NAT misses, such as loopback connections.

open as a page

How do you block container-to-container traffic on a Docker bridge network, and how does docker0 differ from a bridge you create?

level: seniorimportance: should knowfreq 27%

basics

~20 s

Disable inter-container communication. For the default docker0 bridge it is the daemon-wide setting: dockerd --icc=false, or "icc": false in daemon.json. For a bridge you create it is a driver option fixed at creation: --opt com.docker.network.bridge.enable_icc=false.

open as a page

Containers on a user-defined Docker bridge stall on large responses while small requests succeed — how do you diagnose it?

level: seniorimportance: should knowfreq 34%

basics

~10 s

That signature points at an MTU mismatch: the bridge is 1500 while the host's real egress path is smaller, so full-size frames are dropped. Compare the container's eth0 MTU with the host's egress interface.

open as a page

How does Docker decide which upstream DNS servers a container uses, and what would you change if every container must query a corporate internal DNS server instead?

level: seniorimportance: should knowfreq 30%

basics

~20 s

Docker derives upstream resolvers from the host's /etc/resolv.conf, dropping loopback entries and falling back to public resolvers if nothing is left. Override globally with the daemon.json dns/dns-search/dns-opts keys, or per container with --dns, --dns-search, --dns-option, or Compose's dns keys.

open as a page

How does Docker's `overlay` network driver let containers on different hosts communicate as if on one network, and what does it require from the underlying infrastructure?

level: seniorimportance: should knowfreq 33%

basics

~20 s

Overlay networks tunnel container traffic between hosts using VXLAN: each network gets a VXLAN ID and packets are encapsulated in UDP (default port 4789) between host IPs. It needs a control plane (Docker swarm mode), the swarm management and gossip ports plus UDP 4789 open, and MTU headroom for the encapsulation header.

open as a page

Docker reports "could not find an available, non-overlapping IPv4 address pool" on a CI host. Why, and how do you fix it?

level: seniorimportance: should knowfreq 40%

basics

~10 s

The daemon's address-pool list is empty: roughly 31 networks fit in the built-in defaults and leaked per-project networks consumed them all. Prune the unused networks, fix the teardown, then raise the ceiling with default-address-pools.

open as a page

What does starting a container with Docker's --network container:<name> flag do? Explain exactly what is shared and what is not shared between the two containers, and give a case where you would use it.

level: seniorimportance: should knowfreq 42%

basics

~20 s

The new container joins the existing container's network namespace instead of getting its own. They share interfaces, IP, ports and loopback, so they reach each other on 127.0.0.1 and cannot both bind the same port. Filesystem, processes and users stay separate. It is the sidecar pattern, useful for debug and proxy containers.

open as a page

A container started with -p 5432:5432 turns out to be reachable from the public internet even though the host's ufw firewall denies port 5432. Explain why the host firewall did not stop it, and how you would fix the exposure properly.

level: seniorimportance: should knowfreq 48%

basics

~20 s

ufw rules live in the INPUT chain, but published container traffic is DNATed in PREROUTING and then traverses FORWARD, so INPUT is never consulted. Fix it by publishing to loopback only (-p 127.0.0.1:5432:5432), not publishing at all and using a shared network, or adding DROP rules in the DOCKER-USER chain.

open as a page

What does `docker network inspect` tell you when a container cannot reach the rest of its network?

level: seniorimportance: should knowfreq 46%

basics

~20 s

It answers attachment and addressing: the Containers map lists the running containers on that network on this host with their IPv4 addresses, IPAM.Config gives the subnet and gateway, and Internal reveals a network with no outside route. A missing container is the finding.

open as a page

How do you plan Docker's container address space across a fleet of hosts on a corporate network?

level: principalimportance: should knowfreq 33%

basics

~20 s

Agree one private block the organisation does not route, express it as default-address-pools and bip in a daemon.json shipped by configuration management, and reuse it on every host: bridge addresses are host-local and NAT'd, so they need not be unique.

open as a page

You are designing the Docker network layout for a multi-tier application on a single host: a public-facing reverse proxy, an internal API, and a database. How do you arrange networks so the database is reachable only by the API, what does attaching one container to two networks buy you, and how does Docker's --internal network option fit in?

level: principalimportance: should knowfreq 36%

basics

~20 s

Use one network per trust boundary: edge (proxy + API) and data (API + database). The API is multi-homed on both; the proxy never joins data, so it cannot reach the database at all. Publish ports only on the proxy. Mark the data network --internal to remove its external route. Networks, not published ports, are the boundary.

open as a page

On docker network create, what do the --ip-range and --aux-address flags do beyond --subnet?

level: middleimportance: nice to knowfreq 20%

basics

~20 s

In docker network create, --subnet declares the whole address block, --ip-range narrows the slice Docker's IPAM may hand out automatically, leaving the remainder free for manual assignment, and --aux-address reserves individual addresses inside the subnet that Docker must never allocate.

open as a page

Container A publishes port 8080 on the Docker host. Container B, attached to a user-defined bridge network, tries to reach A by connecting to the host's IP address on port 8080. Does that work, what is the term for that traffic pattern, and what should B do instead?

level: middleimportance: nice to knowfreq 34%

basics

~20 s

It usually works, going out to the host and back in through the NAT rules; that loop is called hairpin traffic. It is wasteful and fragile: it depends on the host address, loses the real source IP and breaks if the mapping changes. B should join A's network and connect to A's container port directly, with no published port involved.

open as a page

When would you attach containers to a physical LAN using Docker's `macvlan` or `ipvlan` driver instead of a bridge, and what problems do those drivers introduce?

level: seniorimportance: nice to knowfreq 24%

basics

~20 s

Use them when a container must appear as a first-class device on the physical LAN - its own IP (and, for macvlan, its own MAC), reachable inbound with no NAT or port publishing. Costs: the host usually cannot talk to its own macvlan containers, the parent NIC must accept extra MAC addresses (blocked on most clouds and Wi-Fi), and IP allocation must be coordinated with the LAN.

open as a page