Kubernetes imposes a flat network model with specific guarantees. Understanding these guarantees — and how they're implemented — is essential for debugging connectivity issues, designing NetworkPolicies, and choosing CNI plugins.

1. The Three Guarantees

Kubernetes requires that any networking implementation (CNI plugin) satisfies these rules:

#GuaranteeMeaning
1Every Pod gets its own IPNo sharing. Containers within a Pod share an IP (via pause container), but each Pod has a unique cluster-wide IP.
2Pods can communicate with all other Pods without NATPod A on Node 1 can reach Pod B on Node 2 using Pod B's IP directly. No port mapping. No translation.
3Agents on a node can communicate with all Pods on that nodekubelet, kube-proxy, and node-local daemons can reach Pods directly.
The "no NAT" rule is the key insight. Unlike Docker's default bridge networking (where containers use private IPs behind port-mapped NAT), Kubernetes Pods have routable IPs visible across the entire cluster. When Pod A connects to Pod B, Pod B sees Pod A's real IP as the source. This simplifies service discovery, logging, and security policies.

What This Looks Like in Practice

# Pod on node-1:
kubectl exec pod-a -- ip addr
# eth0: 10.244.1.5/24   ← Pod IP (unique across cluster)

# Pod on node-2:
kubectl exec pod-b -- ip addr
# eth0: 10.244.2.8/24   ← Different subnet, same flat network

# Connectivity test (no NAT, no port mapping):
kubectl exec pod-a -- curl 10.244.2.8:8080
# Works directly — flat network

Network Planes in a Cluster

Node Network (e.g., 192.168.1.0/24) Physical/VM IPs — nodes talk to each other here Pod Network (e.g., 10.244.0.0/16) — "Cluster CIDR" Virtual overlay — each Pod gets an IP from this range Service Network (e.g., 10.96.0.0/12) — "Service CIDR" Virtual IPs (ClusterIPs) — not routable, implemented by kube-proxy/eBPF Pod IPs are routable across nodes. Service IPs exist only in iptables/IPVS/eBPF rules.
NetworkCIDR ExampleConfigured ByRoutable?
Node network192.168.1.0/24Infrastructure (cloud VPC, bare metal)✅ Physical
Pod network (Cluster CIDR)10.244.0.0/16CNI plugin (--cluster-cidr)✅ Virtual overlay or routed
Service network (Service CIDR)10.96.0.0/12API server (--service-cluster-ip-range)❌ Virtual only (kernel rules)

2. Pod-to-Pod Communication

Same Node

On the same node, Pods are connected via a virtual bridge (typically cbr0 or cni0). Each Pod has a veth pair — one end in the Pod's network namespace, the other plugged into the bridge.

Node (worker-1) cni0 bridge (10.244.1.0/24) Pod A 10.244.1.5 veth Pod B 10.244.1.6 Pod C 10.244.1.7 eth0 (node)

Traffic between Pod A and Pod B stays on the bridge — no routing needed, just L2 switching.

Cross-Node

When Pod A (node-1) talks to Pod D (node-2), the packet must leave node-1 and reach node-2. CNI plugins solve this differently:

ApproachHowUsed By
Overlay (VXLAN/Geneve)Encapsulate Pod packet inside a UDP packet between nodesFlannel (VXLAN), Calico (optional), Cilium (optional)
Direct routingConfigure host routes so Pod CIDRs are routable via node IPsCalico (BGP), Cilium (native routing)
Cloud routesCloud VPC route tables know which node owns which Pod CIDRGKE, EKS VPC CNI, Azure CNI
Node 1 (192.168.1.10) Pod A 10.244.1.0/24 Node 2 (192.168.1.11) Pod D 10.244.2.0/24 VXLAN tunnel / BGP route / VPC route src: 10.244.1.5 → dst: 10.244.2.8 (no NAT!)
Overlay vs routing trade-off: Overlays work everywhere (no infra changes needed) but add ~50 bytes of encapsulation overhead and slight latency. Direct routing is faster (no encap) but requires infrastructure support (BGP peering or cloud route tables). Cloud-native CNIs (EKS VPC CNI) assign Pod IPs from the VPC itself — no overlay, no routing config, native performance.

