linuxdockerdocker-containerdocker-networknic

How to run Docker containers on a bonded interface (bond0) using a bridge network?


I’m trying to make my Docker containers use a bonded interface (bond0) for fault tolerance, instead of binding directly to a single network adapter.

The bonded interface is successfully created with all available NICs, and shows up as bond0.

After the bond is created, the following commands are executed:

# works fine if I use 'enp0s8' instead of 'bond0'
nmcli conn add con-name cmynode type ethernet ifname bond0 ip4 10.11.11.241 ip4 10.11.11.249

docker network create \
  -d bridge \
  --subnet=10.11.11.0/24 \
  --ip-range=10.11.11.10/29 \
  --gateway=10.11.11.8 \
  -o parent=bond0 \
  bondbridge

docker run -itd --rm \
  --name flask \
  --hostname apisrv \
  -v /etc/localtime:/etc/localtime:ro \
  -v /pace/:/pace \
  -v /pacedata/:/pacedata/ \
  -v /root/gitrepo/resolv.conf:/etc/resolv.conf \
  --net bondbridge \
  -p 10.11.11.249:5001:5001 \
  -v /TS/:/TS \
  -v /TSd/:/TSd \
  mn/qs:flask3

This setup works perfectly if I replace bond0 with a single NIC (e.g., enp0s8). When using bond0, however, I don’t get the expected connectivity inside containers.

My questions are:

  1. Is there anything special I need to configure in Docker when using a bonded interface (bond0) as the parent?
  2. Is there a better way to make containers inherit fault tolerance from a host bond?
  3. Am I missing a step in the nmcli configuration or Docker network creation?

Solution

  • After a lot of trial and error, I realized I was approaching this problem from the wrong angle and fundamentally misunderstanding how the networking layers interact. My attempts to use docker network create with macvlan or a bridge tied to the bond0 parent were overcomplicating the solution because I was trying to solve a host-level problem inside the container's configuration.

    The correct solution is much simpler: Handle fault tolerance entirely at the host level.

    Docker and its containers don't need any special configuration to use a bond. If the host is configured correctly, the containers will transparently inherit the fault tolerance of the bond when you publish their ports.

    Here is the correct, working procedure:

    1. Create a Robust Bond on the Host

    First, create a true active-backup bond on the host. This mode is critical as it provides fault tolerance without requiring any special configuration on your network switch (like LACP). The key is to create the bond and then apply the options directly to the final connection profile.

    # Create the bond connection
    nmcli conn add type bond con-name 'bond0' ifname 'bond0'
    
    # Create the final connection profile for IP addressing
    # This is where we will apply the bond options
    nmcli conn add type bond con-name 'cmynode' ifname 'bond0' ip4 10.11.11.241/24 ip4 10.11.11.249/24
    
    # CRITICAL STEP: Apply the bond options to the IP-bearing profile
    nmcli conn modify cmynode bond.options "mode=active-backup,miimon=100,fail_over_mac=1"
    
    # Add the physical NICs as slaves
    nmcli conn add type ethernet con-name 'bond-slave-enp0s3' ifname 'enp0s3' master 'bond0'
    nmcli conn add type ethernet con-name 'bond-slave-enp0s8' ifname 'enp0s8' master 'bond0'
    # ...add other slaves...
    
    # Bring up the connection
    nmcli conn up cmynode
    

    At this point, the host itself has a fault-tolerant network connection on the bond0 interface, with the IP addresses 10.11.11.241 and 10.11.11.249.

    2. Run Containers and Publish Ports to the Host IP

    Now, you can completely ignore the Docker network parent options. You don't need to create a special bondbridge. Simply run your container and publish its ports to the IP address that now lives on the bond0 interface.

    My mistake was trying to make Docker manage the bond. The correct approach is to make the host manage the bond, and let Docker simply use the resilient network connection the host provides.