Docker Networking 101: User-defined Bridge Network

Photo by Nathan Cima on Unsplash

Docker Networking 101: User-defined Bridge Network

User-defined bridge networks in Docker offer several advantages over the default bridge network. They are a key part of Docker’s networking features that allow containers to communicate with each other and with the host system. Bridge networks created manually by the user, offering more control and flexibility compared to the default bridge network.

What is a User-Defined Bridge?

A user-defined bridge is a type of network in Docker that you create manually. It is different from the default bridge network that Docker provides automatically. User-defined bridge networks are superior to the defaultbridge network.

User-defined bridges provide automatic DNS resolution, better isolation, and customizable options.

Use the command docker network create <network-name> to create a new user-defined bridge network. When running this command Docker creates a virtual bridge on the host system and assigns it a subnet.

Automatic DNS resolution between containers

Containers on the default bridge network can only access each other by IP addresses, unless you use the --link option, which is considered legacy. On a user-defined bridge network, containers can resolve each other by name or alias.

Imagine an application with a web front-end and a database back-end. If you call your containers web and db, the web container can connect to the db container at db, no matter which Docker host the application stack is running on.

If you run the same application stack on the default bridge network, you need to manually create links between the containers (using the legacy --link flag). These links need to be created in both directions, so you can see this gets complex with more than two containers which need to communicate. Alternatively, you can manipulate the /etc/hosts files within the containers, but this creates problems that are difficult to debug.

Better Network isolation with user-defined bridges

All containers without a --network specified, are attached to the default bridge network. This can be a risk, as unrelated stacks/services/containers are then able to communicate.

If you do not specify a network using the --network flag, and you do specify a network driver, your container is connected to the default bridge network by default. Containers connected to the default bridge network can communicate, but only by IP address, unless they're linked using the legacy --link flag.

Using a user-defined network provides a scoped network in which only containers attached to that network are able to communicate.

Connecting Containers to the Network

During a container's lifetime, you can connect or disconnect it from user-defined networks on the fly. To remove a container from the default bridge network, you need to stop the container and recreate it with different network options.

This example connects a Nginx container to the my-net network. It also publishes port 80 in the container to port 8080 on the Docker host, so external clients can access that port. Any other container connected to the my-net network has access to all ports on the my-nginx container, and vice versa.

docker create --name my-nginx \
  --network my-net \
  --publish 8080:80 \
  nginx:latest

To connect a running container to an existing user-defined bridge, use the docker network connect command. The following command connects an already-running my-nginx container to an already-existing my-net network:

docker network connect my-net my-nginx

To disconnect a running container from a user-defined bridge, use the docker network disconnect command. The following command disconnects the my-nginx container from the my-net network.

docker network disconnect my-net my-nginx

Use docker network inspect to see detailed information about the network, including which containers are connected.

Use Cases

  • Multi-Container Applications: Group related containers within a network for easy communication and isolation from other applications.

  • Development and Testing: Create isolated networks for different environments or scenarios.

  • Microservices: For microservices architecture, different services can be isolated in different containers and connected via a user-defined bridge.

  • Segmented Networking: Separating different parts of an application (e.g., front-end, back-end, database) for better control and security.

  • Isolated Database Services: Running databases in containers and allowing only selected application containers to access them.

There is a connection limit for bridge networks. Due to limitations set by the Linux kernel, bridge networks become unstable and inter-container communications may break when 1000 containers or more connect to a single network. For more information about this limitation, see moby/moby#44973.

Workshop: Default and User-defined Bridge Networks

This workshop will guide you through the process of setting up and experimenting with both types of bridge networks default and user-defined.

In this workshop, you will learn how to:

  • Inspect and use the default Docker bridge network.

  • Create and use a user-defined bridge network.

  • Observe the differences in DNS resolution and network isolation between the two types of networks.

Prerequisites

💡
For the testing purposes you can boot up local Ubuntu 20.04 VM with already installed Docker daemon. To boot up the machine use Vagrant. Code files can be found here.

Part 1: Exploring the Default Bridge Network

Step 1: Inspect the Default Bridge Network

  1. Open a terminal.

  2. Run docker network ls to list all networks. You should see the default bridge network.

  3. Inspect the default bridge network: docker network inspect bridge

Step 2: Run Containers on Default Bridge Network

  1. Run a new container: docker run -dit --name container1 alpine ash

  2. Run another container: docker run -dit --name container2 alpine ash

Step 3: Test Communication and DNS

  1. Enter container1: docker exec -it container1 ash

  2. Try to ping container2 by name: ping container2. It should fail because DNS resolution is not supported in the default bridge.

Part 2: Setting Up a User-Defined Bridge Network

Step 1: Create a User-Defined Bridge

  1. Create a new bridge network: docker network create --driver bridge my_bridge

Step 2: Run Containers on User-Defined Bridge

  1. Stop previous containers (optional): docker stop container1 container2

  2. Run a new container on my_bridge:
    docker run -dit --name new_container1 --network my_bridge alpine ash

  3. Run another container on my_bridge:
    docker run -dit --name new_container2 --network my_bridge alpine ash

Part 3: Testing User-Defined Bridge

Step 1: Test Communication and DNS

  1. Enter new_container1:
    docker exec -it new_container1 ash

  2. Ping new_container2 by name: ping new_container2. It should succeed, showing DNS resolution works.

Step 2: Inspect User-Defined Bridge

  1. Inspect my_bridge: docker network inspect my_bridge

  2. Note the differences in configuration and connected containers compared to the default bridge.

Part 4: Cleanup

Step 1: Stop and Remove Containers

  1. Stop containers: docker stop new_container1 new_container2.

  2. Remove containers: docker rm new_container1 new_container2.

Step 2: Remove User-Defined Bridge

  1. Remove the bridge network: docker network rm my_bridge.

Step 3 (Optional): Destroy VM

Destroy VM machine: vagrant destroy

References:

  1. Differences between user-defined bridges and the default bridge

  2. The user-defined bridge network YouTube