Back to Scaling Containers guides

Understanding Docker Networks: A Comprehensive Guide

Ayooluwa Isaiah
Updated on March 17, 2025

While containers excel at isolating applications, most modern systems require communication between containers and with external networks. Docker networks provide the essential infrastructure for this communication, enabling containers to interact with each other and the outside world in controlled, secure ways.

Docker's networking capabilities allow you to create complex, multi-container applications with clearly defined communication paths.

This tutorial will guide you through Docker's networking concepts, different network types, and practical patterns for implementation in real-world scenarios.

The fundamentals of container networking

At its core, Docker networking is about connecting containers to each other and to external systems. Without proper networking, containers would operate in isolation, which defeats the purpose of microservice architectures where different components need to interact.

When Docker runs a container, it places the container in a specific network environment. By default, containers can make outbound connections to the internet, but external systems and other containers cannot connect to them unless explicitly configured to do so. This design provides security through isolation by default, with selective exposure where needed.

Docker implements networking using network namespaces, a Linux kernel feature that creates isolated network stacks. Each container gets its own network namespace, complete with its own routing tables, firewall rules, and network interfaces. This isolation ensures that container networks don't interfere with each other or with the host system.

Docker network drivers

Docker provides several built-in network drivers, each designed for specific use cases. Understanding these drivers is crucial for selecting the right networking approach for your applications.

Bridge networks

The bridge network driver is Docker's default networking mode. When you install Docker, it automatically creates a default bridge network named "bridge" (also called "docker0"). Unless specified otherwise, new containers connect to this network.

A bridge network creates a virtual bridge on the host machine, connecting all containers on that network. Containers on the same bridge network can communicate with each other using their IP addresses, but they're isolated from containers on different networks.

Here's how to create a custom bridge network:

 
docker network create --driver bridge my_custom_network

To run a container on this network:

 
docker run -d --name web_server --network my_custom_network nginx

Bridge networks provide a good balance of isolation and connectivity for most container deployments.

Host networks

With the host network driver, a container shares the host's networking namespace. This means the container uses the host's IP address and port space directly, without any network isolation.

To use the host network:

 
docker run -d --name web_server --network host nginx

This approach offers the best network performance since it eliminates the network address translation (NAT) layer and other overhead. However, it reduces container isolation and can lead to port conflicts if multiple containers need the same ports.

None networks

The "none" network driver provides the highest level of network isolation by giving containers no external network interface beyond the loopback interface (localhost).

 
docker run -d --name isolated_container --network none alpine sleep infinity

A container with no network can't communicate with other containers or the external world. This is useful for containers that need to process data locally without network access, providing maximum security isolation.

Overlay networks

Overlay networks enable communication between containers running on different Docker hosts, essential for multi-host Docker Swarm deployments.

 
# Initialize a swarm first (on the manager node)
docker swarm init

# Create an overlay network
docker network create --driver overlay my_overlay_network

Overlay networks encapsulate container traffic in VXLAN packets, allowing containers across multiple hosts to communicate as if they were on the same local network. They're transparent to the containers but add some network overhead.

Macvlan networks

Macvlan networks assign a MAC address to each container, making them appear as physical devices on your network. This allows containers to be directly connected to the physical network, with their own MAC and IP addresses.

 
docker network create -d macvlan \
 --subnet=192.168.1.0/24 \
 --gateway=192.168.1.1 \
 -o parent=eth0 \
 my_macvlan_network

Macvlan is ideal when containers need to appear as separate physical devices on your network, particularly for applications that monitor network traffic or need to receive broadcasts.

Network management commands

Docker provides a robust set of commands for managing networks. You can create networks with specific drivers and options:

 
docker network create --driver bridge \
 --subnet=172.18.0.0/16 \
 --gateway=172.18.0.1 \
 my_network

This creates a bridge network with a specified subnet and gateway.

To see all networks on your Docker host, run:

 
docker network ls
Output
NETWORK ID     NAME               DRIVER    SCOPE
7b369448a044   bridge             bridge    local
615e9a7b9421   host               host      local
cba62d0d8c2c   my_custom_network  bridge    local
f4bd3d0bbac5   my_network         bridge    local
70f998968268   none               null      local

For detailed information about a network, execute:

 
docker network inspect my_network
Output
[
   {
       "Name": "my_network",
       "Id": "f4bd3d0bbac5e664a9841052905e3364c8fe5da1d8055df42b9f8c72b6c7e2b3",
       "Created": "2023-03-17T10:43:21.648303237Z",
       "Scope": "local",
       "Driver": "bridge",
       "EnableIPv6": false,
       "IPAM": {
           "Driver": "default",
           "Options": {},
           "Config": [
               {
                   "Subnet": "172.18.0.0/16",
                   "Gateway": "172.18.0.1"
               }
           ]
       },
       "Internal": false,
       "Attachable": false,
       "Ingress": false,
       "ConfigFrom": {
           "Network": ""
       },
       "ConfigOnly": false,
       "Containers": {},
       "Options": {},
       "Labels": {}
   }
]

