Merge pull request #50467 from robmry/no_nftables_in_swarm

No nftables in swarm
This commit is contained in:
Rob Murray
2025-07-22 16:58:26 +01:00
committed by GitHub
6 changed files with 50 additions and 7 deletions

View File

@@ -126,6 +126,11 @@ func (conf *Config) IsSwarmCompatible() error {
if conf.LiveRestoreEnabled {
return errors.New("--live-restore daemon configuration is incompatible with swarm mode")
}
// Swarm has not yet been updated to use nftables. But, if "iptables" is disabled, it
// doesn't add rules anyway.
if conf.FirewallBackend == "nftables" && conf.EnableIPTables {
return errors.New("--firewall-backend=nftables is incompatible with swarm mode")
}
return nil
}

View File

@@ -12,6 +12,7 @@ import (
"github.com/docker/docker/testutil"
"github.com/docker/docker/testutil/daemon"
"github.com/moby/moby/api/types/network"
swarmtypes "github.com/moby/moby/api/types/swarm"
"github.com/vishvananda/netlink"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
@@ -494,3 +495,31 @@ func createBridge(t *testing.T, ifName string, addrs []string) net.IP {
}
return llAddr
}
// TestSwarmNoNftables checks that, because swarm does not yet have nftables support,
// it's not possible to:
// - enable Swarm when nftables is enabled, or to
// - restart an already Swarm enabled daemon with nftables enabled as well.
func TestSwarmNoNftables(t *testing.T) {
ctx := testutil.StartSpan(baseContext, t)
skip.If(t, testEnv.IsRemoteDaemon)
skip.If(t, testEnv.IsRootless, "rootless mode doesn't support Swarm-mode")
t.Run("start", func(t *testing.T) {
d := daemon.New(t)
d.Start(t, "--firewall-backend=nftables")
defer d.Stop(t)
err := d.SwarmInitWithError(ctx, t, swarmtypes.InitRequest{AdvertiseAddr: "127.0.0.1:2377"})
assert.Check(t, is.ErrorContains(err, "--firewall-backend=nftables is incompatible with swarm mode"))
})
t.Run("restart", func(t *testing.T) {
d := daemon.New(t)
d.Start(t, "--firewall-backend=iptables")
defer d.Stop(t)
d.SwarmInit(ctx, t, swarmtypes.InitRequest{AdvertiseAddr: "127.0.0.1:2377"})
err := d.RestartWithError("--firewall-backend=nftables")
assert.Check(t, is.ErrorContains(err, "daemon exited during startup"))
})
}

View File

@@ -65,7 +65,7 @@ func TestHostPortMappings(t *testing.T) {
ctx := setupTest(t)
d := daemon.New(t)
d.StartWithBusybox(ctx, t)
d.StartNodeWithBusybox(ctx, t)
defer d.Stop(t)
d.SwarmInit(ctx, t, swarmtypes.InitRequest{AdvertiseAddr: "127.0.0.1:2377"})

View File

@@ -60,7 +60,7 @@ func TestPingSwarmHeader(t *testing.T) {
ctx := setupTest(t)
d := daemon.New(t)
d.Start(t)
d.StartNode(t)
defer d.Stop(t)
apiClient := d.NewClientT(t)
defer apiClient.Close()

View File

@@ -530,10 +530,10 @@ func (d *Daemon) StartWithLogFile(out *os.File, providedArgs ...string) error {
d.args = append(d.args, "--storage-driver", d.storageDriver)
}
hasFwBackendArg := !slices.ContainsFunc(providedArgs, func(s string) bool {
hasFwBackendArg := slices.ContainsFunc(providedArgs, func(s string) bool {
return strings.HasPrefix(s, "--firewall-backend")
})
if hasFwBackendArg {
if !hasFwBackendArg {
if fw := os.Getenv("DOCKER_FIREWALL_BACKEND"); fw != "" {
d.args = append(d.args, "--firewall-backend="+fw)
}

View File

@@ -77,8 +77,8 @@ func (d *Daemon) NodeID() string {
return d.CachedInfo.Swarm.NodeID
}
// SwarmInit initializes a new swarm cluster.
func (d *Daemon) SwarmInit(ctx context.Context, t testing.TB, req swarm.InitRequest) {
// SwarmInitWithError initializes a new swarm cluster and returns an error.
func (d *Daemon) SwarmInitWithError(ctx context.Context, t testing.TB, req swarm.InitRequest) error {
t.Helper()
if req.ListenAddr == "" {
req.ListenAddr = fmt.Sprintf("%s:%d", d.swarmListenAddr, d.SwarmPort)
@@ -93,8 +93,17 @@ func (d *Daemon) SwarmInit(ctx context.Context, t testing.TB, req swarm.InitRequ
cli := d.NewClientT(t)
defer cli.Close()
_, err := cli.SwarmInit(ctx, req)
assert.NilError(t, err, "initializing swarm")
if err == nil {
d.CachedInfo = d.Info(t)
}
return err
}
// SwarmInit initializes a new swarm cluster.
func (d *Daemon) SwarmInit(ctx context.Context, t testing.TB, req swarm.InitRequest) {
t.Helper()
err := d.SwarmInitWithError(ctx, t, req)
assert.NilError(t, err, "initializing swarm")
}
// SwarmJoin joins a daemon to an existing cluster.