Skip to main content

Command Palette

Search for a command to run...

Docker Networking

Published
11 min read
Docker Networking
R

✨🌟💫Threat Hunter 💫🌟✨

“Networking in Docker is about who can talk to whom, and on which terms.”

This write up walks through Docker network drivers, basic docker network commands, how to create and inspect networks, and how to attach containers. It also covers macvlan and none drivers with practical tests and ends with small challenge tasks.


1. Network Drivers Overview

Docker provides multiple network drivers. If you do not specify a driver when you run a container or create a network, Docker uses the bridge driver by default.

1.1 Core Network Drivers

NetworkDescription
bridgeDefault driver if none is specified. Containers on the same bridge network can talk to each other but are isolated from containers on other bridge networks. All containers can reach the external network through NAT.
hostThe container shares the host network stack. Network isolation is disabled while storage and process isolation remain. Ports exposed in the container are visible on the host IP directly.
macvlanAttaches containers directly to the physical network. Each container gets its own MAC address on the parent interface (for example eth0) and an IP on that network. Misconfiguration can flood the network with many MACs or cause IP conflicts.
noneNetworking is disabled. Containers cannot talk to each other or the outside world.

[!WARNING] Misconfigured macvlan can cause network issues, including too many MAC addresses seen by switches or duplicate IP addresses. Use it only when you know exactly how your upstream network behaves.

1.2 High Level View

  • bridge - good default for most scenarios.

  • macvlan - used when containers must appear as real hosts on the LAN.

  • none - used for isolation or lab scenarios when you do not want any network.


2. Working With docker network

Docker provides a dedicated subcommand to manage networks.

docker network --help

Sample output:

Usage:  docker network COMMAND

Manage networks

Commands:
  connect     Connect a container to a network
  create      Create a network
  disconnect  Disconnect a container from a network
  inspect     Display detailed information on one or more networks
  ls          List networks
  prune       Remove all unused networks
  rm          Remove one or more networks

Run 'docker network COMMAND --help' for more information on a command.

[!NOTE] In most labs you will use docker network ls, docker network create, docker network inspect, and docker network rm.


3. Default Networks

When Docker is installed, it creates three default networks.

docker network ls
# or
docker network list

Sample output:

NETWORK ID          NAME                DRIVER              SCOPE
a49ba9341007        bridge              bridge              local
d12b019b2364        host                host                local
ddc639acd513        none                null                local
  • bridge - default user space bridge network.

  • host - uses the host network stack.

  • none - no networking.


4. Creating and Inspecting a Bridge Network

4.1 Create a Custom Bridge Network

docker network create mynetwork

Sample output:

4e2338e543280718087375b475bfe73de1e6019ad94b4c408a73dad3ccbe78ff

Verify:

docker network ls

Example:

NETWORK ID          NAME                DRIVER              SCOPE
8b2369f350d5        bridge              bridge              local
019ff813f4f4        host                host                local
4e2338e54328        mynetwork           bridge              local
a9e2bdd51902        none                null                local

4.2 Inspect Network Details

Use docker inspect to see IPAM configuration, subnet, and gateway.

docker inspect mynetwork

Sample output (trimmed):

[
  {
    "Name": "mynetwork",
    "Id": "e383473123cb3ad81a69f4842150a98b90113d0db31f1718927a09a73a5b42b9",
    "Driver": "bridge",
    "IPAM": {
      "Driver": "default",
      "Config": [
        {
          "Subnet": "172.19.0.0/16",
          "Gateway": "172.19.0.1"
        }
      ]
    },
    "Containers": {},
    "Options": {},
    "Labels": {}
  }
]

[!TIP] docker inspect works on containers, images, and networks. For networks, focus on IPAM, Subnet, Gateway, and Containers.


5. Attaching a Container to a Bridge Network

You can attach a container to a specific network at creation time using --network.

5.1 Run a Container on mynetwork

docker run -d --name ubuntu --network mynetwork -it ubuntu:20.04

Sample output:

