Skip to content

nerdctl requires CNI to be installed when running containers with network_mode host #4461

Closed

Description

@vosdev

Description

Running containers with network_mode: host, nerdctl still tries to create a default network even when no containers require one.

Steps to reproduce the issue

  1. Do not have a CNI installed on your host
  2. Try to start a container with network_mode: host (nerdctl run --rm -it --network host alpine sh or nerdctl compose up -d with a compose file with network_mode: host)
FATA[0000] failed to create default network: needs CNI plugin "bridge" to be installed in CNI_PATH ("/opt/cni/bin"), see https://github.com/containernetworking/plugins/releases: exec: "/opt/cni/bin/bridge": stat /opt/cni/bin/bridge: no such file or directory

Describe the results you received and expected

I expected nerdctl to not try to create a default network when none of my containers need one.

Docker is able to start these containers without creating a docker bridge/network

What version of nerdctl are you using?

v2.1.3 (latest)

Are you using a variant of nerdctl? (e.g., Rancher Desktop)

None

Host information

Client:
Namespace: default
Debug Mode: false

Server:
Server Version: 1.7.27
Storage Driver: overlayfs
Logging Driver: json-file
Cgroup Driver: systemd
Cgroup Version: 2
Plugins:
Log: fluentd journald json-file none syslog
Storage: native overlayfs
Security Options:
apparmor
seccomp
Profile: builtin
cgroupns
Kernel Version: 6.14.0-27-generic
Operating System: Ubuntu 25.04
OSType: linux
Architecture: x86_64
CPUs: 6
Total Memory: 3GiB
Name: grafana
ID: 6890ed18-5623-4145-9125-84c57aaed5ae

Activity

  1. mwinters0 commented on Dec 7, 2025

    @mwinters0

    It's not just host -- it looks like the bridge network is always getting created, even with none. This appears specific to v2.2.0, as v2.1.6 behaves correctly. In both cases, I'm using containerd v2.1.5.

    My specifics:
    I'm running a Kubernetes node with Cilium which also (don't ask why) needs to run nerdctl. What happens is:

    1. nerdctl run --net none hello-world
    2. nerdctl creates the bridge network anyway
    3. cilium deletes it
    4. containerd calls runc
    5. runc can't find the "bridge" network:
    nerdctl run hello-world --net none
    
    FATA[0000] failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: error during container init: error running createRuntime hook #0: exit status 1, stdout: , stderr: time="2025-12-07T06:51:51Z" level=fatal msg="no such network: \"bridge\""
    
  2. kamlane commented on Dec 29, 2025

    @kamlane

    I'm seeing this same behavior with containerd 1.7.28 and nerdctl version 2.2.1 however I have cilium installed.

  3. ravi-arnan commented on Aug 8, 2026

    @ravi-arnan
    Contributor

    I would like to work on this.

    Reproduced on current main (2.3.5-0.20260805080927-fcaa66c54420, containerd 2.3.3, a host with
    no CNI plugins installed at all). The report splits into two halves that behave differently today:

    The plain run half no longer reproduces. With an empty CNI_PATH, both of these succeed:

    nerdctl run --rm --net host alpine echo OK   ->  OK
    nerdctl run --rm --net none alpine echo OK   ->  OK
    

    NewNetworkingOptionsManager dispatches host and none to their own managers, neither of which
    touches CNI, and the OCI hook already returns early for nettype.Host / nettype.None
    (pkg/ocihook/ocihook.go:178).

    The compose half still fails. With the same empty CNI_PATH:

    services:
      probe:
        image: alpine
        network_mode: host
        command: echo OK
    FATA[0000] failed to create default network: needs CNI plugin "bridge" to be installed in
    CNI_PATH ("/opt/cni/bin") ...
    

    Cause is compose.New (pkg/cmd/compose/compose.go:55), which passes
    netutil.WithDefaultNetwork(...) to NewCNIEnv. That creates nerdctl's default bridge before a
    single service has been parsed, so it happens no matter what network_mode the services declare.
    The CNIEnv built there is only used for NetworkExists, which up_network.go and down.go call
    exclusively with project-scoped names such as myproject_default, and external networks return
    before reaching it. Nothing in that path needs the default bridge to exist.

    @mwinters0 on the v2.1.6 vs v2.2.0 point: I could not confirm a regression window there. Every
    WithDefaultNetwork call site is identical across v2.1.6, v2.2.0 and main, and the diff between
    those two tags in the networking path is checkpoint and healthcheck work that does not touch it.
    One thing worth checking on your side: in the failing command you posted, --net none comes after
    the image name, where it is treated as an argument to the container rather than as a flag. If it
    still reproduces with the flag before the image, that is likely a separate bug and worth its own
    issue.

    PR shortly, with the fix scoped to the compose path plus a regression test.

  4. added a commit that references this issue on Aug 13, 2026
    b073d7c
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions