skip to content

IPAM & Subnet Exhaustion

How Docker hands out addresses: the 172.17.0.0/16 docker0 default, the pools it carves user-defined networks from, and the flags that override them. Asked because a bridge subnet colliding with the corporate VPN, or a host with no pools left, is a real outage.

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

questions

5

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

level: middleimportance: must knowfreq 62%

answer

  1. One private range, chosen for you
  2. The host end of the bridge is the gateway
  3. A list of candidate ranges, tried in order
  4. 172.17 is only the first entry
  5. About thirty-one networks before it runs dry

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.

solid answer

~40 s

On a fresh Linux install the daemon creates a bridge interface named `docker0` and gives it 172.17.0.0/16, with 172.17.0.1 on the host side acting as the containers' gateway. Containers attached to it get the next free address in that /16 from the daemon's built-in IPAM driver. When you run `docker network create`, the daemon does not invent a range: it walks a predefined list of candidate pools and takes the first one that does not overlap anything already in use, either by another Docker network or by a route on the host. That list is 172.17.0.0/16 to 172.31.0.0/16, then 192.168.0.0/16 divided into /20s, so roughly 31 networks before the list is empty and creation fails. Container addresses are ephemeral: they are released on stop and reallocated on start.

code

bash · 4 lines
bash
docker network inspect bridge -f '{{range .IPAM.Config}}{{.Subnet}} gw {{.Gateway}}{{end}}'
docker network create checkout-net
docker network inspect checkout-net -f '{{range .IPAM.Config}}{{.Subnet}} gw {{.Gateway}}{{end}}'
ip addr show docker0

go deeper

for a junior

Be ready to state that docker0 defaults to 172.17.0.0/16 and that containers get private addresses from that range, handed out by Docker itself rather than by a DHCP server on your office network.

for a middle

Explain the two levels of allocation — a subnet per network, an address per container — and name the predefined pool list that user-defined networks are carved from, including why the first network you create usually lands on 172.18.0.0/16.

for a senior

Show that you know the pool list is finite and checked against the host's routing table at allocation time, and connect that directly to the two field failures it causes: collisions with routed corporate ranges and outright exhaustion on long-lived hosts.

for a principal

Own the consequence: defaults that were chosen years ago are now a fleet-wide risk, so container addressing should be a deliberate, config-managed decision rather than whatever the daemon picks on first boot.

### The two things being allocated Docker's IPAM (IP address management) works at two levels, and interviews usually want both. The first level is the **subnet given to a network**: a whole CIDR block reserved for one Docker network. The second is the **individual address given to a container** when it attaches to that network. The built-in `default` IPAM driver in the daemon does both, entirely on the local host, with no coordination with anything else on the LAN. ### The default bridge When dockerd starts for the first time on Linux it creates a Linux bridge interface called `docker0` and assigns it **172.17.0.0/16**, taking **172.17.0.1** for the host end. You can see it with `ip addr show docker0`. Every container started without a `--network` flag lands on that bridge and is handed an address inside that /16 — 172.17.0.2, then .3, and so on. The container's default route points at 172.17.0.1, which is how its outbound traffic leaves the host. That range is not special or reserved by any standard beyond being inside RFC 1918 private space. Docker simply picked it, and picked it a long time ago, which is exactly why it collides with corporate networks that also picked something in 172.16.0.0/12. ### The pool list for created networks `docker network create checkout-net` with no `--subnet` has to come up with a block from somewhere. The daemon keeps an ordered list of **predefined address pools** and allocates the first candidate that does not overlap: - 172.17.0.0/16, 172.18.0.0/16, … 172.31.0.0/16 — fifteen /16 blocks - 192.168.0.0/20, 192.168.16.0/20, … 192.168.240.0/20 — sixteen /20 blocks Because 172.17.0.0/16 is already taken by `docker0`, the first network you create typically lands on 172.18.0.0/16, the next on 172.19.0.0/16, and so on. Add up what is left and you get about **31 concurrent networks** on a default host — a number worth remembering, because it is small enough to hit on a busy CI machine. "Does not overlap" is checked against more than Docker's own networks. The daemon also looks at the host's routing table, so a range your VPN or a physical interface already routes is normally skipped. That check is best-effort and happens at allocation time, which is why a VPN that connects *after* the network was created can still collide. ### Per-container addresses Within a network's subnet the IPAM driver hands out the next free host address. The first usable address is normally taken by the gateway (the bridge interface on the host), so containers start one above it. The allocation is **not sticky**: stop a container and its address goes back to the pool; start it again and it may get a different one, especially if something else started in between. Never hardcode a container IP anywhere — that is what names and network aliases exist for. If you genuinely need a fixed address, create the network with an explicit `--subnet` and start the container with `docker run --ip`; a fixed address is only accepted on a user-defined network whose subnet you chose yourself. ### Inspecting what you actually got `docker network inspect <name>` shows the allocation under `IPAM.Config` — the subnet and the gateway — and each attached container's address under `Containers`. A compact form: ``` docker network inspect bridge -f '{{range .IPAM.Config}}{{.Subnet}} gw {{.Gateway}}{{end}}' ``` Run that against `bridge` (the network name of `docker0`) and against a network you created, and the two-level scheme becomes obvious immediately. ### Why this matters Three production problems fall straight out of these defaults. First, **collision**: a host whose containers sit on 172.18.0.0/16 cannot reach a corporate service on 172.18.0.0/16, because the local, more specific route wins. Second, **exhaustion**: a machine that accumulates networks faster than it removes them eventually cannot create any, and the failure message is about address pools, not about disk or memory. Third, **surprise addressing**: because the pools are chosen in order, the same compose project can land on a different subnet on a different machine, which breaks anything that assumed the address rather than the name. All three are configuration problems, not bugs. The daemon exposes `bip` for `docker0`'s own subnet and `default-address-pools` for the list above, both in `/etc/docker/daemon.json`, and `docker network create --subnet` for pinning one network by hand.

  • Does a container keep the same IP address across a stop and a start?
    No. The address is released back to the network's pool when the container stops and a fresh one is allocated when it starts, so it can change — particularly if another container started in between. Treat container addresses as ephemeral and reach containers by name or alias. If you truly need a fixed address, create the network with an explicit `--subnet` and pass `docker run --ip`, which the daemon accepts only on a user-defined network.
  • How does Docker decide a candidate pool is unusable before it allocates it?
    It checks the candidate against the subnets already assigned to other Docker networks and against the host's routing table, and skips anything that overlaps. That is why a range your VPN already routes is usually avoided. The check happens at allocation time only, so a VPN or a route that appears after the network was created will not cause the network to move — the collision simply appears.
  • Roughly how many networks can a default Docker host create, and what limits it?
    About 31: fifteen /16 blocks from 172.17.0.0/16 through 172.31.0.0/16, plus sixteen /20 blocks carved out of 192.168.0.0/16. The limit is the built-in pool list, not memory or interface count. Once the list is exhausted, `docker network create` fails complaining that no available, non-overlapping IPv4 address pool could be found. Raising the ceiling means configuring `default-address-pools` in the daemon's configuration.

saying these in an interview costs you the question

  • Thinks containers get public or DHCP addresses from the LAN
  • Believes Docker picks a random subnet at every boot
  • Assumes a container keeps its IP across restarts
  • Says the pool list is unlimited
  • Confuses docker0's own address with a container address
  • Claims the subnet is fixed and cannot be changed

context

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 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

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

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