E-NO
Docker Networking local lab 9 Min Read

Docker Networking Lab: Build a Safe Local Environment for Testing and Troubleshooting

calendar_today Published: 2026-10-26
update Last Updated: 2026-10-26
analytics SEO Efficiency: 100%
Technical guide illustration for Docker Networking Lab: Build a Safe Local Environment for Testing and Troubleshooting.

Intro

Docker networking is one of the most common sources of confusion when moving from a single container to multi-container applications. Misconfigured networks lead to containers that cannot reach each other, DNS resolution failures, or unintended exposure to the host. Rather than experimenting on a production host, you can build a safe local Docker networking lab to test configurations, troubleshoot behavior, and create repeatable learning workflows. A controlled lab helps you isolate problems, verify fixes, and build confidence before making changes elsewhere in your infrastructure.

This guide walks through setting up such a lab with concrete commands and expected outputs. We will create dedicated Docker bridge networks, launch containers with static IP addresses and custom hostnames, test connectivity and DNS resolution, demonstrate network isolation, and then examine common failure modes along with recovery steps. All examples are designed to run on a single Linux host with Docker installed, including Docker Desktop on Windows or macOS. The commands are safe for your local environment and do not affect other Docker networks or running containers.

A local lab is especially valuable when you are learning Docker networking concepts or troubleshooting an issue you suspect is network-related. Instead of guessing or reading through lengthy documentation, you can reproduce the problem in minutes, test fixes, and document what works. The ability to inspect network internals directly inside containers gives you immediate insight into how Docker manages networking under the hood.

Version and Environment Inventory

Before starting, confirm your environment meets the following prerequisites:

  • Docker Engine version 20.10 or later, or Docker Desktop equivalent.
  • A Linux host (native or virtual machine) with a Bash shell. Windows Subsystem for Linux 2 (WSL2) works well, as does Docker Desktop with Linux containers.
  • Basic familiarity with the Docker CLI and container lifecycle commands such as docker run, docker exec, and docker rm.
  • No existing user-defined networks named labnet1 or labnet2, and no containers named lab1, lab2, or lab3 (we will create them).

To check your Docker version, run:

docker version --format '{{.Server.Version}}'

Expected output similar to:

20.10.21

Also confirm you can list current networks:

docker network ls

You should see output similar to the following (network IDs will vary):

NETWORK ID     NAME      DRIVER    SCOPE
abc123def456   bridge    bridge    local
ghi789jkl012   host      host      local
mno345pqr678   none      null      local

If you see the default bridge, host, and none networks, you are ready to proceed. This lab uses user-defined bridge networks, which provide automatic DNS resolution between containers and isolation from the host network stack.

Quick check 1 of 2

According to the networking overview, when multiple containers are attached to the same custom network, how can they communicate with each other?

Passage 1 states that when multiple containers are attached to the same custom network, they can communicate using container names as DNS hostnames, demonstrated by pinging 'web'.

Safe Configuration Path

We will build the lab incrementally, verifying each step before moving to the next. This approach limits the scope of changes and makes rollback straightforward: if something goes wrong, you can remove only the resources you just created without affecting the rest of your environment.

Step 1: Create an isolated user-defined bridge network

Create a network named labnet1 with a specific subnet to avoid conflicts with existing networks and to allow static IP assignments:

docker network create \
  --driver bridge \
  --subnet 192.168.100.0/24 \
  --gateway 192.168.100.1 \
  labnet1

Expected output is the network ID, for example:

6f8d4c9b2a1e

Verify the network exists and has the correct configuration:

docker network inspect labnet1 --format '{{.Name}} {{.Driver}} {{.IPAM.Config}}'

Expected output:

labnet1 bridge [{192.168.100.0/24 192.168.100.1 map[]}]

This confirms that the network is a bridge driver with the specified subnet and gateway.

Step 2: Launch two containers on the network with static IPs

We will run two Alpine Linux containers because they are lightweight and start quickly. Each container gets a static IP address and a custom hostname. Start the first container, lab1, with IP 192.168.100.10:

docker run -dit \
  --name lab1 \
  --network labnet1 \
  --ip 192.168.100.10 \
  --hostname lab1 \
  alpine:latest

