diff --git a/cmd/nerdctl/compose/compose_up_linux_test.go b/cmd/nerdctl/compose/compose_up_linux_test.go index 97f06b37fe0..4ac9af1163b 100644 --- a/cmd/nerdctl/compose/compose_up_linux_test.go +++ b/cmd/nerdctl/compose/compose_up_linux_test.go @@ -1423,3 +1423,44 @@ services: testCase.Run(t) } + +func TestComposeUpNetworkModeHostWithoutCNIPlugins(t *testing.T) { + testCase := nerdtest.Setup() + + // --cni-path and --cni-netconfpath are nerdctl specific. + testCase.Require = require.Not(nerdtest.Docker) + + testCase.Setup = func(data test.Data, helpers test.Helpers) { + dockerComposeYAML := fmt.Sprintf(` +services: + svc0: + image: %s + network_mode: host + command: "sleep infinity" +`, testutil.CommonImage) + + data.Labels().Set("composeYAML", data.Temp().Save(dockerComposeYAML, "compose.yaml")) + // An empty CNI_PATH and an empty netconf dir together mimic a host that never + // installed the CNI plugins. Services using host networking do not need them. + data.Labels().Set("cniPath", data.Temp().Dir("cni-bin")) + data.Labels().Set("cniNetConfPath", data.Temp().Dir("cni-netconf")) + } + + testCase.Command = func(data test.Data, helpers test.Helpers) test.TestableCommand { + return helpers.Command( + "--cni-path", data.Labels().Get("cniPath"), + "--cni-netconfpath", data.Labels().Get("cniNetConfPath"), + "compose", "-f", data.Labels().Get("composeYAML"), "up", "-d") + } + + testCase.Expected = test.Expects(expect.ExitCodeSuccess, nil, nil) + + testCase.Cleanup = func(data test.Data, helpers test.Helpers) { + helpers.Anyhow( + "--cni-path", data.Labels().Get("cniPath"), + "--cni-netconfpath", data.Labels().Get("cniNetConfPath"), + "compose", "-f", data.Labels().Get("composeYAML"), "down", "-v") + } + + testCase.Run(t) +} diff --git a/pkg/cmd/compose/compose.go b/pkg/cmd/compose/compose.go index 146c4997b99..fbf00600f8e 100644 --- a/pkg/cmd/compose/compose.go +++ b/pkg/cmd/compose/compose.go @@ -52,7 +52,10 @@ func New(client *containerd.Client, globalOptions types.GlobalCommandOptions, op return nil, err } - cniEnv, err := netutil.NewCNIEnv(globalOptions.CNIPath, globalOptions.CNINetConfPath, netutil.WithNamespace(globalOptions.Namespace), netutil.WithDefaultNetwork(globalOptions.BridgeIP)) + // The default network is deliberately not created here. It is only needed by + // services that actually attach to it, and `nerdctl run` already creates it on + // demand. + cniEnv, err := netutil.NewCNIEnv(globalOptions.CNIPath, globalOptions.CNINetConfPath, netutil.WithNamespace(globalOptions.Namespace)) if err != nil { return nil, err }