Networking using a macvlan network

This series of tutorials deals with networking standalone containers which connect to macvlan networks. In this type of network, the Docker host accepts requests for multiple MAC addresses at its IP address, and routes those requests to the appropriate container. For other networking topics, see the overview.

Goal

The goal of these tutorials is to set up a bridged macvlan network and attach a container to it, then set up an 802.1Q trunked macvlan network and attach a container to it.

Prerequisites

  • Most cloud providers block macvlan networking. You may need physical access to your networking equipment.

  • The macvlan networking driver only works on Linux hosts, and is not supported on Docker Desktop for Mac, Docker Desktop for Windows, or Docker EE for Windows Server.

  • You need at least version 3.9 of the Linux kernel, and version 4.0 or higher is recommended.

  • The examples assume your ethernet interface is eth0. If your device has a different name, use that instead.

  • The macvlan driver is not supported in rootless mode.

Bridge example

In the simple bridge example, your traffic flows through eth0 and Docker routes traffic to your container using its MAC address. To network devices on your network, your container appears to be physically attached to the network.

  1. Create a macvlan network called my-macvlan-net. Modify the subnet, gateway, and parent values to values that make sense in your environment.

    $ docker network create -d macvlan \
      --subnet=172.16.86.0/24 \
      --gateway=172.16.86.1 \
      -o parent=eth0 \
      my-macvlan-net
    

    You can use docker network ls and docker network inspect my-macvlan-net commands to verify that the network exists and is a macvlan network.

  2. Start an alpine container and attach it to the my-macvlan-net network. The -dit flags start the container in the background but allow you to attach to it. The --rm flag means the container is removed when it is stopped.

    $ docker run --rm -dit \
      --network my-macvlan-net \
      --name my-macvlan-alpine \
      alpine:latest \
      ash
    
  3. Inspect the my-macvlan-alpine container and notice the MacAddress key within the Networks key:

    $ docker container inspect my-macvlan-alpine
    
    ...truncated...
    "Networks": {
      "my-macvlan-net": {
          "IPAMConfig": null,
          "Links": null,
          "Aliases": [
              "bec64291cd4c"
          ],
          "NetworkID": "5e3ec79625d388dbcc03dcf4a6dc4548644eb99d58864cf8eee2252dcfc0cc9f",
          "EndpointID": "8caf93c862b22f379b60515975acf96f7b54b7cf0ba0fb4a33cf18ae9e5c1d89",
          "Gateway": "172.16.86.1",
          "IPAddress": "172.16.86.2",
          "IPPrefixLen": 24,
          "IPv6Gateway": "",
          "GlobalIPv6Address": "",
          "GlobalIPv6PrefixLen": 0,
          "MacAddress": "02:42:ac:10:56:02",
          "DriverOpts": null
      }
    }
    ...truncated
    
  4. Check out how the container sees its own network interfaces by running a couple of docker exec commands.

    $ docker exec my-macvlan-alpine ip addr show eth0
    
    9: eth0@tunl0: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
    link/ether 02:42:ac:10:56:02 brd ff:ff:ff:ff:ff:ff
    inet 172.16.86.2/24 brd 172.16.86.255 scope global eth0
       valid_lft forever preferred_lft forever
    
    $ docker exec my-macvlan-alpine ip route
    
    default via 172.16.86.1 dev eth0
    172.16.86.0/24 dev eth0 scope link  src 172.16.86.2
    
  5. Stop the container (Docker removes it because of the --rm flag), and remove the network.

    $ docker container stop my-macvlan-alpine
    
    $ docker network rm my-macvlan-net
    

802.1Q trunked bridge example

In the 802.1Q trunked bridge example, your traffic flows through a sub-interface of eth0 (called eth0.10) and Docker routes traffic to your container using its MAC address. To network devices on your network, your container appears to be physically attached to the network.

  1. Create a macvlan network called my-8021q-macvlan-net. Modify the subnet, gateway, and parent values to values that make sense in your environment.

    $ docker network create -d macvlan \
      --subnet=172.16.86.0/24 \
      --gateway=172.16.86.1 \
      -o parent=eth0.10 \
      my-8021q-macvlan-net
    

    You can use docker network ls and docker network inspect my-8021q-macvlan-net commands to verify that the network exists, is a macvlan network, and has parent eth0.10. You can use ip addr show on the Docker host to verify that the interface eth0.10 exists and has a separate IP address

  2. Start an alpine container and attach it to the my-8021q-macvlan-net network. The -dit flags start the container in the background but allow you to attach to it. The --rm flag means the container is removed when it is stopped.

    $ docker run --rm -itd \
      --network my-8021q-macvlan-net \
      --name my-second-macvlan-alpine \
      alpine:latest \
      ash
    
  3. Inspect the my-second-macvlan-alpine container and notice the MacAddress key within the Networks key:

    $ docker container inspect my-second-macvlan-alpine
    
    ...truncated...
    "Networks": {
      "my-8021q-macvlan-net": {
          "IPAMConfig": null,
          "Links": null,
          "Aliases": [
              "12f5c3c9ba5c"
          ],
          "NetworkID": "c6203997842e654dd5086abb1133b7e6df627784fec063afcbee5893b2bb64db",
          "EndpointID": "aa08d9aa2353c68e8d2ae0bf0e11ed426ea31ed0dd71c868d22ed0dcf9fc8ae6",
          "Gateway": "172.16.86.1",
          "IPAddress": "172.16.86.2",
          "IPPrefixLen": 24,
          "IPv6Gateway": "",
          "GlobalIPv6Address": "",
          "GlobalIPv6PrefixLen": 0,
          "MacAddress": "02:42:ac:10:56:02",
          "DriverOpts": null
      }
    }
    ...truncated
    
  4. Check out how the container sees its own network interfaces by running a couple of docker exec commands.

    $ docker exec my-second-macvlan-alpine ip addr show eth0
    
    11: eth0@if10: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
    link/ether 02:42:ac:10:56:02 brd ff:ff:ff:ff:ff:ff
    inet 172.16.86.2/24 brd 172.16.86.255 scope global eth0
       valid_lft forever preferred_lft forever
    
    $ docker exec my-second-macvlan-alpine ip route
    
    default via 172.16.86.1 dev eth0
    172.16.86.0/24 dev eth0 scope link  src 172.16.86.2
    
  5. Stop the container (Docker removes it because of the --rm flag), and remove the network.

    $ docker container stop my-second-macvlan-alpine
    
    $ docker network rm my-8021q-macvlan-net
    

Other networking tutorials