Expected output is the container ID, for example:

abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890

Start the second container, lab2, with IP 192.168.100.20:

docker run -dit \
  --name lab2 \
  --network labnet1 \
  --ip 192.168.100.20 \
  --hostname lab2 \
  alpine:latest

Verify both containers are running:

docker ps --filter "name=lab" --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}'

Expected output:

NAMES   IMAGE            STATUS
lab1    alpine:latest    Up 10 seconds
lab2    alpine:latest    Up 8 seconds

Step 3: Test basic connectivity between containers

Execute a ping from lab1 to lab2 using its IP address:

docker exec lab1 ping -c 2 192.168.100.20

Expected output (timing values may vary):

PING 192.168.100.20 (192.168.100.20): 56 data bytes
64 bytes from 192.168.100.20: seq=0 ttl=64 time=0.123 ms
64 bytes from 192.168.100.20: seq=1 ttl=64 time=0.098 ms

--- 192.168.100.20 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.098/0.110/0.123 ms

Now test using the container name to verify DNS resolution:

docker exec lab1 ping -c 2 lab2

Expected output should be similar to the previous ping, showing that lab2 resolved to 192.168.100.20. This confirms that Docker's embedded DNS server works automatically on user-defined networks.

Step 4: Expose a simple service and test from another container

Testing at the network layer is useful, but a practical lab should also verify service-level connectivity. We will run a lightweight web server in lab2 using Python's built-in HTTP server. Alpine Linux does not include Python by default, so first install it inside lab2:

docker exec lab2 apk add --no-cache python3

Then start a simple HTTP server on port 8000 inside lab2:

docker exec -d lab2 python3 -m http.server 8000

The -d flag runs the server in detached mode inside the container. Verify the server is listening:

docker exec lab2 netstat -tuln | grep 8000

Alternatively, use ss -tuln if netstat is not available. Expected output shows a line with 0.0.0.0:8000 indicating the server is listening on all interfaces.

Now test from lab1 using wget (available in Alpine by default) to fetch a file from the server. Since the server's root directory is / inside lab2, you can fetch /etc/hostname to see the hostname:

docker exec lab1 wget -qO- http://192.168.100.20:8000/etc/hostname

Expected output:

lab2

You can also use the container name in the URL to test DNS-based service discovery:

docker exec lab1 wget -qO- http://lab2:8000/etc/hostname

This should produce the same output, confirming that the embedded DNS resolves lab2 and that the HTTP service is reachable.

Step 5: Create a second network to demonstrate isolation

Create another network labnet2 with a different subnet:

docker network create \
  --driver bridge \
  --subnet 10.10.10.0/24 \
  --gateway 10.10.10.1 \
  labnet2

Attach a new container lab3 to labnet2:

docker run -dit \
  --name lab3 \
  --network labnet2 \
  --ip 10.10.10.10 \
  --hostname lab3 \
  alpine:latest

Now test connectivity from lab1 (on labnet1) to lab3 (on labnet2) by IP address:

docker exec lab1 ping -c 2 10.10.10.10

Expected output will show 100% packet loss, because the two networks are isolated unless you explicitly connect them. This demonstrates Docker network isolation: containers on different user-defined bridge networks cannot communicate directly, even if they know each other's IP addresses.

Step 6: Connect a container to multiple networks

If needed, you can connect lab1 to labnet2 as well, allowing it to communicate with lab3. This is a common pattern for multi-tier applications where a container needs to access services on different networks.

docker network connect labnet2 lab1

After connecting, lab1 receives an additional IP address on labnet2. Docker automatically assigns the next available IP in that subnet, for example 10.10.10.2. Verify by inspecting the network interfaces inside lab1:

docker exec lab1 ip addr show

Look for an interface (likely eth1) with an IP address in the 10.10.10.0/24 subnet. Then test ping again from lab1 to lab3:

docker exec lab1 ping -c 2 10.10.10.10

Now it should succeed, showing connectivity after attaching to the same network. This demonstrates how Docker allows containers to be part of multiple networks, which is useful for controlled communication between different tiers.

Verification and Diagnostics

