Default Docker network or your own: which to choose?
The default Docker bridge network resolves no container name. A network made with docker network create does, and isolates the others. Measured on Docker 29.
The issue opens pre-filled with this page title and URL.
A container started without any network option joins the default bridge network. It receives an IP address and can reach the outside thanks to an address translation, NAT. It reaches its neighbors by their address, but not by their name. A network you create yourself with docker network create changes two things. Container names resolve on it, and a container that is not part of it cannot reach it.
This page is for someone starting with Docker who wants an application made of two containers to find each other without writing an IP address into its configuration. It only covers the bridge network, on a single host (the machine that runs Docker). To publish a port to the outside, see publish a port. To cut a network off from the outside, see isolate a container from the network.
What you will learn
Read what the default bridge network gives a container: an address, a gateway, an exit through NAT
Check that a container name does not resolve on this network
Create a dedicated bridge network and attach containers to it with --network
Check name resolution, and the isolation of the containers left outside the network
Move a container with docker network connect and docker network disconnect
Read a network with docker network inspect
Tell the name of a Docker network from the name of the host interface, and link a gateway to its interface
Give a service a stable name with --network-alias, and check that this alias only holds on the network where it is set
Prerequisites
You need Docker installed (installing Docker), the basic commands run, exec, ps and rm (running a container) and the lesson publish a port, which explains what reaching a service from the host means. The commands are written for Docker Engine 29.9.2 and the alpine:3.24 image, whose busybox tools provide nc and ping.
What does the default bridge network give a container?
The default bridge network is a virtual switch that Docker creates at startup. It is called bridge, and the host sees it as an ordinary network interface. Every container that attaches to it receives an IP address taken from the network's range. The address of this interface serves as the containers' gateway, that is, their way out.
To reach the outside, a container's packets go through the host. The host applies a NAT rule (masquerade): it replaces the container's address with the host's, which lets the reply come back.
The diagram shows the default network on the left and a dedicated network on the right. Look first at who each container can address. On the default network, nothing translates names into addresses. The dedicated network embeds a small DNS service, a directory that translates a name into an IP address, and this service answers to the names of its members. Notice too that both networks leave through the same host NAT.
To see it, you start a listener and a second container that plays the client. The listener answers a fixed line to each connection on port 9100. It is an easy sign of life to read.
The third command queries the network itself. The --format option keeps only two values: the subnet, the range of addresses the network hands out, and the containers' gateway. In the output, the first two lines are the identifiers of the containers just created. The last line gives, on this machine, the range 172.17.0.0/16 and the gateway 172.17.0.1.
You then need the address of the phare container. Since Docker 29, the .NetworkSettings.IPAddress field no longer exists. The address is read under each network the container is attached to. The command below goes through all these networks, however many there are.
Here it is 172.17.0.2, just after the gateway. You will copy the address you get in place of ADRESSE.
Does the container really leave through NAT? Have vigie reach a public address. This command assumes the host has Internet access.
Terminal window
dockerexecvigieping-c11.1.1.1
PING 1.1.1.1 (1.1.1.1): 56 data bytes
64 bytes from 1.1.1.1: seq=0 ttl=54 time=17.107 ms
--- 1.1.1.1 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 17.107/17.107/17.107 ms
The line 1 packets received, 0% packet loss shows that the reply came back. The container has no public address. The reply reaches it because the host rewrote the source address on the way out, as a home router does.
Why does a container name not resolve on this network?
The default bridge network has no name service. Docker does not register the container's name there. A client looking for phare therefore queries the host's DNS servers, which do not know it. These servers are the ones listed in the /etc/resolv.conf file, where a Linux machine keeps the address of the name server to query. To reach a neighbor, you therefore have to know its IP address.
Reach phare from vigie in two ways, first by its address, then by its name. Replace ADRESSE with the one you just noted.
Terminal window
dockerexecvigienc-w3ADRESSE9100
dockerexecvigienc-w3phare9100
echo"code de nc = $?"
The first command must print the line from phare. The second must fail, unable to translate the name, and the code printed will not be 0.
mot=phare
nc: bad address 'phare'
code de nc = 1
Writing an IP address into a configuration is fragile: it can change as soon as the container is recreated. A dedicated network fixes this flaw. The default network has another: all the containers started without options end up there together, and each one can reach all the others by their address.
How do you create a network of your own?
You create it with docker network create, then attach each container as soon as it is created with the --network option. Here, you also choose the subnet with --subnet, to decide the addressing plan yourself. Without this option, Docker takes a free range of its own choice, and that range may overlap a company network.
A container started with --network vitrine is no longer on the default network. It is only on vitrine. docker network connect, presented below, acts differently: it adds a network and leaves the container on the previous ones.
On this network, name resolution works because Docker adds an embedded DNS. It is a small name server that listens at the address 127.0.0.11, inside each container of the network. It answers to the name given by --name. The first command below shows which name server the client uses. The second checks that the connection by name succeeds. The output is shortened: /etc/resolv.conf contains other lines, only the name server line is kept.
Terminal window
dockerexeccaissecat/etc/resolv.conf
dockerexeccaissenc-w3comptoir9100
nameserver 127.0.0.11
mot=comptoir
Look at the nameserver 127.0.0.11 line. The client no longer queries the host's servers, it queries the network's embedded DNS, which knows comptoir. The last line, mot=comptoir, is the listener's reply. The connection by name succeeded.
No port was published with -p. Two containers on the same network do not need one: they talk to each other directly on the port where the application listens. Publishing only serves to open the service to the outside of the network, which the lesson on publish a port covers.
What happens to a container that is not in the network?
A container that is not in the network is isolated. It does not reach the members of the dedicated network by name, because the network's DNS does not know it. Nor does it reach them by address, because Docker does not link two bridge networks together. This is the second half of the point of a network of your own: a tool started by mistake on the default network no longer sees the application.
Start a container on the default network, then try to reach comptoir in two ways.
The first command prints the identifier of the new container, the second the address of comptoir on vitrine. Use this address in place of ADRESSE_COMPTOIR below.
Now try to reach comptoir by its name, then by its address.
Terminal window
dockerexecpassantnc-w3comptoir9100
dockerexecpassantnc-w3ADRESSE_COMPTOIR9100
echo"code de nc = $?"
nc: bad address 'comptoir'
code de nc = 1
Neither attempt returns the line from comptoir. The first prints bad address: the name is unknown. The second prints nothing: nc gives up after 3 seconds without having been able to connect to 10.77.0.2. The code 1 is that of this second command, the last one run.
Both routes are tested for a reason: if only the attempt by name failed, you would not know whether the name or the route is missing. Here, neither is available.
How do you move a container from one network to another?
docker network connect adds an existing container to a network, without restarting it. docker network disconnect removes it from it. There is no "move" command: a move is a connect followed by a disconnect. A container can belong to several networks at the same time, with one address per network.
Terminal window
dockernetworkconnectvitrinepassant
dockerexecpassantnc-w3comptoir9100
dockernetworkdisconnectvitrinepassant
dockerexecpassantnc-w3comptoir9100
echo"code de nc = $?"
The first nc, run between the two network commands, must receive the line from comptoir. The second, run after the removal, must fail as it did at the start.
mot=comptoir
nc: bad address 'comptoir'
code de nc = 1
The trap lies in what connect does not do: it does not remove the container from its current networks. For a container of the default network to move to vitrine, also disconnect it from the first with docker network disconnect bridge <container>. Otherwise it stays on both networks, so it is reachable from the default network, and the isolation you thought you had set up does not exist.
How do you read a network with docker network inspect?
docker network inspect displays a network as JSON: its type (the driver), its subnet, its gateway, and the list of attached containers with their address. It is the first reflex when two containers do not see each other, because it tells you in one command who is a member of what.
Terminal window
dockernetworkinspectvitrine
The real output is about fifty lines long. It is shortened here to the two blocks that matter: IPAM.Config for the addressing plan and Containers for the members. The ... mark the omitted fields, and the container identifiers are truncated.
[
{
"Name": "vitrine",
"Driver": "bridge",
"IPAM": {
...
"Config": [
{
"Subnet": "10.77.0.0/24",
"Gateway": "10.77.0.1"
}
]
},
...
"Containers": {
"065684b29017...": {
"Name": "comptoir",
"IPv4Address": "10.77.0.2/24",
"IPv6Address": ""
},
"6a768dcedfd7...": {
"Name": "caisse",
"IPv4Address": "10.77.0.3/24",
"IPv6Address": ""
}
},
...
}
]
To keep only the essentials, pass --format a template, a small expression written in the Go language syntax, that goes through the list of members. It prints the name of each container and its address, which answers directly "who is on this network?".
docker network ls lists Docker's networks. You should find vitrine there, next to the three networks Docker creates on its own. The DRIVER column gives the type of network. bridge is the default network; host and none are two special cases this page does not use. To know which networks a container belongs to, see the NetworkSettings section in inspect a running container.
How do you link a network's gateway to the host interface?
The name of a Docker network and the name of a host interface are two different things. vitrine and bridge are names for Docker; the host only knows interfaces, with their own name. To go from one to the other, start from the gateway: it is the address the network's interface carries on the host. A first command reads the gateway on the Docker side, a second finds it again on the host side.
For a network you create, Docker names the interface br- followed by the first 12 characters of the network identifier. It is the identifier printed by docker network create and repeated in the NETWORK ID column of docker network ls. Replace the identifier below with your own.
Run the second command on the Linux host, not in a container, since it is the host you are querying. The ip command lists the interfaces there, and the -br option summarizes each one on a single line.
br-c651b12896e8 UP 10.77.0.1/24 fe80::a8b7:46ff:fe6c:575b/64
The first column of the second line is the interface name, the second its state, and the rest its addresses. 10.77.0.1/24 is indeed the gateway read by the first command.
This naming rule holds for the networks you create. Do not assume it for the default network. Read its gateway with the command given at the start of the page, then run ip -br addr, which lists all the host's interfaces, and look for the one whose addresses contain that gateway.
How do you give a service a stable name with a network alias?
A network alias is an additional name that a network's embedded DNS associates with a container, besides its name. It gives a service a stable name, independent of the container that provides it. The application aims at stock, and you can replace the entrepot container with another one without touching its configuration, as long as the new one carries the same alias.
You set the alias with --network-alias, at docker run time, next to --network.
Start entrepot with the alias stock, then ask caisse, which is on the same network, to resolve both names as an application would (getent hosts). The last docker inspect prints the aliases set by hand (Aliases) and all the names the network resolves for this container (DNSNames).
The container name and the alias return the same address. Aliases only contains stock. DNSNames adds the container name and a short identifier, which you can ignore.
An alias only resolves from the network where it is set. From passant, which left vitrine in the previous step and is only on the default network, the name stock does not resolve. The command prints nothing and returns the code 2.
Terminal window
dockerexecpassantgetenthostsstock
echo"code de getent = $?"
code de getent = 2
Several containers can carry the same alias. The resolver then returns all their addresses, each on two lines (STREAM and DGRAM designate two kinds of connection, only the address matters here). A shared alias is a list of addresses, not a load balancer: it is up to the client to choose which one it uses.
A network can only be deleted once it has no attached container left. Delete the containers first, then the networks. The deletion is limited to the names on this page, so as not to touch your other containers. If you skipped the box on the second network, remove relais and annexe from these commands.
The final list must no longer contain vitrine or annexe.
phare
vigie
comptoir
caisse
passant
entrepot
entrepot-bis
relais
vitrine
annexe
NETWORK ID NAME DRIVER SCOPE
b564d4a88292 bridge bridge local
b5b096dacd08 host host local
262c750bdafd none null local
Practice
The two labs in this lesson are played on a fresh virtual machine, with their own containers. The first validates what the default network gives and refuses: a container's address and gateway, the host interface that carries them, and a name that does not resolve while the connection by address succeeds. The second checks Docker's state once your commands have run: a network with the addressing plan requested, members that reach each other by name, and a container left outside that no longer reaches them.
Key points
The default bridge network gives every container an address, a gateway and an exit through NAT. It does not resolve names. You reach a neighbor there by its IP address, which changes when the container is recreated.
A network created with docker network createembeds a DNS that answers to container names, and a container cannot reach it until it is a member. You attach a container to it at creation with --network, and it is then no longer on the default network.
docker network connect adds a container to a network without removing it from the others, and docker network disconnect removes it from one. A container on two networks stays reachable from each of them. docker network inspect says who is a member of what, with which address.
The name of a Docker network is not the name of its interface on the host. For a network you create, the interface is called br- followed by the first 12 characters of the network identifier.
An alias set with --network-alias gives a service a stable name, independent of the container name. It only holds on the network where it is set.
Two containers on the same network talk to each other without publishing a port. A name that resolves does not prove that a connection succeeds: test by connecting.
Knowledge check
Check that the essentials of this guide stuck. The questions cover only what
has just been explained here.
Knowledge check
Check what you have learned with this interactive quiz
6 questions
6 min
70% to pass
How it works
The timer starts when you click Start
Multiple choice, true/false and short answer questions
You can move between questions
Detailed results are shown at the end
Starts the quiz and the timer
⏱️--:--
0 / 6
Review
(0/0)
--:--
0%
0Correct
0To review
0:00Time
-Level
Score by domain
A domain groups several guides and gets several questions, so its score is more reliable than a per-topic score, which often rests on a single question.
Summary
Strengths
No topic passed at 80% on at least two questions yet.