This output shows the network's configuration details, connected containers, and other properties.

You can also remove a network when it's no longer needed with:

 
docker network rm my_network

Finally, you can clean up unused networks by running:

 
docker network prune
Output
WARNING! This will remove all custom networks not used by at least one container.
Are you sure you want to continue? [y/N] y
Deleted Networks:
my_custom_network
my_network

Connecting containers to networks

There are multiple ways to connect containers to networks in Docker. The most common approach is to specify the network when creating the container:

 
docker run -d --name web_app --network my_network nginx

You can also connect an existing container to a network:

 
docker network connect my_network existing_container

Or to multiple networks simultaneously:

 
docker run -d --name multi_network_container --network first_network nginx
docker network connect second_network multi_network_container

This is useful for creating layered security models or for containers that need to interact with multiple isolated groups of services.

To remove a container from a network:

 
docker network disconnect my_network multi_network_container

The container remains running but can no longer communicate with other containers on that network.

Container network discovery

For containers to communicate, they need a way to find each other. Docker provides two main methods for network discovery.

1. IP addressing

Every container on a Docker network receives an IP address. You can find a container's IP address:

 
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' web_app
Output
172.18.0.2

While this works, IP addresses are dynamically assigned and can change when containers restart, making them unreliable for long-term communication.

2. DNS resolution

Docker provides automatic DNS resolution for containers on the same network. Each container can be reached by its name or container ID.

For example, if you have two containers named "web" and "db" on the same network, the "web" container can connect to the "db" container simply by using "db" as the hostname.

 
# Start a database container
docker run -d --name db --network my_network postgres:14

# Start a web container and connect to the database using the container name
docker run -d --name web --network my_network \
 -e "DATABASE_URL=postgres://postgres:postgres@db:5432/postgres" \
 my-web-application

This automated name resolution is one of Docker's most powerful networking features, especially for multi-container applications.

Port publishing

While containers on the same network can communicate with each other directly, external access to containers requires port publishing.

To make a container's service accessible from outside Docker, you need to publish its ports to the host:

 
docker run -d --name web_server -p 8080:80 nginx

This maps port 80 in the container to port 8080 on the host. External systems can now connect to your host's IP address on port 8080 to reach the container's service.

You can also publish to a specific host interface:

 
docker run -d --name web_server -p 127.0.0.1:8080:80 nginx

This only allows connections from the local machine, enhancing security for development or internal services.

If you don't need a specific port on the host, Docker can assign one randomly:

 
docker run -d --name web_server -P nginx

The -P flag publishes all exposed ports to random high-numbered ports on the host. You can find out which ports were assigned:

 
docker port web_server
Output
80/tcp -> 0.0.0.0:49153

Networking with Docker Compose

Docker Compose simplifies networking for multi-container applications with a declarative approach.

By default, Docker Compose creates a single network for your application, and all services defined in your compose.yaml file join this network automatically.

compose.yaml
services:
 web:
   image: nginx
   ports:
     - "8080:80"

 api:
   image: my-api-service

 db:
   image: postgres:14
   environment:
     POSTGRES_PASSWORD: example

With this configuration, the web service can communicate with api and db using their service names as hostnames.

You can also define custom networks in Docker Compose for more complex scenarios:

 
version: '3.8'

services:
 web:
   image: nginx
   networks:
     - frontend
   ports:
     - "8080:80"

 api:
   image: my-api-service
   networks:
     - frontend
     - backend

 db:
   image: postgres:14
   networks:
     - backend
   environment:
     POSTGRES_PASSWORD: example

networks:
 frontend:
   driver: bridge
 backend:
   driver: bridge
   internal: true

In this example:

  • The frontend network connects the web frontend to the API.
  • The backend network connects the API to the database.
  • The backend network is marked as internal, meaning it has no access to the external network, adding a layer of security.

Network security considerations

Proper network configuration is crucial for container security. Here are some best practices to follow:

Isolating sensitive services

Use separate networks to isolate sensitive services:

 
version: '3.8'

services:
 web:
   image: nginx
   networks:
     - public
   ports:
     - "80:80"

 api:
   image: my-api-service
   networks:
     - public
     - private

 db:
   image: postgres:14
   networks:
     - private
   environment:
     POSTGRES_PASSWORD: example

networks:
 public:
   driver: bridge
 private:
   driver: bridge
   internal: true

The database is only accessible from the API service and has no direct connection to the public network or the web service.

Using internal networks

For services that don't need internet access, use internal networks:

 
docker network create --internal secure_network
 
docker run -d --name protected_db --network secure_network postgres:14

This prevents the database container from initiating connections to the internet, reducing the attack surface.

