network: add auto-detection of optimal MTU for WireGuard interface, --wg-mtu flag, set max_mtu for Corrosion to 1232

This commit is contained in:
Pasha Sviderski
2026-06-16 21:36:12 +10:00
parent 2f76187bf5
commit 0c3b8b122f
18 changed files with 373 additions and 170 deletions
+35 -5
View File
@@ -19,12 +19,21 @@ import (
"github.com/psviderski/uncloud/pkg/api"
)
// EnsureUncloudNetwork creates the Docker bridge network NetworkName with the provided machine subnet
// if it doesn't exist. If the network exists but has a different subnet, it removes and recreates the network.
// driverMTUOption is the Docker bridge network option that sets the MTU on the bridge and on each container's
// interface attached to the network. It is immutable, so changing it requires recreating the network.
const driverMTUOption = "com.docker.network.driver.mtu"
// EnsureUncloudNetwork creates the Docker bridge network NetworkName with the provided machine subnet and MTU
// if it doesn't exist. The subnet and MTU are immutable Docker network options, so if the existing network has
// a different subnet it is removed and recreated. If it has a different MTU, it is recreated only when no
// containers are attached (otherwise the change is deferred with a warning to avoid disrupting running services).
// It also configures iptables to allow container access from the WireGuard network.
func (c *Controller) EnsureUncloudNetwork(ctx context.Context, subnet netip.Prefix, dnsServer netip.Addr) error {
// Ensure the Docker network 'uncloud' is created with the correct subnet.
func (c *Controller) EnsureUncloudNetwork(
ctx context.Context, subnet netip.Prefix, mtu int, dnsServer netip.Addr,
) error {
// Ensure the Docker network 'uncloud' is created with the correct subnet and MTU.
needsCreation := false
mtuStr := strconv.Itoa(mtu)
nw, err := c.client.NetworkInspect(ctx, NetworkName, dnetwork.InspectOptions{})
if err != nil {
if !errdefs.IsNotFound(err) {
@@ -42,6 +51,24 @@ func (c *Controller) EnsureUncloudNetwork(ctx context.Context, subnet netip.Pref
return fmt.Errorf("remove Docker network '%s': %w", NetworkName, err)
}
needsCreation = true
} else if nw.Options[driverMTUOption] != mtuStr {
// The MTU changed. Recreating the network is the only way to apply it, which is only possible when no
// containers are attached. Don't disrupt running services. Defer the change with a warning otherwise.
if len(nw.Containers) == 0 {
slog.Info("Recreating Docker network to apply new MTU.", "name", NetworkName, "mtu", mtu)
if err = c.client.NetworkRemove(ctx, NetworkName); err != nil {
return fmt.Errorf("remove Docker network '%s': %w", NetworkName, err)
}
needsCreation = true
} else {
slog.Warn("New WireGuard MTU can't be applied to the Docker network because it must be recreated but "+
"it's in use by the running service containers. You can either remove all service containers on the "+
"machine and restart the daemon (uncloud.service). Or disconnect them from the network "+
"(docker network disconnect), restart the daemon, and reconnect them back (docker network connect) "+
"without removing them.",
"name", NetworkName, "current_mtu", nw.Options[driverMTUOption], "desired_mtu", mtu,
"containers", len(nw.Containers))
}
}
if needsCreation {
@@ -63,12 +90,15 @@ func (c *Controller) EnsureUncloudNetwork(ctx context.Context, subnet netip.Pref
// Starting with Docker 28.2.0 (https://github.com/moby/moby/pull/49832), we have to explicitly
// allow direct routing from the WireGuard interface to the bridge network.
"com.docker.network.bridge.trusted_host_interfaces": network.WireGuardInterfaceName,
// Match the container interfaces' MTU to the WireGuard interface so cross-machine container
// traffic is right-sized for the tunnel.
driverMTUOption: mtuStr,
},
},
); err != nil {
return fmt.Errorf("create Docker network '%s': %w", NetworkName, err)
}
slog.Info("Docker network created.", "name", NetworkName, "subnet", subnet.String())
slog.Info("Docker network created.", "name", NetworkName, "subnet", subnet.String(), "mtu", mtu)
if nw, err = c.client.NetworkInspect(ctx, NetworkName, dnetwork.InspectOptions{}); err != nil {
return fmt.Errorf("inspect Docker network '%s': %w", NetworkName, err)