fix: do not require CNI plugins for compose projects that avoid CNI - #5132
Conversation
haytok
left a comment
There was a problem hiding this comment.
Totally LGTM, but I've left a comment.
| // demand. Creating it eagerly made every compose command require a CNI plugin, | ||
| // even for projects whose services all use network_mode: host or none. |
There was a problem hiding this comment.
nit:
Creating it eagerly made every compose command require a CNI plugin,
even for projects whose services all use network_mode: host or none.
This PR's commit message includes these comments, so they are redundant. It can be shortened, so WDYT?
There was a problem hiding this comment.
Good catch, shortened to just the reason the call site needs. The rest only
described the history, which the commit message already carries. Amended and
force-pushed as b073d7c3.
On the 4 red jobs in this run: none of them are from this change, which is
comment-only. The previous head had a single red (in-host / windows), and that
one is still the same wall-clock assertion in TestRunRmTime.
The other three look like current repo-wide flakiness rather than anything here.
TestLoadQuiet is also red on #5131 and TestSave on #5136, both dependabot PRs
that touch no Go code, and #5136 additionally fails TestComposeRemove and
TestComposeRestart on EL / almalinux-8.
TestIPFSCompNoBuild is the one I looked at hardest, since it lives in
ipfs_compose_linux_test.go and this PR changes compose networking. It fails at
kubo.go:78 with context deadline exceeded polling the kubo HTTP API, and the
captured container log shows ipfs init had only just finished. That helper
starts the server with a plain nerdctl run -d -p ... and polls the published
host port, so it never goes through the compose path this PR touches. The
container started and got its address; the daemon just was not answering yet.
Happy to rebase or re-push if you want a clean run.
compose.New unconditionally passed netutil.WithDefaultNetwork to NewCNIEnv, so every compose command created nerdctl's default bridge network before parsing a single service. On a host without the CNI plugins installed this failed outright, even for projects whose services all use network_mode: host or none and so never touch CNI. The default network is not needed there. NetworkExists, the only consumer of the CNIEnv built in compose.New, is called exclusively with project-scoped network names, and external networks return before reaching it. Services that do attach to the default bridge still get it created on demand, because compose shells out to `nerdctl run`, which ensures the default network via cniNetworkManager. Fixes containerd#4461 Signed-off-by: Ravi Arnan <raviarnankeren@gmail.com>
7553726 to
b073d7c
Compare
Fixes #4461
Problem
On a host with no CNI plugins installed, every
nerdctl composecommand fails, even when noservice in the project uses CNI networking:
Docker starts this project fine, and so does
nerdctl run --net hoston current main.Cause
compose.Newpassednetutil.WithDefaultNetwork(...)toNewCNIEnv, which creates nerdctl'sdefault bridge network as a side effect of constructing the environment. That happens before any
service has been parsed, so it applies to every compose invocation regardless of what the services
actually ask for.
The default network is not needed there. The only consumer of that
CNIEnvisNetworkExists, andboth call sites (
up_network.go,down.go) invoke it exclusively with project-scoped names such asmyproject_default. External networks return before reaching it. Nothing in the compose path readsthe default bridge.
Services that genuinely use the default bridge are unaffected: compose shells out to
nerdctl run,and that path ensures the default network through
cniNetworkManagerwhen it is actually needed.Fix
Drop
WithDefaultNetworkfrom theCNIEnvbuilt incompose.New. One-line change plus a commentexplaining why the eager creation is deliberately absent.
Verification
Built from this branch and compared against an unpatched build of the same commit, on Zorin OS 18
(kernel 6.17), containerd 2.3.3, runc 1.4.3.
--cni-pathand--cni-netconfpathwere used tosimulate a host without plugins, so neither
/opt/cni/binnor/etc/cni/net.dwas involved.compose up,network_mode: host, empty CNI pathfailed to create default network, service never rancompose up, ordinary project on its_defaultbridge network, real pluginscompose up,network_mode: bridge, real plugins, empty netconf dirnerdctl-bridge.conflistwas created on demand by therunpathCase C is the one the change could plausibly break, and it confirms the default network is still
created when a service actually asks for the bridge.
The
TestComposeUp,TestComposeDownandTestComposeCreateselection was also run against bothbuilds from identical host state (leftover nerdctl bridges deleted between runs, since a stale
bridge holding 10.4.0.0/24 makes the next run fail the default network overlap check):
Of the four failures on the unpatched build, one is the new regression test below, and the other
three are
TestComposeCreatePulland two of its subtests failing on an IPv6 timeout reachingghcr.io. That one is unrelated to this change and passes on the unpatched build when the registry
is reachable. No test regressed.
For the plain
runhalf of the issue report, bothnerdctl run --net hostandnerdctl run --net nonealready succeed on unpatched main with no CNI plugins present, so thathalf appears to have been fixed previously. Details are in the issue thread.
Test
TestComposeUpNetworkModeHostWithoutCNIPluginsrunscompose up -don anetwork_mode: hostproject with
--cni-pathand--cni-netconfpathpointing at empty directories. It fails onunpatched code with the error above and passes with the fix.
Note the test needs both flags. Pointing only
--cni-pathat an empty directory is not enough,because a default network config left in the real netconf dir by an earlier test would satisfy
GetDefaultNetworkConfigand the creation attempt would never happen.