Service Mesh adds ‘intelligence’ without the rework. You can extend an applicatoin with authentication, encryption, load-balancing, observability, canary and blue/green deployment etc. without modifying the application.
flowchart LR
subgraph NodeA["Node 1"]
subgraph PodA["Pod A"]
AppA[App Container]
SidecarA[Envoy Sidecar]
AppA <-->|"localhost, redirected by iptables/iptables-nft"| SidecarA
end
end
subgraph NodeB["Node 2"]
subgraph PodB["Pod B"]
SidecarB[Envoy Sidecar]
AppB[App Container]
SidecarB <-->|"localhost, redirected by iptables/iptables-nft"| AppB
end
end
SidecarA -->|mTLS over the network| SidecarB
Every pod carries its own proxy container; all ingress/egress is intercepted and routed through it
Adds a container (memory/CPU) and a network hop per pod, plus startup-ordering races between app and sidecar
eBPF alone can’t parse L7 protocols (HTTP, gRPC, Kafka, etc.); it only sees up through L4
When an L7 policy or L7 visibility requirement exists, Cilium’s eBPF datapath redirects just that traffic to a single Envoy proxy (one per node, not one per pod), which handles the L7 parsing/enforcement, then hands the traffic back to the eBPF datapath
flowchart LR
App["App Container"] -->|socket syscall| Check{{"eBPF: policy check"}}
Check -->|"L3/L4 policy only"| Dest["Destination Pod (via eBPF datapath)"]
Check -->|"L7 policy or visibility needed"| Envoy["Per-Node Envoy Proxy"]
Envoy -->|"HTTP/gRPC/Kafka parsing + L7 rules"| Reinject{{"eBPF: re-inject packet"}}
Reinject --> Dest
Only traffic that actually needs L7 handling takes the Envoy detour; everything else stays on the fast, in-kernel eBPF path
Because Envoy is shared per-node (not per-pod), this avoids the N-sidecars-per-node resource cost of the sidecar model while still supporting full L7 features