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:
bond0
) as the parent?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:
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
.
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.