Proper verification ensures your lab behaves as expected. Use the following commands to inspect network configuration and connectivity.

Inspect network details

docker network inspect labnet1

This returns a JSON object with the subnet, gateway, containers attached, and their IP addresses. For a concise view, use:

docker network inspect labnet1 --format '{{range .Containers}}{{.Name}} {{.IPv4Address}}{{"\n"}}{{end}}'

Expected output:

lab1 192.168.100.10/24
lab2 192.168.100.20/24

This confirms IP assignments.

Check DNS resolution

From lab1, resolve the hostname lab2 using nslookup (available via BusyBox in Alpine):

docker exec lab1 nslookup lab2

Expected output similar to:

Server:    127.0.0.11
Address:   127.0.0.11:53

Name:      lab2
Address:   192.168.100.20

The DNS server at 127.0.0.11 is Docker's embedded DNS, which runs inside each container on user-defined networks.

Verify isolation

Check that containers on separate networks cannot reach each other without explicit connection. From lab1 (if not connected to labnet2), ping lab3's IP and confirm failure. A successful ping after connecting demonstrates the change.

Examine container network interfaces

docker exec lab1 ip addr show

Look for the eth0 interface with the assigned IP. You can also check routing:

docker exec lab1 ip route

Expected output shows the default gateway via 192.168.100.1, along with the subnet route.

Common Pitfalls and How to Avoid Them

Even in a controlled lab, certain mistakes are common. Recognizing them early can save time and frustration.

Pitfall 1: Using the default bridge network

Many beginners place containers on the default bridge network and then wonder why DNS resolution fails. The default bridge network does not provide automatic DNS resolution between containers; you must use legacy --link flags (deprecated) or, better, create a user-defined bridge network. Why it happens: Docker's default bridge is designed for backward compatibility and does not have the embedded DNS server or automatic service discovery that user-defined networks provide. How to avoid: Always create a dedicated user-defined network for your applications. This lab demonstrates the correct approach.

Pitfall 2: Static IP conflicts

Assigning a static IP that is already in use by another container on the same network causes an error such as Address already in use. Why it happens: Docker tracks IP allocations in its IPAM (IP Address Management) database, and each IP on a subnet must be unique. How to avoid: Before assigning a static IP, inspect the network to see existing allocations using docker network inspect. Alternatively, use a subnet with enough addresses and plan your IP scheme. If a conflict occurs, choose a different IP or remove the conflicting container.

Pitfall 3: Forgetting to connect a container to the second network

When testing multi-network connectivity, it is easy to forget that a container is not automatically attached to all networks. Pinging across networks will fail until you explicitly connect the container. Why it happens: Docker networks are isolated by default, and containers only join networks they are explicitly connected to. How to avoid: Always verify network membership with docker network inspect before expecting cross-network communication. If needed, use docker network connect as shown in Step 6.

Pitfall 4: Misinterpreting DNS resolution failures

If ping lab2 returns Name or service not known, it is tempting to think Docker's DNS is broken. Why it happens: Usually, the containers are on the default bridge network, or the container name is misspelled, or the containers are on different user-defined networks. How to avoid: Check the network membership of both containers with docker network inspect. Ensure they are on the same user-defined network. If not, connect them or create a new network and attach both.

Pitfall 5: Leaving test containers and networks running

After experimenting, you may forget to clean up, leaving orphaned containers and networks that consume resources and clutter your environment. Why it happens: It is easy to move on to the next task without deleting lab resources. How to avoid: Adopt a habit of tearing down the lab when finished, as described in the cleanup section below. You can also use labels or naming conventions to identify lab resources easily.

Quick check 2 of 2

In the custom network example, what command creates the network named my-net?

Passage 1 shows 'docker network create my-net' as the command that creates the custom network before running containers attached to it.

Failure Modes and Recovery

Understanding common failure modes helps you recover quickly and keeps your lab productive.

IP address conflict

If you attempt to assign a static IP already in use, Docker returns an error like:

Error response from daemon: Address already in use

Recovery: Choose a different IP or inspect existing allocations with docker network inspect labnet1 to find the conflict. Remove the conflicting container if necessary and retry.

