Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

CNI Plugins Compared: Calico, Cilium, Flannel

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.

Kubernetes CNI attach sequencekubeletpod createCNI pluginADD callveth pairbridge or routePod IP assignedCNI_CONF returnedCNI responsibilities: IPAM, routing, optional NetworkPolicyFlannel = overlay | Calico = BGP + policy | Cilium = eBPF dataplane
CNI Plugins Compared: Calico, Cilium, Flannel — how the kubelet delegates pod networking to a CNI plugin at runtime.

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.

Three CNI data-plane modelsFlannelVXLAN overlayNo built-in policyLowest ops burdenCalicoBGP or VXLANNetworkPolicy via FelixMature multi-cloudCiliumeBPF in kernelL3-L7 policyHubble observabilityUnderlay: same physical nodes and switches for all threeComplexity rises left to right; policy depth rises with it
Flannel prioritises simplicity; Calico adds routing flexibility and policy; Cilium replaces iptables with eBPF for scale and visibility.

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.

NetworkPolicy enforcement pathsCalico (Felix + iptables/eBPF)Policy sync from APIRule chains per endpointL4 focus; Calico CRDs for extrasCilium (eBPF programs)Policy compiled to BPF mapsL3 through L7 in kernelHubble logs dropped flowsFlannel: no native NetworkPolicyAdd Calico policy controller or use Cilium alongsideNot recommended — pick one primary CNI
Calico and Cilium both enforce Kubernetes NetworkPolicy; Cilium extends to L7 and pairs with Hubble for flow-level debugging.

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.

CriteriaFlannelCalicoCilium
Primary data planeVXLAN overlay (default)BGP routing or VXLAN/WireGuardeBPF (VXLAN or native routing)
Kubernetes NetworkPolicyNot supported nativelyFull support + Calico CRDsFull support + L7 CiliumNetworkPolicy
ObservabilityBasic metrics onlyFlow logs (commercial Tigera)Hubble UI and metrics built-in
kube-proxy replacementNoPartial (eBPF dataplane)Yes, mature eBPF kube-proxy replacement
Multi-clusterManualCalico Enterprise featuresCluster Mesh
Operational complexityLowMediumMedium–high (kernel/BPF requirements)
Typical fitDev, edge, k3s, small prodGeneral-purpose productionSecurity-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.

CNI selection decision treeNeed NetworkPolicy?NoChoose FlannelYesNeed L7 or Hubble?NoChoose CalicoYesChoose CiliumRe-evaluate when compliance or scale changes requirements
A practical decision tree for CNI Plugins Compared: Calico, Cilium, Flannel — start with policy need, then observability depth.

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

  1. Install the Tigera operator: kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.29.0/manifests/tigera-operator.yaml
  2. Apply a custom resource matching your pod CIDR: kubectl apply -f custom-resources.yaml
  3. Verify: kubectl get pods -n calico-system until all agents report Ready
  4. Confirm IPAM: calicoctl ipam check if 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/bash and 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

A Container Network Interface plugin is what gives every pod a routable IP address. The kubelet does not assign that address itself; when a pod starts, it calls the CNI binary, which configures the pod network namespace, attaches a virtual interface, and reports the IP back to the API server. Without a working CNI, pods stay stuck in ContainerCreating forever. The CNI specification is vendor-neutral, so any compliant plugin can plug into kubeadm, k3s, RKE2, EKS, GKE, or a bare-metal cluster you built on Ubuntu. You are picking the data plane for every workload on the cluster, not a library inside one application.

Flannel is the simplest of Calico, Cilium, and Flannel. It ships a single DaemonSet and a ConfigMap, uses a cluster-wide overlay typically VXLAN, and a bridge on each node. Setup takes minutes on a small cluster. Calico runs calico-node on every host plus optional calico-kube-controllers, with Felix programming iptables or eBPF rules and Typha caching reads on large clusters. Cilium installs via Helm or the Cilium CLI, runs privileged agents with CAP_SYS_ADMIN to load eBPF programs, and carries medium-to-high operational complexity because of kernel and BPF requirements.

No. Flannel does not implement Kubernetes NetworkPolicy natively.

Flannel prioritises simplicity: a VXLAN overlay and bridge on each node give every pod an IP and cross-node connectivity, with host-gw mode removing encapsulation when nodes share an L2 segment. Calico defaults to routed pod subnets without encapsulation when your underlay supports it, can fall back to VXLAN or WireGuard overlays, and advertises pod subnets via BGP peering with top-of-rack switches. Cilium still uses tunnel or native routing for pod networking, but packet handling runs in the kernel through eBPF programs instead of iptables-heavy paths, reducing per-connection overhead at scale and opening doors for L7 policy without a sidecar.

Both enforce standard Kubernetes NetworkPolicy by pod label, namespace, and port. Calico adds Calico NetworkPolicy and GlobalNetworkPolicy CRDs for host endpoint rules, egress to external CIDR blocks, and ordering semantics Felix understands; enforcement historically used iptables, with an eBPF dataplane mode to reduce rule churn on high-churn clusters. Cilium adds CiliumNetworkPolicy with L7 rules, so you can allow HTTP GET to one path while denying POST on the same path, plus DNS-aware policy for domains like S3 without opening all of AWS. Cilium enforces in eBPF before packets hit the slow path and pairs with Hubble for flow-level debugging.

