How to Establish Communication Between Containers and the Host Machine
Cesar Diaz
May 7, 2020
Docker is great. We all know containers help simplify and automate the development and setup of an application environment. Let's explore how we can establish communication between containers and from the inside to the host machine.
First of all, we'll provide a little context. To understand how the process of communication works, we'll need to clarify some concepts first.
Docker Network
When you list the networks after a traditional installation of Docker and run the following command docker network ls
...
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
dbb52b9c258f bridge bridge local
0c35ae96fe77 host host local
cb85dfadb376 local_default bridge local
94431f37b012 none null local
...you might get the default in-built networks:
- Bridge
- Host
- None
Note: As you probably noticed, there is another one called local_default, which in this case is a user-defined bridge network.
A brief overview extracted from the current Docker documentation states:
Bridge network: The default network driver. If you don’t specify a driver, this is the type of network you are creating. Bridge networks are usually used when your applications run in standalone containers that need to communicate
Host network: Adds a container on the host’s network stack. As far as the network is concerned, there is no isolation between the host machine and the container. For instance, if you run a container that runs a web server on port 80 using host networking, the web server is available on port 80 of the host machine.
None network: Is generally known as container specific network. A container can be attached to a none network. This allows internal communication between containers that are isolated to outside networks. 1
Therefore, the network in charge of the communication process between containers is by default the bridge network or the user-defined bridge networks, so let’s focus on this type of network.
Bridge Networks
$ ifconfig bridge0
bridge0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
options=63<RXCSUM,TXCSUM,TSO4,TSO6>
ether 82:17:02:be:ed:00
Configuration:
id 0:0:0:0:0:0 priority 0 hellotime 0 fwddelay 0
maxage 0 holdcnt 0 proto stp maxaddr 100 timeout 1200
root id 0:0:0:0:0:0 priority 0 ifcost 0 port 0
ipfilter disabled flags 0x2
member: en1 flags=3<LEARNING,DISCOVER>
ifmaxaddr 0 port 5 priority 0 path cost 0
member: en2 flags=3<LEARNING,DISCOVER>
ifmaxaddr 0 port 6 priority 0 path cost 0
Address cache:
nd6 options=201<PERFORMNUD,DAD>
media: <unknown type>
status: inactive
When you start Docker, a default bridge network (also called bridge0
or docker0
) is created automatically, and newly-started containers connect to it unless otherwise specified. You can also create user-defined custom bridge networks. User-defined bridge networks are superior to the default bridge network.
In terms of Docker, a bridge network uses a software bridge which allows containers connected to the same bridge network to communicate, while providing isolation from containers which are not connected to that bridge network. The Docker bridge driver automatically installs rules in the host machine so that containers on different bridge networks cannot communicate directly with each other.
The communication would be established only if the bridge network is provided and the proper permissions on the iptables rules are given.
Ping Between Containers
To understand the communication between containers, let’s create two containers over the same network and make sure that they can see each other using a ping command.
- Create two containers.
$ docker run -d --name nginx1 -p 8001:80 nginx:latest
$ docker run -d --name nginx2 -p 8002:80 nginx:latest
- Create a custom network.
$ docker network create my-custom-net
$ docker network inspect my-custom-net
- List the networks. You should see a new network type bridge created.
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
dbb52b9c258f bridge bridge local
0c35ae96fe77 host host local
cb85dfadb376 my-custom-net bridge local
94431f37b012 none null local
- Connect the network with the containers.
docker network connect my-custom-net nginx1
docker network connect my-custom-net nginx2
- Inspect the network. You should see the containers attached to the network.
$ docker network inspect my-custom-net
[
{
"Name": "my-custom-net",
"Id": "cb85dfadb376cc7aa020410ee6c839137b6d5dedff7972b9eed0e37ec573b002",
"Created": "2020-04-09T20:26:42.897203Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.19.0.0/16",
"Gateway": "172.19.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]
- Before you try to make the ping, you should install
iputils-ping
in the container to make it work. So we enter into the container namednginx1
.
$ docker exec -ti nginx1 bash
root@39484307e6ee:/# apt update
root@39484307e6ee:/# apt install iputils-ping
- You’re ready to run a ping command.
docker exec -ti nginx1 ping nginx2
PING nginx2 (172.18.0.3) 56(84) bytes of data.
64 bytes from nginx2.my-custom-net (172.18.0.3): icmp_seq=1 ttl=64 time=0.224 ms
64 bytes from nginx2.my-custom-net (172.18.0.3): icmp_seq=2 ttl=64 time=0.093 ms
64 bytes from nginx2.my-custom-net (172.18.0.3): icmp_seq=3 ttl=64 time=0.082 ms
64 bytes from nginx2.my-custom-net (172.18.0.3): icmp_seq=4 ttl=64 time=0.081 ms
Connecting the Container to a Service Inside the Host
Docker allows you to have access to the host from the containers through a special DNS named host.docker.internal
.
You can run ping inside the container nginx1
. You will get a response with your current host IP
root@39484307e6ee:/# ping host.docker.internal
In a nutshell, we achieved a better understanding of how bridge networks in Docker make communication easier between containers in the same network. If required, we can connect our containers to any service on our host using the special host.docker.internal.
-
"Networking overview," Docker Docs. ↩
Recommendations for Using Docker
Docker has changed the way we develop software. Here are a few things that helped mitigate some common problems we ran into when we started our Docker journey.
Building Robust Systems with C# Interfaces
C# is a general-purpose, object-oriented programming language. In this post, we’ll explain the benefits of using C# interfaces to build robust systems and show how to implement them.
Photo by Miryam León.
Categorized under research & learning.Join our team
If you're passionate about building quality software and our values resonate with you, get in touch with us!