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.
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.
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
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
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.
This is exactly what i was searching for. Thank you so much!
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?
I am not familiar with your setup, but have you tried this on a regular Linux desktop or server?
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 »
I meant to say modem* not router. This OpenWRT device is my router.
Did you create the bridge macvlan and the static routes to point back to the container via the bridge macvlan?
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
thanks a lot. This is was I was looking for. The network-manager option is great.
Thank you!! This was what I needed!