Pod IP and the shared network namespace
What you'll learn
- Explain how a Pod gets its IP address and which Linux primitive holds it
- Reason about the shared network namespace between containers in a Pod
- Trace Pod-to-Pod traffic through the CNI and node network stack
- Identify when hostNetwork breaks the Pod network model
Prerequisites
Verified against Kubernetes 1.34.x · kubeadm 1.34.x · kubectl 1.34.x · etcd 3.6.x · CoreDNS 1.11.x · containerd 1.7.x / 2.x · 2026-08-16
Every Pod has one IP address. Every container in the Pod sees that IP and shares the network namespace. This lesson explains how the IP is assigned, how containers share the namespace, and how Pod-to-Pod traffic flows through the CNI.
One IP per Pod
The fundamental Kubernetes network model:
- Every Pod gets its own IP address.
- Pods on any node can communicate with all other Pods without NAT.
- Agents on a node (kubelet, system processes) can communicate with all Pods on that node without NAT.
- Pods in the same node can communicate without NAT.
This is “flat networking” — every Pod has a routable address that any other Pod can reach. The implementation:
- The kubelet on a node receives a Pod to schedule.
- The kubelet calls the CRI (containerd) to create a sandbox container (a paused container that holds the namespaces).
- The kubelet calls the CNI plugin to attach the sandbox’s network namespace to the node network.
- The CNI plugin assigns an IP from the cluster’s Pod CIDR
(e.g.,
10.244.0.0/16) and configures a veth pair connecting the sandbox to a bridge on the node. - The kubelet then asks the CRI to start each container inside the sandbox; each container inherits the sandbox’s network namespace.
flowchart LR
Sandbox["Sandbox<br/>(network namespace)"] --> C1["Container A<br/>(shares net ns)"]
Sandbox --> C2["Container B<br/>(shares net ns)"]
Sandbox --> Veth["veth pair"]
Veth --> Bridge["cbr0 / cni0<br/>(bridge on node)"]
Bridge --> Node["Node NIC"]
Node --> Fabric["Cluster network"]
Fabric --> Pod2["Other Pod"]
The sandbox is a real Linux container (running pause) that
holds the namespaces and stays alive for the lifetime of the
Pod. When the Pod terminates, the kubelet tears down the
sandbox, the veth pair, and the IP is returned to the pool.
Containers share the network namespace
All containers in a Pod share the sandbox’s network namespace. This means:
- They share the same IP address (the Pod IP).
- They share the same ports (no port collisions if they bind to different ports).
- They can communicate over
localhost. - They see each other’s network connections in
netstat,ss, etc.
If container A listens on port 8080 and container B listens
on port 9090, both are accessible on the Pod’s IP at those
ports. Container A can reach container B at
localhost:9090. They share the loopback interface.
kubectl exec web-7c8 -c sidecar -- curl localhost:8080/healthz
# from the sidecar's perspective, port 8080 is localhost
# even though it's the main container's listener
This is the standard sidecar pattern: the sidecar uses
localhost to interact with the main container’s ports,
without going through the Pod IP and the CNI bridge.
How Pod-to-Pod traffic flows
sequenceDiagram
participant App1 as Pod A<br/>container
participant Veth1 as veth on node 1
participant Bridge1 as cbr0 on node 1
participant Fabric as Cluster network
participant Bridge2 as cbr0 on node 2
participant Veth2 as veth on node 2
participant App2 as Pod B<br/>container
App1->>Veth1: send packet to Pod B IP
Veth1->>Bridge1: bridge forward
Bridge1->>Fabric: route to node 2
Fabric->>Bridge2: deliver to node 2
Bridge2->>Veth2: bridge forward
Veth2->>App2: deliver to Pod B
The flow:
- Container in Pod A sends a packet to Pod B’s IP.
- The packet exits through the veth pair (the kernel sees the packet going from the sandbox’s network namespace to the node’s bridge).
- The bridge forwards the packet based on the destination IP. If Pod B is on the same node, the bridge delivers to Pod B’s veth directly. If Pod B is on a different node, the bridge sends the packet up to the node’s routing table.
- The node’s routing table sends the packet out via the node’s NIC, across the cluster network (a routed fabric, often VXLAN or BGP), to the destination node.
- The destination node’s routing table receives the packet, sends it to its bridge, which delivers to Pod B’s veth.
The packet never goes through the host network stack as a host process. Containers communicate directly via the veth and bridge.
How Pod-to-Service traffic flows
Services provide a stable virtual IP for a set of Pods. The kube-proxy on each node watches the API server and configures iptables (or IPVS) rules that DNAT traffic to the Service IP to one of the backing Pod IPs.
sequenceDiagram
participant App as Pod A<br/>container
participant Veth as veth
participant Bridge as cbr0
participant IPTables as iptables<br/>DNAT to Pod B
participant Node as Node NIC
participant PodB as Pod B
App->>Veth: send to Service IP
Veth->>Bridge: bridge forward
Bridge->>IPTables: DNAT rule matches
IPTables->>Node: rewritten to Pod B IP
Node->>PodB: deliver
The flow:
- Container sends a packet to the Service IP (e.g.,
10.96.0.1). - The packet exits via the veth to the bridge.
- The bridge hits iptables (kube-proxy’s rules); the rule matches the Service’s IP and DNATs the destination to one of the backing Pod IPs.
- The packet is rewritten and forwarded normally.
- The destination Pod receives the packet; the source sees the Service IP, not the Pod IP.
kube-proxy implements this in iptables (the default) or IPVS (a hash-table-based virtual server for higher scale). Either way, the Service IP is never assigned to any interface — it is a virtual IP that only exists in the iptables/IPVS rules.
hostNetwork breaks the model
spec:
hostNetwork: true
Setting hostNetwork: true puts the Pod directly on the
node’s network namespace:
- The Pod IP = node IP.
- The Pod sees all node interfaces, all node ports.
- The Pod is reachable on the node’s IP at whatever port it binds.
- The Pod’s ports collide with other hostNetwork Pods on the same node.
Use cases for hostNetwork:
- Node agents (CNI plugins, log shippers) that need to bind on the node’s interfaces.
- Pods that need to access host-local services (e.g., a node-local cache).
- Pods that need to bind a privileged port (e.g., 80) without
configuring the kubelet’s
--allow-privilegedor using unprivileged port mapping.
Risks:
- Port collisions: two hostNetwork Pods on the same node cannot bind the same port.
- Reduced scheduling: only one Pod per node per port.
- Network policy doesn’t apply: traffic to/from hostNetwork Pods bypasses NetworkPolicy (the CNI treats them as different from regular Pods).
Production discipline: avoid hostNetwork except for node
agents. For Pods that need a privileged port, run the
container as non-root with securityContext.capabilities.add: [NET_BIND_SERVICE].
Cross-course references
- The Linux course part
I-Linux-Foundationscovers Linux namespaces (man 7 namespaces); the Pod’s network namespace is the same primitive. - The Docker course part
XXXI-Docker-Networkingcovers container networking; Pod-level networking is the cluster-level equivalent. - The VyOS course part
XXXVII-VyOS-Firewallcovers routed networking; the cluster network is similar in structure.
Quiz
Knowledge check · 4 questions
Q1. What holds the network namespace for a Pod's containers?
Q2. The Service ClusterIP is assigned to an interface on the node so that pods can ARP for it.
Q3. A Pod has two containers: nginx (main, port 8080) and a metrics exporter sidecar that needs to scrape nginx's `/metrics` endpoint. The team wonders whether the sidecar should call `localhost:8080/metrics` or the Pod IP. Diagnose and recommend.
Pod `web-7c8`. Container `nginx` listens on port 8080 (containerPort declared). Container `metrics-exporter` runs every 30s and curls nginx to scrape metrics. The team is debating between `localhost:8080/metrics` (same-Pod communication) and the Pod IP (`10.244.3.7:8080/metrics`)
Q4. When is `hostNetwork: true` the right choice, and what is the production risk?
Passing score: 75%. Answers are checked in this browser.
Production discipline
- Treat Pod IPs as ephemeral. Anything that needs a stable address uses a Service, not a Pod IP.
- Use
localhostfor sidecar-to-main communication. Same-Pod containers share the loopback interface; this is faster and simpler than using the Pod IP. - Avoid
hostNetworkfor application Pods. Reserve it for node agents that genuinely need to bind on the host. - Use
capabilities.add: [NET_BIND_SERVICE]for privileged ports instead of hostNetwork. Let the application bind to a low port without taking over the node’s network namespace. - Inspect the bridge and veth on the node during
debugging.
ip link show,brctl show,iptables -t nat -Lreveal the cluster network state when traffic misbehaves.