Introduction

In the previous chapters, we learned how to run individual Docker containers. However, real-world applications often consist of multiple services (e.g., a web server, a database, a cache) that need to communicate with each other. This is where Docker networking comes into play. Docker provides powerful networking capabilities that allow containers to communicate securely and efficiently, both with each other and with the outside world.

This chapter will delve into the fundamentals of Docker networking, exploring the different network drivers, how to create and manage custom networks, and best practices for connecting your containerized applications. Understanding Docker networking is crucial for building robust, scalable, and maintainable microservice architectures.

Main Explanation

Docker’s networking model is designed to be flexible and powerful, offering several drivers to suit different use cases.

Docker Network Drivers

Docker supports several network drivers, each with its own characteristics:

  • Bridge (Default): This is the default network driver. When you don’t specify a network, Docker creates a bridge network for your container. Containers on a bridge network can communicate with each other using their IP addresses, and Docker provides DNS resolution for container names within the same user-defined bridge network. They can also communicate with the host machine and the external world via NAT.
  • Host: For standalone containers, the host driver removes network isolation between the container and the Docker host. The container shares the host’s network stack, meaning it doesn’t get its own IP address and directly uses the host’s network interfaces. This can be faster but sacrifices isolation.
  • None: Containers using the none network driver are completely isolated from other containers and the host. They have no network interfaces and cannot communicate with anything. This is useful for containers that perform tasks not requiring network access.
  • Overlay: Overlay networks connect multiple Docker daemons together, enabling Swarm services to communicate even when running on different Docker hosts. This is essential for multi-host container orchestration.
  • Macvlan: Macvlan networks allow you to assign a MAC address to a container, making it appear as a physical device on your network. This can be useful for legacy applications or when you need full control over network addressing.

For most single-host applications, the bridge driver (especially user-defined bridge networks) is the most common and recommended choice.

User-Defined Bridge Networks

While Docker automatically creates a default bridge network, user-defined bridge networks offer significant advantages:

  • Automatic DNS Resolution: Containers connected to the same user-defined bridge network can resolve each other’s names (e.g., web-app can talk to database) without needing to know their IP addresses.
  • Better Isolation: User-defined networks provide better isolation than the default bridge network. Containers on different user-defined networks cannot communicate by default.
  • Portability: Applications using user-defined networks are more portable, as their networking configuration is self-contained.

Core Network Commands

Docker provides a set of commands to manage networks:

  • docker network ls: Lists all available networks on your Docker host.
  • docker network create [OPTIONS] NETWORK_NAME: Creates a new user-defined network.
    • --driver [DRIVER]: Specifies the network driver (e.g., bridge, overlay). Default is bridge.
  • docker network inspect NETWORK_NAME: Displays detailed information about a specific network, including connected containers and their IP addresses.
  • docker network connect NETWORK_NAME CONTAINER: Connects an existing container to a network.
  • docker network disconnect NETWORK_NAME CONTAINER: Disconnects a container from a network.
  • docker network rm NETWORK_NAME: Removes a user-defined network.

DNS Resolution within Docker Networks

When containers are connected to the same user-defined bridge network, Docker automatically registers their names in an internal DNS service. This allows containers to refer to each other by their service names rather than their dynamic IP addresses, simplifying configuration and making applications more resilient to IP changes.

For example, if you have a container named db and another named web, the web container can connect to the database using db:5432 (assuming the database runs on port 5432) without needing to know db’s IP address.

Port Mapping vs. Internal Networking

It’s important to distinguish between port mapping and internal networking:

  • Port Mapping (-p or --publish): This exposes a container’s port to the Docker host’s network. It allows external clients (outside the Docker host) or other containers on different networks to access a service running inside the container via the host’s IP and the mapped port.
  • Internal Networking: This refers to communication between containers on the same Docker network. This communication happens directly between containers using their internal IP addresses or service names, without needing to expose ports to the host. For services that only communicate with other services within the Docker network (e.g., a database backend), port mapping is often unnecessary and can be omitted for better security.

Examples

Let’s walk through an example of creating a network and connecting two services (a web application and a database) to it.

First, let’s list existing networks:

docker network ls

You’ll typically see bridge, host, and none by default.

Now, let’s create a user-defined bridge network for our application:

docker network create my-app-network

Next, we’ll run a PostgreSQL database container and connect it to my-app-network. We won’t publish any ports to the host, as it will only be accessed by our web app internally.

docker run -d \
  --name my-db \
  --network my-app-network \
  -e POSTGRES_PASSWORD=mysecretpassword \
  postgres:13

Verify the database container is running and connected to the network:

docker inspect my-db | grep -i "network" -A 5

You should see an entry for my-app-network under Networks.

Now, let’s run a simple Nginx web server container, also connecting it to my-app-network. This time, we’ll map port 80 of the container to port 8080 on the host so we can access it from our browser.

docker run -d \
  --name my-web \
  --network my-app-network \
  -p 8080:80 \
  nginx:latest

At this point, my-web and my-db can communicate using their container names. For instance, if my-web were a Node.js application, it could connect to the database using the hostname my-db and port 5432.

To demonstrate this, let’s connect to the my-web container and try to ping my-db:

docker exec -it my-web bash

Once inside the my-web container’s shell:

ping my-db

You should see successful ping responses, demonstrating that my-web can resolve my-db’s name and communicate with it.

Exit the my-web container:

exit

Finally, clean up the containers and network:

docker stop my-web my-db
docker rm my-web my-db
docker network rm my-app-network

Mini Challenge

Challenge: Create a custom bridge network named dev-env-network. Run two ubuntu containers, container-a and container-b, both connected to dev-env-network. Install ping in container-a and then verify that container-a can successfully ping container-b by its name.

  1. Create the network.
  2. Run container-a (detached, with a name, connected to the network).
  3. Run container-b (detached, with a name, connected to the network).
  4. Execute a command inside container-a to install iputils-ping.
  5. Execute a command inside container-a to ping container-b (by name).
  6. Clean up containers and network.

Summary

Docker networking is a fundamental aspect of building multi-service applications with Docker. We’ve explored the various network drivers, with a focus on the powerful capabilities of user-defined bridge networks for single-host deployments. You now understand how to create, inspect, and manage Docker networks, and how containers can leverage automatic DNS resolution for seamless communication. By correctly configuring your network, you ensure that your containerized services can interact efficiently and securely, laying the groundwork for more complex, distributed applications.