One of the reasons that Docker has become powerful is its networking system, which allows containers to easily connect with each other, regardless of whether they are running in a Docker environment or on different Docker platforms like Linux, Windows, or MacOS. To understand this in more detail, let's dive into the topic of networking in Docker.
Docker provides several network drivers for different use cases:
In addition, there are also macvlan and third-party plugins, but we won't cover them in this article. If you're interested, you can explore them on the Docker website.
Docker provides commands to easily create a network.
$ docker network create -d bridge estacks-network --attachable
Here, I have created a network called "estacks-network" with the bridge driver. The -d
flag allows me to specify the driver Docker supports, and --attachable
allows containers to manually connect to the network using commands.
To create a new container and specify its connection to the network:
$ docker run --network estacks-network --name nginx -d nginx
To connect an existing container to the network:
$ docker network connect estacks-network mysql
Here, "mysql" is the name of the container.
There are many more commands that I cannot list here, but you can refer to the Docker network documentation for more details and usage.
One thing is certain: for containers to communicate with each other, they must be part of the same network. "Communication" here refers to their ability to exchange data. Therefore, if you encounter connectivity issues while deploying your application, you should check if there are any network problems.
There are several ways to deploy containers and enable them to communicate with each other. Here are a few approaches that I often use:
For example, if you simply want to run a MySQL container as a database for your development environment, you can use the docker run
command:
$ docker run --name mysql -d mysql
When no network is specified, the container will default to the bridge
network, and it will be assigned a fixed IP address within that network. Any container running in the bridge network will be able to call each other using their IP addresses:
$ docker inspect mysql
{
...
"NetworkSettings": {
...
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "22a978aa722c09d9636cfcc4e6dedb4c788cf839421201a00a004596e812f0e1",
"EndpointID": "a72743fdd788e759ed3358d3dd043122be08d5f5dcc8cd20144e55d7161f433c",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.3",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:03",
"DriverOpts": null
}
}
}
}
Tip: Use the docker inspect
command to view detailed information about a container.
As you can see from the above example, the MySQL container has an IP address of 172.17.0.3
. Now, let's say I want to create another container, nginx, also using the bridge
network. I will access that container and try to ping the address 172.17.0.3
to see if it receives any response:
$ docker run -d --name nginx nginx
$ docker exec -it nginx bash
root@02d4d43a19fd:/# ping 172.17.0.3
PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data.
64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.045 ms
64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.038 ms
64 bytes from 172.17.0.3: icmp_seq=3 ttl=64 time=0.035 ms
64 bytes from 172.17.0.3: icmp_seq=4 ttl=64 time=0.035 ms
^C
--- 172.17.0.3 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 115ms
rtt min/avg/max/mdev = 0.035/0.038/0.045/0.006 ms
As you can see, because they are both part of the bridge
network, they can communicate with each other if the IP address is known.
However, these containers can only call each other if they are part of the same network. If I try to ping MySQL from the terminal, I won't receive any response. Why? Because my terminal is not connected to Docker's bridge
network. To achieve that, Docker provides a mechanism that you might already know, which is to expose the port of the MySQL container externally. In simple terms, that means mapping the port of MySQL to a different port on the host, so we can connect to the container through that port.
$ docker run -d --name mysql2 -p 3306:3307 mysql
$ telnet localhost 3307
The -p 3306:3307
flag denotes exposing the port 3306 of the container to port 3307 of the host. Port 3307 will be the port to communicate with MySQL inside the container. Now, I can use the MySQL server through localhost:3307
.
Instead of using the -p
flag to expose individual ports in Docker, I can run containers on the host. When a container is specified to run on the host, it won't be bound by Docker's network anymore. For example:
$ docker run --network host --name mysql -d mysql
In the terminal, I try to telnet to port 3306:
$ telnet localhost 3306
Trying ::1...
Connected to localhost.
Escape character is '^]'.
Docker for Windows or MacOS actually runs inside a Linux virtual machine, so when using the host
option, Docker uses the network of that virtual machine. Therefore, if you are using Windows and want to telnet to the MySQL container while using "localhost," it won't work:
$ telnet localhost 3306
Trying ::1...
telnet: connect to address ::1: Connection refused
Instead of using "localhost," you can try using the IP address of the running Docker virtual machine.
I have written an article about Docker Compose for orchestrating multiple services.
In the docker-compose.yml
file, you'll notice that each service needs to be part of the networks
section. This networks
section is not limited, and you can connect services to each other as you wish, as long as they are part of the same network. The networks declared in the docker-compose.yml
will exist within that stack. In other words, when you start the compose, the network will be created, and when you shut down the compose, the network will be destroyed. You can also create a network first and join the services to that network.
$ docker network create my-network -d bridge --attachable
The -d bridge
flag specifies creating a network with the bridge driver, and --attachable
allows containers to join manually. Refer to the docker create command documentation for more details.
In the docker-compose.yml
:
version: "3.9"
services:
mysql:
...
networks:
- my-network
...
...
networks:
my-network:
external: true
When Docker is deployed in swarm mode, each node may have different IP addresses. To simplify communication between containers on different nodes, Docker provides the overlay driver.
In simple terms, if containers on different nodes are part of the same overlay network, they can communicate with each other.
If you're not familiar with Docker swarm, don't worry—I have planned the next article in this series to cover that topic.
Networking in Docker makes it easy for containers to communicate with each other because containers are independent entities. Docker also provides various network drivers to cater to different usage needs, such as bridge, host, overlay, and more. One crucial principle to remember in deployment and troubleshooting is that containers need to be part of the same network to communicate with each other.
Me & the desire to "play with words"
Have you tried writing? And then failed or not satisfied? At 2coffee.dev we have had a hard time with writing. Don't be discouraged, because now we have a way to help you. Click to become a member now!
Subscribe to receive new article notifications
Hello, my name is Hoai - a developer who tells stories through writing ✍️ and creating products 🚀. With many years of programming experience, I have contributed to various products that bring value to users at my workplace as well as to myself. My hobbies include reading, writing, and researching... I created this blog with the mission of delivering quality articles to the readers of 2coffee.dev.Follow me through these channels LinkedIn, Facebook, Instagram, Telegram.
Comments (0)