
September 11, 2026
14 min read
By Kokil Thapa | Last reviewed: September 2026
CNI Plugins Compared: Calico, Cilium, Flannel is the question every platform team hits once a Kubernetes cluster leaves the lab. The Container Network Interface (CNI) decides how pods get IP addresses, how traffic routes between nodes, and whether you can enforce zero-trust rules at the network layer. Flannel keeps things simple. Calico adds BGP routing and mature policy. Cilium pushes eBPF for observability and security. This guide walks through architecture, trade-offs, and real install paths so you can choose without guessing. If you run Linux system administration alongside application work, the CNI choice affects every deploy that follows.
What is a CNI plugin and why does Kubernetes need one?
Every pod in Kubernetes needs a routable IP address. The kubelet does not assign that address itself. Instead it calls a CNI plugin when a pod starts. The plugin configures the pod network namespace, attaches a virtual interface, and reports the IP back to the API server. Without a working CNI, pods stay in ContainerCreating forever.
The CNI specification is vendor-neutral. Any plugin that implements the standard binary interface can plug into kubeadm, k3s, RKE2, EKS, GKE, or a bare-metal cluster you built on Ubuntu. That portability is why the comparison matters. You are not picking a library inside one app. You are picking the data plane for every workload on the cluster.
A CNI plugin typically handles three jobs. IP address management (IPAM) assigns pod CIDR blocks. Data-plane setup creates veth pairs or tunnel interfaces. Optional policy enforcement applies Kubernetes NetworkPolicy or vendor extensions. Flannel stops after connectivity. Calico and Cilium add policy layers on top.
On clusters I help maintain for enterprise application development clients, the CNI choice often outlives the first application team. Switching later means draining nodes and replatforming. Treat this as infrastructure architecture, not a checkbox during cluster bootstrap.
Core CNI concepts you will see in every comparison
- Overlay networking: Encapsulates pod traffic in VXLAN or Geneve tunnels between nodes. Works on any L3 network but adds header overhead.
- Routing (non-overlay): Pod subnets are advertised via BGP or static routes. Lower latency, but your underlay must support it.
- NetworkPolicy: Layer-3/Layer-4 firewall rules scoped to pods. Not all CNIs implement it.
- IPAM modes: Host-local, Kubernetes host-local, Calico IPAM, or Cilium cluster-pool — each affects IP exhaustion and scaling.
The official Kubernetes network plugins documentation lists CNI as the standard extension point. That page is the authoritative starting point before you read vendor-specific guides.
How does Flannel compare to Calico and Cilium for basic pod networking?
Flannel is the simplest of the three. CoreOS (now maintained by the community) built it to give every pod an IP and basic cross-node connectivity. It uses a cluster-wide overlay — typically VXLAN — and a bridge on each node. Setup takes minutes on a small cluster.
Calico defaults to a routed model without encapsulation when your network supports it. It can fall back to VXLAN or WireGuard overlays when needed. Pod IPs sit in IP pools you define per node or per block. BGP peering with top-of-rack switches is a first-class feature.
Cilium replaces iptables-heavy paths with an eBPF dataplane. Pod networking still uses a tunnel or native routing mode, but packet handling runs in the kernel via eBPF programs. That design reduces per-connection overhead at scale and opens doors for L7 policy without a sidecar.
Flannel in practice
Flannel ships a single daemonset and a ConfigMap. The default backend is VXLAN. Host-gw mode removes encapsulation when nodes share an L2 segment. Flannel does not implement Kubernetes NetworkPolicy. If you need pod-to-pod firewall rules, pair Flannel with a separate policy engine or accept that security stays at the application layer.
# Flannel ConfigMap excerpt (kube-flannel-cfg)
net-conf.json: |
{
"Network": "10.244.0.0/16",
"Backend": {
"Type": "vxlan"
}
}
Flannel fits k3s defaults, homelab clusters, and early-stage platforms where the goal is "pods can talk to each other." It is not wrong for production at small scale. It becomes limiting when compliance asks for micro-segmentation or when you need per-namespace egress control.
Calico in practice
Calico runs calico-node on every host and optionally calico-kube-controllers in the cluster. Felix programs iptables or eBPF rules depending on your chosen dataplane. Typha caches datastore reads on large clusters. The Calico documentation covers operator installs on EKS, AKS, and bare metal.
Calico's sweet spot is multi-team platforms that need NetworkPolicy today and might need WireGuard encryption or eBPF acceleration tomorrow. Many managed Kubernetes offerings expose Calico as an optional CNI because support teams already know it.
Cilium in practice
Cilium installs via Helm or the Cilium CLI. The agent runs privileged with CAP_SYS_ADMIN so it can load eBPF programs. Enable Hubble for flow visibility — it is the feature that most often tips teams toward Cilium over Calico. See the dedicated Cilium eBPF networking for Kubernetes write-up for deeper eBPF mechanics.
Cilium also supports Cluster Mesh for multi-cluster networking and can replace kube-proxy entirely when you enable kube-proxy replacement. That removes another iptables layer from the data path.
How do Calico network policies differ from Cilium's eBPF enforcement?
Kubernetes NetworkPolicy is a standard API object. It defines ingress and egress rules by pod label, namespace, and port. What differs between CNIs is how faithfully and how efficiently they enforce those rules — and what extensions they add beyond the standard.
Calico implements standard NetworkPolicy plus Calico NetworkPolicy and GlobalNetworkPolicy CRDs. Those add host endpoint rules, egress to external CIDR blocks, and ordering semantics Felix understands. Enforcement historically used iptables. Calico's eBPF dataplane mode reduces rule churn on high-churn clusters.
Cilium implements NetworkPolicy and adds CiliumNetworkPolicy with L7 rules. You can allow HTTP GET to /api/health while denying POST to the same path. DNS-aware policy lets you allow egress to *.s3.amazonaws.com without opening all of AWS. Enforcement happens in eBPF at the hook point before packets hit the slow path.
Example NetworkPolicy both CNIs understand
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-api-from-frontend
namespace: production
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080
Apply that manifest and both Calico and Cilium enforce it. Flannel ignores it unless you install a separate policy provider — which is why running two CNIs on one cluster is a common anti-pattern.
Policy design intersects with how you expose services. If you run a service mesh or ingress controller, align policy with those layers. The Kuma and Consul Connect compared article covers mesh-side mTLS, which complements but does not replace CNI policy.
Which CNI plugin should you choose for production in 2026?
There is no universal winner. The right choice depends on cluster size, compliance requirements, team familiarity, and whether your underlay supports BGP. The table below summarises what platform engineers actually weigh.
| Criteria | Flannel | Calico | Cilium |
|---|---|---|---|
| Primary data plane | VXLAN overlay (default) | BGP routing or VXLAN/WireGuard | eBPF (VXLAN or native routing) |
| Kubernetes NetworkPolicy | Not supported natively | Full support + Calico CRDs | Full support + L7 CiliumNetworkPolicy |
| Observability | Basic metrics only | Flow logs (commercial Tigera) | Hubble UI and metrics built-in |
| kube-proxy replacement | No | Partial (eBPF dataplane) | Yes, mature eBPF kube-proxy replacement |
| Multi-cluster | Manual | Calico Enterprise features | Cluster Mesh |
| Operational complexity | Low | Medium | Medium–high (kernel/BPF requirements) |
| Typical fit | Dev, edge, k3s, small prod | General-purpose production | Security-focused, high-scale, observability-heavy |
Use Flannel when you need pod networking fast and security policy lives elsewhere — for example behind an API gateway with rate limiting and abuse prevention at the application edge. Use Calico when you want a proven default with strong docs and broad cloud support. Use Cilium when eBPF, Hubble, and L7 policy justify the learning curve.
Managed Kubernetes defaults matter
Amazon EKS defaults to the AWS VPC CNI, not any plugin in this comparison. GKE offers Dataplane V2 powered by Cilium. AKS lists Azure CNI and Calico as options. On self-managed clusters built with kubeadm on Ubuntu 24.04, you pick the CNI explicitly. Document that choice in your runbook alongside backup and upgrade procedures covered in support and maintenance planning.
Cost and staffing reality for Nepal and small teams
Smaller teams often run a single cluster for staging and production namespaces. Flannel on k3s keeps monthly cloud spend lower when you do not need policy. A law-firm portal or booking platform on Kubernetes — similar to workloads behind Adventure Third Pole Trek — rarely needs Cilium on day one. Add Calico when client data segregation becomes a contract requirement.
Enterprise Tigera Calico and Isovalent Cilium Enterprise add support SLAs. Open-source builds of both are production-grade without licensing fees. Budget Rs 0 for software; budget engineer time for upgrades and kernel compatibility testing instead.
How do you install and migrate between CNI plugins safely?
Installing a CNI on a fresh cluster is straightforward. Migrating live workloads is painful because every node holds state in iptables, eBPF maps, or bridge FDB tables. Plan migrations during a maintenance window with a node drain strategy similar to blue-green vs canary deployment thinking.
Install Calico with the operator on a new cluster
- Install the Tigera operator:
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.29.0/manifests/tigera-operator.yaml - Apply a custom resource matching your pod CIDR:
kubectl apply -f custom-resources.yaml - Verify:
kubectl get pods -n calico-systemuntil all agents report Ready - Confirm IPAM:
calicoctl ipam checkif you installed calicoctl
Install Cilium with Helm
helm repo add cilium https://helm.cilium.io/
helm install cilium cilium/cilium --version 1.16.0 \
--namespace kube-system \
--set kubeProxyReplacement=true \
--set hubble.enabled=true \
--set hubble.relay.enabled=true \
--set hubble.ui.enabled=true
Confirm eBPF programs loaded: cilium status from a Cilium CLI install. Kernel 5.10 or newer is recommended for full feature support. Test on one node before rolling cluster-wide.
Install Flannel on kubeadm
kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
Ensure your kubeadm podSubnet matches Flannel's Network CIDR in the ConfigMap. A mismatch produces pods with IPs outside the routed range — a failure mode I've seen on hand-built clusters where the init config was copied from an old gist.
Migration checklist
- Drain and cordon one node at a time; never run two CNIs on the same node.
- Delete old CNI daemonsets and ConfigMaps after the new CNI passes conformance tests.
- Reapply NetworkPolicy manifests; label selectors survive but enforcement backend changes.
- Run
kubectl run tmp-shell --rm -it --image=nicolaka/netshoot -- /bin/bashand test cross-namespace DNS and egress. - Update monitoring dashboards — Cilium exposes Prometheus metrics on port 9962; Calico on Felix metrics endpoints.
Validate YAML and policy manifests with a JSON formatter or regex tester when debugging label selectors. Small typos in podSelector labels silently open holes in policy.
GitOps workflows should pin CNI versions in Helm values or manifests committed to Git. The FluxCD vs ArgoCD GitOps compared guide applies the same discipline here: treat CNI config as infrastructure code, not a one-time kubectl apply.
Performance and troubleshooting tips
Overlay overhead shows up under heavy east-west traffic. Benchmark with iperf3 between pods on different nodes before and after enabling WireGuard or switching from VXLAN to native routing. For observability gaps, wire CNI metrics into your stack alongside guidance from metrics, logs, and traces compared.
Admission webhooks and policy controllers add startup latency. Read admission controllers and validating webhooks to understand ordering when Cilium or Calico injects sidecars or validates security contexts at schedule time.
Multi-cloud designs should align CNI choice with interconnect strategy. The active-active vs active-passive multi-cloud article covers failover patterns that assume stable pod networking across zones.
Key Takeaways
- Flannel delivers basic pod connectivity with minimal ops overhead but no native NetworkPolicy — fine for dev and small prod, limiting for regulated workloads.
- Calico is the balanced production default: BGP routing, strong L4 policy, wide cloud support, and an optional eBPF dataplane when iptables churn hurts.
- Cilium suits teams that want eBPF performance, Hubble flow visibility, L7 policy, and kube-proxy replacement in one CNI.
- Never run two CNIs on the same node; migrate by draining nodes and switching daemonsets during a planned window.
- Match pod CIDR in kubeadm or cloud config to your CNI IPAM pool — mismatches cause silent routing failures.
- Document your CNI choice in GitOps repos and revisit when compliance, multi-cluster, or observability requirements change.
People Also Ask
Can you use Flannel and Calico together?
Some older guides suggested Flannel for networking plus Calico for policy only. That dual-CNI pattern is deprecated and unsupported on modern Kubernetes. Pick one primary CNI. Both Calico and Cilium provide connectivity and policy in a single stack.
Is Cilium faster than Calico?
Cilium's eBPF dataplane reduces iptables rule evaluation on high-connection workloads. Calico's eBPF mode narrows the gap. Real-world speed depends on kernel version, connection churn, and whether kube-proxy is in the path. Benchmark your actual traffic pattern before switching for performance alone.
Which CNI does k3s use by default?
k3s ships with Flannel as the default CNI. You can disable it and install Calico or Cilium instead by passing --flannel-backend=none at server start and applying your chosen manifest. Many edge clusters in bandwidth-constrained regions stay on Flannel for simplicity.
Do you need a service mesh if you use Cilium?
Cilium provides L7 policy and mutual TLS via Cilium Mesh or ingress integration. A full service mesh still adds retries, traffic splitting, and multi-cluster identity features. Many teams use Cilium for network policy and a mesh only where advanced traffic management is required.
Pick your CNI, then lock it in Git
CNI Plugins Compared: Calico, Cilium, Flannel comes down to policy need, observability appetite, and team capacity. Flannel keeps bootstrap friction low. Calico remains the safe general-purpose choice for production Kubernetes in 2026. Cilium rewards teams ready to invest in eBPF and Hubble. Whichever you choose, pin versions, test NetworkPolicy before go-live, and treat the dataplane as long-lived infrastructure — not a swap-you-later detail.
Platform decisions like this sit next to OS choice and CI design. If you are standardising infrastructure for application teams, see how RHEL, Rocky Linux, and AlmaLinux compared for the node OS layer, or review load balancing algorithms for traffic entering the cluster. Need help designing or hardening a production stack? Contact us to discuss your cluster architecture and deployment workflow.
Frequently Asked Questions
0 Comments
Leave a comment
Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