Unable to find image 'ubuntu:20.04' locally
20.04: Pulling from library/ubuntu
f22ccc0b8772: Pull complete
3cf8fb62ba5f: Pull complete
e80c964ece6a: Pull complete
Digest: sha256:fd25e706f3dea2a5ff705dbc3353cf37f08307798f3e360a13e9385840f73fb3
Status: Downloaded newer image for ubuntu:20.04
6de044989252172bde92f8489d721030e578f36d34e6e0a2a92b299aa3500800

5.2 Verify Container Attachment

docker inspect mynetwork

Key parts:

# docker inspect mynetwork
[
    {
        "Name": "mynetwork",
        "Id": "3d83391642c5e601013fcbb77ebaf429b072b2100ab6d6a72bdc59c2706f76ac",
        "Created": "2025-12-11T18:28:13.977528981Z",
        "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": {
            "772afcae082db63e8999cf900420a6e96e1f09497e3358b2d130f04c2c086c80": {
                "Name": "lucid_pascal",
                "EndpointID": "806550ee3af5632117a8111673e5088a9a8c942e92c2be66daf0314d9bd13565",
                "MacAddress": "02:42:ac:12:00:02",
                "IPv4Address": "172.18.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]

The container ubuntu now has its own IP address on mynetwork.

5.3 Test Connectivity from the Container

Run apt update inside the container via docker exec.

docker exec lucid_pascal apt update

WARNING: apt does not have a stable CLI interface. Use with caution in scripts.

Get:1 <http://archive.ubuntu.com/ubuntu> focal InRelease [265 kB]
Get:2 <http://security.ubuntu.com/ubuntu> focal-security InRelease [128 kB]
Get:3 <http://archive.ubuntu.com/ubuntu> focal-updates InRelease [128 kB]
Get:4 <http://archive.ubuntu.com/ubuntu> focal-backports InRelease [128 kB]
Get:5 <http://archive.ubuntu.com/ubuntu> focal/universe amd64 Packages [11.3 MB]
Get:6 <http://archive.ubuntu.com/ubuntu> focal/restricted amd64 Packages [33.4 kB]
Get:7 <http://archive.ubuntu.com/ubuntu> focal/multiverse amd64 Packages [177 kB]
Get:8 <http://archive.ubuntu.com/ubuntu> focal/main amd64 Packages [1275 kB]
Get:9 <http://archive.ubuntu.com/ubuntu> focal-updates/restricted amd64 Packages [4998 kB]
Get:10 <http://archive.ubuntu.com/ubuntu> focal-updates/multiverse amd64 Packages [36.8 kB]
Get:11 <http://archive.ubuntu.com/ubuntu> focal-updates/universe amd64 Packages [1599 kB]
Get:12 <http://archive.ubuntu.com/ubuntu> focal-updates/main amd64 Packages [4920 kB]
Get:13 <http://archive.ubuntu.com/ubuntu> focal-backports/main amd64 Packages [55.2 kB]
Get:14 <http://archive.ubuntu.com/ubuntu> focal-backports/universe amd64 Packages [28.6 kB]
Get:15 <http://security.ubuntu.com/ubuntu> focal-security/main amd64 Packages [4432 kB]
Get:16 <http://security.ubuntu.com/ubuntu> focal-security/multiverse amd64 Packages [33.1 kB]
Get:17 <http://security.ubuntu.com/ubuntu> focal-security/restricted amd64 Packages [4801 kB]
Get:18 <http://security.ubuntu.com/ubuntu> focal-security/universe amd64 Packages [1308 kB]
Fetched 35.7 MB in 2s (16.2 MB/s)
Reading package lists...
Building dependency tree...
Reading state information...
5 packages can be upgraded. Run 'apt list --upgradable' to see them.

Sample output (shortened):

Get:1 <http://security.ubuntu.com/ubuntu> bionic-security InRelease [88.7 kB]
Get:2 <http://archive.ubuntu.com/ubuntu> bionic InRelease [242 kB]
...
Fetched 21.7 MB in 3s (7441 kB/s)
Reading package lists...
Building dependency tree...
Reading state information...
5 packages can be upgraded. Run 'apt list --upgradable' to see them.

[!SUCCESS] Since apt update works, DNS resolution and outbound HTTP traffic both work. The container can reach the internet through Docker’s bridge network and NAT.

5.4 Clean Up

docker rm -f lucid_pascal
lucid_pascal

docker ps -a
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

docker network ls
NETWORK ID     NAME        DRIVER    SCOPE
1ee9fdcddb50   bridge      bridge    local
c7ae3f468421   host        host      local
3d83391642c5   mynetwork   bridge    local
ff657c23e1c2   none        null      local

docker network rm mynetwork
mynetwork

docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
1ee9fdcddb50   bridge    bridge    local
c7ae3f468421   host      host      local
ff657c23e1c2   none      null      local

6. macvlan Network

macvlan places containers directly on the physical network. Each container gets its own MAC and IP in the same L2 domain as the host interface.

6.1 Create a macvlan Network

docker network create --driver 
bridge   ipvlan   macvlan  overlay  

docker network create --driver macvlan mymacvlan
3e9e552394578ff6584d184f0eaa0546b33907ddbba091f85e2fd2df0c4306c1

docker network list
NETWORK ID     NAME        DRIVER    SCOPE
1ee9fdcddb50   bridge      bridge    local
c7ae3f468421   host        host      local
3e9e55239457   mymacvlan   macvlan   local
ff657c23e1c2   none        null      local

docker network inspect mymacvlan
[
    {
        "Name": "mymacvlan",
        "Id": "3e9e552394578ff6584d184f0eaa0546b33907ddbba091f85e2fd2df0c4306c1",
        "Created": "2025-12-11T18:38:35.336925861Z",
        "Scope": "local",
        "Driver": "macvlan",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.20.0.0/16",
                    "Gateway": "172.20.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]

Difference Between host and macvlan Network Drivers

1. host Driver

The container shares the host’s network stack.

  • No virtual interfaces created.

  • No container level IP address. The container uses the host’s IP.

  • Ports exposed in the container are directly exposed on the host.

  • No isolation at network level.

  • Very low overhead because no NAT or bridge.

Use case:

Performance sensitive workloads or when you want the container to behave like a local process on the host.


2. macvlan Driver

Docker assigns the container a separate MAC address and separate IP on the physical LAN.

  • Container appears as a real device on the network.

  • Each container gets its own MAC and IP on the parent interface.

  • No NAT. Direct network presence.

  • Containers on macvlan cannot communicate with the host by default due to kernel restrictions.

Use case:

When containers must be reachable directly on the LAN as independent hosts (like appliances, routers, monitoring tools).


Quick Comparison Table

Featurehostmacvlan
IP AddressHost IP (shared)Unique IP per container
MAC AddressHost MACUnique MAC per container
Network IsolationNoneContainers isolated from host
Visibility on LANSame as hostAppears as separate physical device
NATNoNo
Communication with hostYesNo (by default)
PerformanceHighestHigh, but depends on network
Primary Use CaseLocal host level appsWhen devices must look like separate hosts

Sample output:

8df059075f385271a681a5ddc78b6f137607117aa0a5ac1cd22159c599d804c8

List networks:

docker network list

Example:

NETWORK ID          NAME                DRIVER              SCOPE
1201ad8119bc        bridge              bridge              local
76876641b5a2        host                host                local
8df059075f38        mymacvlan           macvlan             local
188042442f13        none                null                local

6.2 Host Network View

On the host, ifconfig will show a new dm-<id> interface:

ifconfig

Relevant part:

dm-8df059075f38: flags=195<UP,BROADCAST,RUNNING,NOARP>  mtu 1500
        ether f6:9b:f7:8e:93:53  txqueuelen 0  (Ethernet)

docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255

eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.19.0.3  netmask 255.255.0.0  broadcast 172.19.255.255

full

ifconfig
dm-3e9e55239457: flags=195<UP,BROADCAST,RUNNING,NOARP>  mtu 1500
        ether 8a:35:12:2e:42:a0  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

***docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
        ether 02:42:a2:34:c1:58  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0***

eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1450
        inet 10.1.156.199  netmask 255.255.0.0  broadcast 10.1.255.255
        ether 02:42:0a:01:9c:c7  txqueuelen 0  (Ethernet)
        RX packets 3  bytes 158 (158.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

eth1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.19.0.5  netmask 255.255.0.0  broadcast 172.19.255.255
        ether 02:42:ac:13:00:05  txqueuelen 0  (Ethernet)
        RX packets 2826  bytes 63471136 (63.4 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 1610  bytes 115857 (115.8 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 28  bytes 3216 (3.2 KB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 28  bytes 3216 (3.2 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

6.3 Attach a Container to mymacvlan

docker run -d \\
> --name ubuntu \\
> --network mymacvlan -it \\
> ubuntu:20.04
f9787ec4440e12ab471d2f38c357df39f8adea4aa10fccef17b8df1a005f4d45

Sample output:

2a42eb64e5acb4e8dc318e64acf4380f11c37a43f088e5e1b9abd6dc4eae415d

Inspect the container network:

docker inspect ubuntu -f "{{json .NetworkSettings.Networks }}" | jq

Sample output:

{
  "mymacvlan": {
    "NetworkID": "8df059075f385271a681a5ddc78b6f137607117aa0a5ac1cd22159c599d804c8",
    "Gateway": "172.18.0.1",
    "IPAddress": "172.18.0.2",
    "IPPrefixLen": 16,
    "MacAddress": "02:42:ac:12:00:02"
  }
}

[!QUESTION] What is the difference between bridge and macvlan drivers?

  • Bridge driver uses a virtual bridge and NAT. Containers get IPs on a private subnet and reach the outside world via NAT.

  • Macvlan puts containers directly on the physical network. Containers appear as independent hosts with their own MAC and IP on the LAN.

6.4 Clean Up

docker rm -f ubuntu
docker network rm mymacvlan

7. none Network Driver

The none driver disables networking for the container.

7.1 Run a Container With No Network

docker run -d --name ubuntu --network=none -it ubuntu:20.04

Sample output:

76f1219d23bec228e3d3c3320cfeed79eb7010865664f4fd8c55df55cc58660c

Inspect the network settings:

docker inspect ubuntu -f "{{json .NetworkSettings.Networks }}" | jq

Sample output:

{
  "none": {
    "NetworkID": "188042442f13fc27fb5a09ab35be331c46070f3cdf702b2a7e0d8362f01207d4",
    "Gateway": "",
    "IPAddress": "",
    "IPPrefixLen": 0,
    "IPv6Gateway": "",
    "GlobalIPv6Address": "",
    "GlobalIPv6PrefixLen": 0,
    "MacAddress": ""
  }
}

7.2 Test Connectivity

docker exec ubuntu apt update

Sample output (trimmed):

Err:1 <http://archive.ubuntu.com/ubuntu> bionic InRelease
  Temporary failure resolving 'archive.ubuntu.com'
Err:2 <http://archive.ubuntu.com/ubuntu> bionic-updates InRelease
  Temporary failure resolving 'archive.ubuntu.com'
Err:3 <http://archive.ubuntu.com/ubuntu> bionic-backports InRelease
  Temporary failure resolving 'archive.ubuntu.com'
Err:4 <http://security.ubuntu.com/ubuntu> bionic-security InRelease
  Temporary failure resolving 'security.ubuntu.com'
...
W: Some index files failed to download. They have been ignored, or old ones used instead.

[!FAIL] The container cannot resolve DNS or reach the internet. This is expected behavior for the none network driver.


8. Summary Comparison

DriverIP sourceExternal accessContainer to containerCommon use case
bridgePrivate Docker subnetYes, via NATYes, on same bridgeDefault container networking
hostHost networkYes, same as hostN/APerformance sensitive apps on bare host
macvlanPhysical LAN of parent ifaceYes, directly on LANYes, on same macvlanWhen containers must look like real hosts
noneNoneNoNoStrong isolation or controlled lab scenarios

More from this blog