There is no universal winner. Use Flannel when you need pod networking fast and security policy lives elsewhere, such as behind an API gateway at the application edge; it fits k3s defaults, homelab clusters, and early-stage platforms. Choose Calico when you want a proven default with BGP routing, strong L4 policy, broad cloud support, WireGuard encryption, and optional eBPF acceleration; many managed offerings expose it because support teams already know it. Pick Cilium when eBPF, Hubble flow visibility, L7 policy, kube-proxy replacement, and Cluster Mesh for multi-cluster networking justify the learning curve and kernel compatibility testing.

Overlay networking encapsulates pod traffic in VXLAN or Geneve tunnels between nodes. It works on any L3 underlay but adds header overhead, which shows up under heavy east-west traffic; benchmark with iperf3 between pods on different nodes before and after switching backends. Routing, or non-overlay, advertises pod subnets via BGP or static routes for lower latency, but your underlay must support it. Flannel defaults to VXLAN overlay. Calico prefers BGP routing without encapsulation when possible and falls back to VXLAN or WireGuard. Cilium supports eBPF with VXLAN or native routing depending on your cluster design.

Flannel offers basic metrics only, which leaves observability gaps unless you wire additional tooling into your stack. Calico provides flow logs through commercial Tigera offerings rather than as a fully built-in open-source UI comparable to Cilium Hubble. Cilium includes Hubble for flow visibility, and enabling Hubble UI and metrics is often the feature that tips teams toward Cilium over Calico. When migrating, update monitoring dashboards: Cilium exposes Prometheus metrics on port 9962, while Calico publishes Felix metrics endpoints. Treat CNI metrics alongside your broader metrics, logs, and traces strategy.

Running two CNIs on one cluster is a common anti-pattern and should be avoided. If you use Flannel and need pod-to-pod firewall rules, pairing it with a separate policy engine is sometimes discussed, but the safe approach during migration is to drain and cordon one node at a time and never run two CNIs on the same node. Delete old CNI DaemonSets and ConfigMaps only after the new CNI passes conformance tests. Reapply NetworkPolicy manifests because label selectors survive but the enforcement backend changes. Test cross-namespace DNS and egress with a temporary netshoot pod before declaring the migration complete.

Open-source builds of Calico and Cilium are production-grade without licensing fees, so budget Rs 0 for software and budget engineer time for upgrades and kernel compatibility testing instead. Enterprise Tigera Calico and Isovalent Cilium Enterprise add support SLAs for teams that need vendor backing. Smaller teams running a single cluster for staging and production namespaces often keep monthly cloud spend lower with Flannel on k3s when policy is not required. Add Calico when client data segregation becomes a contract requirement; Cilium on day one is rarely necessary for simpler booking or portal workloads unless observability and L7 policy are immediate priorities.

Defaults differ by cloud and do not always match self-managed choices. Amazon EKS defaults to the AWS VPC CNI, not Calico, Cilium, or Flannel from this comparison. Google GKE offers Dataplane V2 powered by Cilium. Azure AKS lists Azure CNI and Calico as options. On self-managed clusters built with kubeadm on Ubuntu 24.04, you pick the CNI explicitly during bootstrap. Document that choice in your runbook alongside backup and upgrade procedures, because the CNI choice often outlives the first application team and switching later means draining nodes and replatforming.

On a fresh cluster, installation is straightforward if pod CIDR settings align. Install Calico with the Tigera operator and a custom resource matching your pod CIDR, then verify calico-system pods until agents report Ready and optionally run calicoctl ipam check. Install Cilium with Helm, enabling kube-proxy replacement and Hubble relay and UI if you want visibility, then confirm eBPF programs loaded via cilium status; kernel 5.10 or newer is recommended for full feature support, and test on one node before rolling cluster-wide. Install Flannel by applying the upstream manifest and ensuring kubeadm podSubnet matches Flannel Network CIDR in the ConfigMap.

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 or canary deployment thinking. Drain and cordon one node at a time; never run two CNIs on the same node. After the new CNI passes conformance tests, delete old CNI DaemonSets and ConfigMaps. Reapply NetworkPolicy manifests because enforcement backends change even when label selectors survive. Run cross-namespace DNS and egress tests, update monitoring dashboards for the new metrics endpoints, and pin CNI versions in Helm values or GitOps manifests committed to Git.

A podSubnet mismatch between kubeadm init configuration and Flannel ConfigMap Network CIDR produces pods with IPs outside the routed range. This failure mode appears on hand-built clusters where the init config was copied from an old gist without updating CIDR values. Before applying Flannel, ensure your kubeadm podSubnet matches the Network value in the kube-flannel-cfg ConfigMap net-conf.json. After install, validate connectivity with a temporary netshoot pod and test DNS and egress across namespaces. Small typos in NetworkPolicy podSelector labels can also silently open holes, so validate YAML and policy manifests carefully during troubleshooting.

Flannel suits small clusters needing basic pod networking only, with minimal ops overhead. It fits dev, edge, k3s, and small production environments where the goal is simply that pods can talk to each other and security policy lives at the application layer or behind an ingress gateway. It is not wrong for production at small scale but becomes limiting when compliance asks for micro-segmentation or per-namespace egress control. On clusters I help maintain, the CNI choice often outlives the first application team, so treat Flannel as infrastructure architecture for early platforms, not merely a bootstrap checkbox you plan to replace without a maintenance window.

Share this article

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.

Quick Contact Options
Choose how you want to connect me: