Series on Docker in Practice & Production - Network in Docker

Series on Docker in Practice & Production - Network in Docker

Problem

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.

Network drivers

Docker provides several network drivers for different use cases:

  • Bridge: This is the default driver when creating a network if you don't specify a driver. It allows containers to communicate with each other if they are part of the same network.
  • Host: This driver allows containers to directly use the host's network. In other words, containers using this driver won't use Docker's network, but the host's network instead.
  • Overlay: This driver connects multiple Docker hosts together through Docker Swarm, allowing containers within those hosts to communicate with each other.
  • None: As the name suggests, this driver isolates your containers from the internet.

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.

Creating a network

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.

Using drivers in different scenarios

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:

Deploying independent containers

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.

What if I want containers to use the Docker host's network?

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.

What about containers in Docker Compose?

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

Lastly, what's different about overlay?

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.

Summary

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.

or
* The summary newsletter is sent every 1-2 weeks, cancel anytime.
Author

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.

Did you find this article helpful?
NoYes

Comments (0)