Docker host can’t access containers running on macvlan

There are some instances that I have to use macvlan driver to place the container in a separate VLAN or zone within my network. Also, I have some containers that need to have its own IP address. I really didn’t have a use case where I need the host to access the container that was using macvlan until today. To paint a picture, see Figure 1.

Figure 1

Unfortunately, using the macvlan to give a container a static IP address would not allow the host to reach the container running a macvlan driver. This is also true from the container to the host. In my case, I am running the adguardhome container on 10.0.20.10 and my host is on 10.0.20.11. When I tried to update the host, I couldn’t because I am using the adguardhome container as my DNS server. To make it worse, my setup is one docker-compose.yml per service as shown in Figure 2. This post is basically how I got around with the problem with macvlan while keeping my IP scheme.

Figure 2

When deploying macvlan driver, it would not allow the host and container to reach each other even though they are on the same subnet. To get around this issue we need to create a route between the host and the container(s). Also, if you have multiple containers that need to be using macvlan, you can’t specifiy the macvlan in the docker-compose.yml file. The network need to be created manually, so lets address this one first.

Create a macvlan network

To create a network for macvlan, do the following. Adjust the value that applies to your setup.

docker network create --driver macvlan --subnet 10.0.20.0/24 --gateway 10.0.20.1 -o parent=ens18 dmz_net

Now that we have a network for macvlan with the name dmz_net. We can now reference this to our docker-compose file as shown in an example below.

version: "3"
services:
  adguardhome:
...
...omitted for brevity...
...
    networks:
      dmz_net:
         ipv4_address: 10.0.20.100

networks:
  dmz_net:
    external: true

At this point, my AdGuard Home container is now reachable via the IP address of 10.0.20.100. Repeat the same config to the other containers if necessary.

Allowing routing between the host and macvlan containers

To get the host and macvlan containers to reach each other. We need to create a bridge and a static routes on the host. There are two ways to configure the needed route(s) either via network-manager or iproute2. I am running Debian and installed network-manager, but it should be the same with other distro.

Here is the IP scheme setup for this example:

  • bridge – 10.0.20.2
  • Host – 10.0.20.11
  • AdGuard Home – 10.0.20.100
  • Nextcloud – 10.0.20.101
  • dmz_net – is a name of the link

iproute2

Here is the thing with iproute2. Using the commands below will allow routing; however, it will not persistent. Meaning, if the host reboots, the iproute2 routing config will get deleted.

ip link add dmz_net link eth0 type macvlan mode bridge
ip addr add 10.0.20.2/32 dev dmz_net
ip link set dmz_net up
ip route add 10.0.20.100/32 dev dmz_net
ip route add 10.0.20.101/26 dev dmz_net

To make the iproute2 config permanent is to add it to the /etc/network/interfaces file as shown below

iface ens18 inet static
    address 10.0.20.11
    netmask 255.255.255.0
    gateway 10.0.20.1

    post-up ip link add dmz_net link eth0 type macvlan mode bridge
    post-up ip addr add 10.0.20.2/32 dev dmz_net
    post-up ip link set dmz_net up
    post-up ip route add 10.0.20.100/32 dev dmz_net
    post-up ip route add 10.0.20.101/26 dev dmz_net

network-manager

If you are using network-manager, it is a bit easier and it is a permanent configuration.

nmcli connection add con-name macvlan-ens18 type macvlan ifname macvlan-ens18 ipv4.addresses 10.0.20.2/24 dev ens18 mode bridge
nmcli connection modify macvlan-ens18 ipv4.method manual
nmcli connection modify macvlan-ens18 +ipv4.routes "10.0.20.100/32"
nmcli connection modify macvlan-ens18 +ipv4.routes "10.0.20.101/32"
nmcli connection up macvlan-ens18

At this point, my host is able to use AdGuard Home as its DNS server.

Cheers!

Subscribe
Notify of
guest

10 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Maik
Maik
1 year ago

This is exactly what i was searching for. Thank you so much!

Tim
Tim
1 year ago

Great guide! I followed everything, but my docker container does not have internet access. I don’t know if it makes a difference but my host is running OpenWRT on a Nano R5S.

I have scoured the internet but can not find any solution to my problem. Any tips?

Tim
Tim
Reply to  Karlo Abaga
1 year ago

Okay so I tried this on a RPI4 with Ubuntu server, and it worked great. The docker container had internet access before I even did any of the routing. Once I finished the routing, my host and other devices on the network were able to access and send DNS queries to the container. Perfect. The problem I am having is on my OpenWRT device. It has a WAN (eth0) port which is a direct connection to the internet from the router, and a LAN (eth1) port which the rest of the network connects to for Internet access, etc. (there is… Read more »

Tim
Tim
Reply to  Tim
1 year ago

I meant to say modem* not router. This OpenWRT device is my router.

Tim
Tim
Reply to  Karlo Abaga
1 year ago

I believe so.

bridge ip: 172.16.0.3
docker container ip: 172.16.0.2

Create bridge macvlan:

ip link add dmz_net link eth1 type macvlan mode bridge
ip addr add 172.16.0.3/32 dev dmz_net
ip link set dmz_net up

Add static route:
ip route add 172.16.0.2/32 dev dmz_net

Fernando
Fernando
1 year ago

thanks a lot. This is was I was looking for. The network-manager option is great.

Carlos
Carlos
9 months ago

Thank you!! This was what I needed!

munyika
munyika
5 months ago

excellente!

10
0
Would love your thoughts, please comment.x
()
x