Container cannot resolve DNS names

If DNS resolution fails (e.g., ping lab2 gives Name or service not known), check if the containers are on the same user-defined network. DNS resolution only works on user-defined networks, not the default bridge. Verify with docker network inspect and ensure both containers are attached.

Recovery: Connect both containers to the same user-defined network using docker network connect.

Network isolation breaks unexpectedly

If containers that should be isolated suddenly can communicate, check if they are connected to a common network (e.g., both attached to the same bridge). Use docker network inspect to review connections.

Recovery: Disconnect the unintended network connection with docker network disconnect <network> <container>.

Container loses connectivity after network changes

Modifying network settings (e.g., disconnecting a container) can disrupt active connections.

Recovery: Reconnect the container to the network if needed, or restart the container with docker restart <container> to re-establish networking. In some cases, recreating the container may be necessary.

Port publishing misconfiguration

If you expose a service inside a container but cannot reach it from the host, you may have forgotten to publish the port with -p. Without port publishing, the service is only accessible from other containers on the same network.

Recovery: Re-run the container with the appropriate -p flag, or use docker network connect to allow access from another container on the same network without exposing it to the host.

Rollback strategy

Because the lab is isolated, rollback often means removing the test networks and containers. Save your setup commands in a script for reproducibility. To tear down everything:

docker rm -f lab1 lab2 lab3
docker network rm labnet1 labnet2

Verify removal with docker network ls and docker ps -a.

Operations Checklist

Use this checklist to run the lab reliably and extend it safely. Each step includes a command or check and the expected outcome. For each major action, assign an owner (yourself in a personal lab, or a specific team member in a shared environment) and review the results before proceeding. In a team setting, revisit the lab setup monthly to ensure it still meets current needs and that no conflicts have arisen.

StepActionCommand / CheckOwnerReview Frequency
1Verify Docker is runningdocker infoLab operator (e.g., Alex)At each lab session
2List existing networksdocker network ls (ensure no conflict with lab names)Lab operatorAt each lab session
3Create lab network with subnetdocker network create --subnet 192.168.100.0/24 --gateway 192.168.100.1 labnet1Lab operatorAt each lab build
4Launch test containers with static IPsdocker run -dit --name lab1 --network labnet1 --ip 192.168.100.10 alpine:latest (repeat for lab2)Lab operatorAt each lab build
5Test IP connectivitydocker exec lab1 ping -c 2 192.168.100.20 (expect 0% loss)Lab operatorAfter container start
6Test DNS-based connectivitydocker exec lab1 ping -c 2 lab2 (expect success)Lab operatorAfter container start
7Verify isolationPing 10.10.10.10 from lab1 before connecting (expect failure)Lab operatorWhen testing isolation
8Connect to additional network if neededdocker network connect labnet2 lab1Lab operatorWhen multi-network needed
9Inspect network configurationdocker network inspect labnet1 --format '{{range .Containers}}{{.Name}} {{.IPv4Address}}{{"\n"}}{{end}}'Lab operatorAfter any network change
10Clean up when donedocker rm -f lab1 lab2 lab3 && docker network rm labnet1 labnet2Lab operatorEnd of session

Repeat these steps as needed for experiments. Document any variations and their outcomes for future reference. Maintaining a lab journal helps you track what you have tested and the results, making it easier to reproduce or share findings with your team.

Conclusion

A local Docker networking lab provides a safe, repeatable environment to learn and test network configurations. In this guide, we created isolated bridge networks, deployed containers with static IPs and hostnames, verified connectivity and DNS, demonstrated network isolation, and discussed common failure modes with recovery steps. By following the operations checklist and avoiding the pitfalls described, you can extend the lab to test more complex scenarios such as overlay networks, network policies, or multi-host setups.

Start with a narrow pilot network, inspect behavior locally, and then apply verified changes to your development or production environments with confidence. The skills you build in this lab will transfer directly to real-world Docker deployments, helping you troubleshoot networking issues faster and design more robust container architectures.

Related Research

Article Quality Score

Reader usefulness 100%
  • check_circle Reader-ready guide
  • check_circle Practical examples included
  • check_circle Clean SEO article URL