When orchestrating lightweight Linux containers (such as those managed by LXC/LXD or Docker), a frequent architectural requirement is allowing the container to behave exactly like a physical machine on the local network. By default, container engines utilize NAT (Network Address Translation) and bridge interfaces, meaning the container shares the host’s IP address and requires complex port-forwarding rules to expose services. If you require the container to receive its own distinct DHCP lease from the corporate router and appear as a first-class citizen on the underlying LAN, you must bypass the host’s routing stack. The most efficient, performant method to achieve this on modern Linux distributions is configuring a MACVLAN interface using systemd-networkd.
Understanding the MACVLAN Architecture
A MACVLAN interface is a Linux kernel feature that allows you to configure multiple virtual network interfaces, each possessing a completely unique MAC address, all multiplexed over a single physical Ethernet interface (e.g., eth0). When a container is attached to a MACVLAN interface, any traffic it generates is tagged with its unique virtual MAC address and injected directly onto the physical wire. The physical switch on the network sees this traffic as originating from a distinct physical device.
Crucially, MACVLAN operates in several modes, with Bridge Mode being the most common. In Bridge mode, the virtual interfaces can communicate directly with other virtual interfaces on the same physical link. However, by architectural design, the Linux kernel fundamentally isolates the virtual MACVLAN interfaces from the underlying physical host interface. A container on a MACVLAN cannot ping its own Docker/LXC host, preventing accidental host-level compromise.
Configuring the MACVLAN via systemd-networkd
On modern distributions like Ubuntu Server or Arch Linux, systemd-networkd is the preferred daemon for granular, low-level network configuration, completely superseding legacy tools like ifupdown or netplan abstractions.
To create a MACVLAN interface, you must define two distinct systemd-networkd configuration files within the /etc/systemd/network/ directory.
Step 1: Define the Virtual NetDev
First, we must instruct the kernel to create the virtual MACVLAN device. Create a file named 10-macvlan.netdev:
[NetDev]
Name=macvlan0
Kind=macvlan
[MACVLAN]
Mode=bridge
This configuration defines a new virtual interface named macvlan0 operating in standard bridge mode.
Step 2: Bind the Virtual Device to the Physical Interface
Next, we must bind this virtual device to the actual physical network card connected to your LAN (e.g., eno1). Create a file named 20-bind-macvlan.network:
[Match]
Name=eno1
[Network]
# Ensure the host interface still receives its normal DHCP address
DHCP=ipv4
# Attach the virtual MACVLAN device to this physical link
MACVLAN=macvlan0
Step 3: Apply the Configuration
To inject these changes into the kernel without rebooting, restart the systemd-networkd service:
sudo systemctl restart systemd-networkd
Verify that the new interface exists using the standard ip command:
ip link show macvlan0
Attaching the Container
With the macvlan0 interface successfully established by the host operating system, you can now seamlessly attach your lightweight containers.
If you are utilizing Docker, you must create a corresponding Docker network that maps to the host’s MACVLAN interface. This allows Docker to assign the containers directly to the pre-configured kernel device:
docker network create -d macvlan \
--subnet=192.168.1.0/24 \
--gateway=192.168.1.1 \
-o parent=macvlan0 pub_net
Now, when you spawn a new container, instruct it to utilize the pub_net network. The container will completely bypass the host’s iptables NAT routing, securely requesting and receiving a unique IP address directly from your physical corporate DHCP server.
docker run -itd --network=pub_net --name=isolated-nginx nginx:alpine