Skip to main content

Container Network Interface (CNI) in Kubernetes

Kubernetes Header

A Kubernetes cluster's networking isn't implemented by Kubernetes itself: it's delegated to a CNI plugin (Container Network Interface). The kubelet knows a very simple contract — "set up the network for this pod" — and lets the plugin do the work: create virtual interfaces, assign IPs, program routes and apply policies.

Understanding where that configuration lives helps you diagnose network problems that otherwise look like "magic".

Where the configuration lives

On every node, the CNI configuration sits in:

/etc/cni/net.d/

There you'll find one or more *.conf or *.conflist files holding the configuration of the installed plugin (Calico, Cilium, Flannel, Weave, AWS VPC CNI, etc.). For example:

ls /etc/cni/net.d/
# 10-calico.conflist
# calico-kubeconfig

And the plugin binaries live in:

/opt/cni/bin/

If either of these directories is empty or corrupted, new pods will get stuck in ContainerCreating with network plugin is not ready.

How the plugin is invoked

When the kubelet is about to start a pod:

  1. It creates the pod sandbox (a pause container with its own network namespace).
  2. It reads the first valid config in /etc/cni/net.d/ (lexical order).
  3. It runs the corresponding CNI binary from /opt/cni/bin/, passing data over stdin.
  4. The plugin assigns an IP, creates the interface inside the namespace and returns the result.

That's why kubectl get pod may show a pod as Pending or ContainerCreating for a few seconds: it's waiting for the CNI to return the IP.

Quick checks when "networking doesn't work"

From the affected node:

# Is there config?
ls -l /etc/cni/net.d/

# Do the binaries exist?
ls /opt/cni/bin/

# What does the kubelet say?
journalctl -u kubelet -n 200 --no-pager | grep -i cni

From the cluster:

# Is the CNI pod running?
kubectl get pods -n kube-system -l k8s-app=calico-node # adjust the label to your plugin
kubectl describe pod <cni-pod> -n kube-system
kubectl logs <cni-pod> -n kube-system

If the CNI pod is down on a node, that node won't be able to schedule new pods even if it has free CPU and memory.

Things worth remembering

  • The config in /etc/cni/net.d/ is usually installed by the plugin's DaemonSet. Don't edit it by hand unless you know what you're doing; the DaemonSet will overwrite it.
  • Only the first file is used (lexical order). That's why plugins are named 10-…, 20-…, etc.
  • Switching CNI on a production cluster is a delicate operation: it requires draining nodes and typically restarting pod networking.
  • NetworkPolicies only work if the plugin implements them. Plain Flannel, for example, doesn't; Calico and Cilium do.

Knowing /etc/cni/net.d/ looks like a minor detail, but it's the first place to look when an otherwise healthy node stops accepting pods.