3. IP Allocation

How Pods Get IPs

  1. The cluster has a Cluster CIDR (e.g., 10.244.0.0/16)
  2. Each node gets a Pod CIDR subset (e.g., node-1 gets 10.244.1.0/24 = 254 Pods max)
  3. When a Pod is created, the CNI plugin assigns the next available IP from the node's Pod CIDR
  4. The IP is released when the Pod is deleted
# See node Pod CIDR:
kubectl get nodes -o custom-columns=\
NAME:.metadata.name,\
POD-CIDR:.spec.podCIDR
# NAME       POD-CIDR
# worker-1   10.244.1.0/24
# worker-2   10.244.2.0/24
# worker-3   10.244.3.0/24

IP Exhaustion

If a node's Pod CIDR is /24, it can host at most 254 Pods (minus a few reserved). Larger nodes (or many short-lived Pods) can exhaust this. Solutions:

  • Use a larger per-node CIDR (--node-cidr-mask-size=23 = 510 IPs)
  • Use a CNI that doesn't subdivide (EKS VPC CNI allocates from the entire VPC subnet)
AWS EKS with the VPC CNI allocates real VPC IPs to Pods. This means Pod IPs are routable from outside the cluster (VPN, other services) — powerful but can exhaust VPC address space quickly. Plan your VPC CIDR carefully: a /16 VPC with hundreds of Pods per node gets tight fast.

4. CNI — Container Network Interface

CNI is a specification for how network plugins are invoked. The kubelet calls CNI plugins at two points:

  1. ADD — when a Pod sandbox is created (assign IP, set up veth, configure routes)
  2. DEL — when a Pod sandbox is removed (release IP, remove interfaces)

Popular CNI Plugins

PluginApproachNetworkPolicy?Best For
FlannelVXLAN overlay❌ NoSimple clusters, learning
CalicoBGP routing or VXLAN✅ YesBare metal, hybrid, enterprise
CiliumeBPF (no iptables)✅ Yes (L3-L7)High performance, observability, service mesh
AWS VPC CNIVPC-native IPs✅ Yes (via Calico add-on)EKS
Azure CNIVNet-native IPs✅ YesAKS
Weave NetMesh overlay✅ YesMulti-cloud (less popular now)
CNI plugin choice determines: (1) Whether you get NetworkPolicy support. (2) Performance characteristics (overlay overhead vs native). (3) IP management strategy. (4) Advanced features (eBPF, L7 policies, encryption). Choose carefully — changing CNI on a running cluster is disruptive.

5. Communication Types

CommunicationMechanismExample
Container → Container (same Pod)localhostApp talks to sidecar on localhost:9090
Pod → Pod (same node)Bridge (L2 switch)Direct by Pod IP
Pod → Pod (cross-node)CNI (overlay/route)Direct by Pod IP — no NAT
Pod → Servicekube-proxy (iptables/IPVS/eBPF)ClusterIP → DNAT to Pod IP
External → PodNodePort / LoadBalancer / IngressClient → LB → Service → Pod
Pod → ExternalSNAT (node IP) by defaultPod makes API call to external service

Egress: SNAT Behavior

When a Pod connects to an external service (outside the cluster), the node SNATs the Pod IP to the node's IP. The external service sees the node IP as the source, not the Pod IP.

# Pod 10.244.1.5 on node 192.168.1.10 connects to external API:
# Source: 10.244.1.5 → SNAT → 192.168.1.10
# External API sees source: 192.168.1.10

# Exception: some CNIs (Calico, Cilium) can disable SNAT
# for specific destinations or when using direct routing
SNAT matters for firewall rules: if an external service allowlists by IP, you need to allowlist all node IPs (or use a NAT gateway with a fixed IP). In AWS, use a NAT Gateway with Elastic IP so all egress traffic has a predictable source IP regardless of which node the Pod runs on.

6. Debugging Network Issues

