Skip to main content
Hello, and welcome to this lesson. In this lesson we will learn about the Container Network Interface (CNI) and how it standardizes container networking across different runtimes and platforms. This lesson assumes familiarity with network namespaces — creating isolated network namespaces on a host, connecting namespaces via a bridge network, creating virtual Ethernet pairs (veth) with one end in each namespace and the other attached to a bridge, assigning IP addresses, bringing interfaces up, and enabling NAT / IP masquerade for external connectivity. Docker implements its own bridge networking that follows the same general steps but uses different naming and management conventions. Other container runtimes (rkt, Mesos Containerizer, Kubernetes, etc.) solve the same networking problems with similar workflows and small platform-specific differences:
A dark-blue slide titled "Network Namespaces" showing four columns for Docker, rkt, Mesos, and Kubernetes with their logos and identical numbered steps (1–8) for setting up networking: create network namespace, create bridge, create veth pairs, attach veths, assign IPs, bring interfaces up, and enable NAT/IP masquerade. The layout repeats the same workflow under each platform.
If each project reimplemented this workflow independently, the ecosystem would fragment into many similar—but incompatible—tools. Instead, defining a common standard for how networking plugins should behave and how runtimes should call them enables interoperability. A simple way to think about this is to extract the networking steps into a standalone program (for example, bridge) that performs the tasks necessary to attach a container to a bridge network. The container runtime would invoke that program when creating or deleting a container and provide the network namespace reference:
The command above is an illustrative simplification. In real deployments the CNI specification defines a plugin invocation model where the runtime sets environment variables (for example, CNI_COMMAND, CNI_CONTAINERID, CNI_NETNS, CNI_IFNAME) and passes the network configuration JSON on stdin. The plugin then writes its result JSON to stdout. See the CNI spec for the exact invocation details: https://www.cni.dev/
CNI (Container Network Interface) is the specification that defines this interaction. It standardizes how to write plugin programs and how container runtimes must call them. In the CNI model, responsibilities are separated cleanly:
  • Container runtimes:
    • Create a network namespace for each container.
    • Determine which networks a container should join.
    • Invoke the appropriate CNI plugin(s) when a container is created (ADD) and removed (DEL).
  • CNI plugins:
    • Support the ADD, DEL, and CHECK commands.
    • Accept parameters such as the container ID and the network namespace path.
    • Configure the container’s network (create veth pairs, attach to bridges, assign IPs, configure routes).
    • Return results in a defined JSON format so the runtime knows assigned IPs, routes, and interface details.
To make responsibilities clearer, here is a concise comparison. CNI also standardizes host-side plugin configuration (commonly JSON files under /etc/cni/net.d/) and separates IP address management (IPAM) into distinct plugins. Typical CNI networking plugins include bridge, VLAN, IPVLAN, MACVLAN and platform-specific implementations (for example, Windows), while IPAM plugins include host-local and dhcp. Common CNI plugin types and how they are used: There are many CNI implementations and projects built on the CNI framework — examples include Flannel, Cilium, Project Calico, Weave, and VMware NSX. Because they adhere to the CNI contract, these networking solutions can be used by any runtime that speaks CNI.
A diagram titled "Container Network Interface" showing container platforms (rkt, Mesos, Kubernetes) linked to network plugin types like bridge, VLAN, IPVLAN, MACVLAN and Windows. Below are addressing plugins (host-local, DHCP) and CNI implementations with logos for Flannel, Cilium, VMware NSX and Project Calico.
Important exception: Docker
Docker does not implement CNI; it uses its own Container Network Model (CNM). Because CNM and CNI are different standards, you cannot pass a CNI plugin directly to docker run. To use CNI plugins with Docker you must create the container without a network (for example --network=none) and then invoke CNI plugins manually against the container’s network namespace. Kubernetes uses this same approach when managing Docker containers: it creates containers with --network=none and then calls CNI plugins to complete the networking setup.
Example workflow with Docker + manual CNI invocation:
A minimal example of what a CNI network config might look like (provided to the plugin on stdin) is:
Further reading and references With CNI, container runtimes and networking plugins can evolve independently while remaining interoperable — because both sides implement the same standardized interface for configuring container networks.

Watch Video