Network encryption

For sensitive data transmission between Docker hosts, enable encryption on overlay networks:

 
docker network create --driver overlay --opt encrypted my_secure_overlay

This encrypts all container-to-container traffic across hosts, protecting your data in transit.

Advanced networking patterns

Let's explore some advanced networking patterns and use cases.

Load balancing with Docker Swarm

Docker Swarm provides built-in load balancing for services:

 
# Initialize a swarm
docker swarm init

# Create a service with multiple replicas
docker service create --name web \
 --network my_overlay_network \
 --replicas 3 \
 -p 80:80 \
 nginx

Docker automatically load balances incoming connections across all replicas of the service.

Service discovery in multi-host environments

In Docker Swarm, service discovery works across hosts automatically:

 
# Create a frontend service
docker service create --name frontend \
 --network my_overlay_network \
 -p 80:80 \
 my-frontend-app

# Create a backend service
docker service create --name backend \
 --network my_overlay_network \
 my-backend-app

The frontend service can connect to the backend service using the service name "backend" regardless of which host the containers are running on.

Custom DNS configuration

For more complex DNS needs, you can provide custom DNS configurations:

 
docker run -d --name custom_dns \
 --dns 8.8.8.8 \
 --dns-search example.com \
 nginx

This configures the container to use Google's DNS server (8.8.8.8) and automatically search the example.com domain for unqualified hostnames.

Troubleshooting Docker networks

Network issues can be challenging to diagnose. Here are some common troubleshooting techniques.

Checking network connectivity

To verify if containers can communicate, use the ping command from inside a container:

 
docker exec -it web_container ping db_container
Output
PING db_container (172.18.0.3): 56 data bytes
64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.096 ms
64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.075 ms
^C

Inspecting container networking

For detailed network information about a container:

 
docker inspect -f '{{json .NetworkSettings.Networks}}' web_container | jq
Output
{
 "my_network": {
   "IPAMConfig": null,
   "Links": null,
   "Aliases": [
     "8ec8a37d91f5"
   ],
   "NetworkID": "f4bd3d0bbac5e664a9841052905e3364c8fe5da1d8055df42b9f8c72b6c7e2b3",
   "EndpointID": "4921db32c813b1b7660941a7c646a92c2138a1c4dd95714e5f76a43b654spzr",
   "Gateway": "172.18.0.1",
   "IPAddress": "172.18.0.2",
   "IPPrefixLen": 16,
   "IPv6Gateway": "",
   "GlobalIPv6Address": "",
   "GlobalIPv6PrefixLen": 0,
   "MacAddress": "02:42:ac:12:00:02",
   "DriverOpts": null
 }
}

Debugging with network tools

Sometimes you need to run network diagnostic tools inside a container:

 
docker run --rm -it --network my_network nicolaka/netshoot

The nicolaka/netshoot image contains numerous networking tools for troubleshooting Docker networks.

Checking DNS resolution

To test DNS resolution within a container:

 
docker exec -it web_container nslookup db_container
Output
Server:    127.0.0.11
Address 1: 127.0.0.11

Name:      db_container
Address 1: 172.18.0.3

Final thoughts

Docker networking provides a flexible, powerful framework for container communication. From simple single-host deployments to complex multi-host architectures, Docker's networking capabilities can accommodate a wide range of use cases.

Understanding the different network drivers and their properties allows you to design secure, efficient container networks. By leveraging features like automatic DNS resolution, custom networks, and multi-network connections, you can create sophisticated containerized applications with clean separation of concerns and proper security boundaries.

For most applications, start with bridge networks for single-host deployments and overlay networks for multi-host scenarios. Use DNS-based service discovery rather than hard-coded IP addresses, and implement proper network isolation to enhance security. With these principles in mind, you can build container networks that support your applications' communication needs while maintaining security and performance.

Author's avatar
Article by
Ayooluwa Isaiah
Ayo is a technical content manager at Better Stack. His passion is simplifying and communicating complex technical ideas effectively. His work was featured on several esteemed publications including LWN.net, Digital Ocean, and CSS-Tricks. When he's not writing or coding, he loves to travel, bike, and play tennis.
Got an article suggestion? Let us know
Next article
Best Practices for Building Docker Images
Licensed under CC-BY-NC-SA

This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.

Make your mark

Join the writer's program

Are you a developer and love writing and sharing your knowledge with the world? Join our guest writing program and get paid for writing amazing technical guides. We'll get them to the right readers that will appreciate them.

Write for us
Writer of the month
Marin Bezhanov
Marin is a software engineer and architect with a broad range of experience working...
Build on top of Better Stack

Write a script, app or project on top of Better Stack and share it with the world. Make a public repository and share it with us at our email.

community@betterstack.com

or submit a pull request and help us build better products for everyone.

See the full list of amazing projects on github