# Check Pod IP:
kubectl get pod -o wide

# Test connectivity from inside a Pod:
kubectl exec debug-pod -- curl -v http://10.244.2.8:8080
kubectl exec debug-pod -- nslookup my-service.default.svc.cluster.local
kubectl exec debug-pod -- wget -qO- --timeout=2 http://my-service:80

# Deploy a network debug Pod:
kubectl run netshoot --image=nicolaka/netshoot -it --rm -- bash
# (has curl, dig, nslookup, tcpdump, iperf, ss, ip, traceroute)

# Check node routing:
kubectl debug node/worker-1 -it --image=ubuntu -- ip route

# Check CNI logs:
kubectl logs -n kube-system -l app=calico-node --tail=50

# Check kube-proxy rules (iptables mode):
kubectl debug node/worker-1 -it --image=ubuntu -- iptables-save | grep my-service
For CKA networking questions: (1) Always start with kubectl get pod -o wide to see IPs and nodes. (2) Use kubectl exec to test connectivity from inside a Pod. (3) Check DNS resolution with nslookup. (4) The nicolaka/netshoot image is your best friend for debugging — it has every network tool.

Summary

ConceptKey Point
Flat networkEvery Pod gets a unique IP; all Pods can reach all Pods without NAT
Three networksNode (physical), Pod (Cluster CIDR), Service (Service CIDR)
Same-nodeveth pairs connected to a bridge — L2 switching
Cross-nodeOverlay (VXLAN) or direct routing (BGP/cloud routes)
IP allocationCluster CIDR → per-node Pod CIDR → individual Pod IP via CNI
CNIPlugin spec (ADD/DEL); determines overlay vs routing, policy support
Egress SNATPod → external: source NAT to node IP (external sees node IP)
Service IPsVirtual — exist only in kernel rules, not routable

📝 Quiz: The Kubernetes Network Model

Q1: Pod A (10.244.1.5) on node-1 connects to Pod B (10.244.2.8) on node-2. What source IP does Pod B see?

10.244.1.5 (Pod A's real IP). The K8s network model guarantees no NAT for Pod-to-Pod communication. Pod B sees the actual source Pod IP regardless of which node it's on.

Q2: Pod A connects to an external API at 8.8.8.8. What source IP does the external API see?

The node's IP (e.g., 192.168.1.10). For egress traffic leaving the cluster, SNAT translates the Pod IP to the node IP. The external service has no knowledge of Pod IPs. (Exception: some CNIs can preserve Pod IP for specific destinations.)

Q3: What's the difference between an overlay network and direct routing for cross-node Pod traffic?

Overlay: Encapsulates the Pod packet inside a UDP packet (VXLAN/Geneve). Works on any infrastructure (no router changes needed). Adds ~50 bytes overhead and slight latency.
Direct routing: Programs routes in the network (BGP or cloud VPC route tables) so Pod CIDRs are natively routable. No encapsulation overhead, better performance, but requires infrastructure support.

Q4: A node has Pod CIDR 10.244.1.0/24. How many Pods can it host (maximum)?

~254 Pods (2^8 - 2 = 254 usable host addresses, minus gateway and broadcast). In practice, kubelet also has a --max-pods setting (default 110) which may limit it further. The IP space allows 254, but kubelet defaults may cap it lower.

Q5: You chose Flannel as your CNI plugin. Can you use NetworkPolicies?

No. Flannel does not implement NetworkPolicy. You can create NetworkPolicy objects (the API server accepts them), but they won't be enforced — Flannel has no policy engine. You'd need to add Calico as a policy-only overlay alongside Flannel, or switch to a CNI that supports policies (Calico, Cilium, Weave).

Q6: Service IPs (ClusterIPs) like 10.96.0.1 — can you ping them?

No (usually). ClusterIPs are virtual — they exist only as DNAT rules in iptables/IPVS. There's no actual interface listening on that IP. ICMP (ping) doesn't trigger DNAT rules (which match TCP/UDP port combinations). TCP connections work because they match the kube-proxy rules and get redirected to a real Pod IP.