Container & Kubernetes Networking
A Network Per Pod
Containers changed how applications are packaged, and they also changed networking. Each container needs an IP address, containers on the same host must be isolated, and in an orchestrator like Kubernetes, pods must reach each other across nodes as if they were on a single flat network. The systems that make this work are worth understanding.
Docker's Default Networking
Docker ships several network drivers:
- bridge (default): containers get addresses on a private bridge (e.g.,
172.17.0.0/16) and reach the outside world through NAT. Containers on the same bridge can talk to each other by IP. - host: the container shares the host's network namespace—fast, but no isolation.
- overlay: containers across multiple hosts join a virtual network (VXLAN-based), the basis of Docker Swarm.
- macvlan: the container gets a real MAC and IP on the physical network, appearing as a first-class LAN device.
- none: no networking at all, useful for isolated batch jobs.
The Kubernetes Networking Model
Kubernetes imposes a few simple rules that make networking predictable:
- Every pod gets its own unique IP, cluster-wide.
- Pods can communicate with every other pod without NAT.
- Nodes can communicate with all pods.
- Containers within a pod share the same network namespace and can talk over
localhost.
This flat model is powerful but demanding—it requires a CNI (Container Network Interface) plugin to allocate pod IPs and route traffic across nodes. Popular CNIs include Calico, Cilium, Flannel, and Weave Net. Some use overlays (VXLAN), others program routes directly (BGP), and advanced ones (Cilium) use eBPF for policy and observability.
Services: Stable Virtual IPs
Pod IPs are ephemeral; pods come and go. Kubernetes Services provide a stable virtual IP (ClusterIP) and DNS name that load-balances across a set of pods selected by labels. There are several types:
- ClusterIP: internal-only virtual IP.
- NodePort: exposes the service on every node's IP at a static port.
- LoadBalancer: provisions a cloud load balancer in front of the service.
- ExternalName: a DNS alias to an external host.
- Headless: no virtual IP; DNS returns all pod IPs directly (used for stateful sets).
The actual routing is implemented by kube-proxy (iptables/IPVS) or, increasingly, by the CNI/eBPF datapath.
Ingress and the Edge
Ingress resources (and the newer Gateway API) route external HTTP/HTTPS traffic to services by hostname and path, usually through an ingress controller (NGINX, Traefik, Envoy). This is where TLS termination, host-based routing, and rate limiting typically live—the Kubernetes equivalent of a reverse proxy layer.
Network Policy
By default, every pod can reach every other pod. NetworkPolicies restrict that: default-deny ingress and egress, then allow only specific flows. This is the primary defense against lateral movement inside a cluster. On clusters that support it, policies are enforced at the CNI level per pod or namespace.
DNS Inside the Cluster
Kubernetes runs a cluster DNS (CoreDNS) that resolves Service names to their virtual IPs and provides records for pods. Pods are configured to use it automatically. Debugging "why can't service A reach service B" almost always starts with DNS resolution, then network policy, then endpoint readiness—in that order.
Debugging Tools
kubectl exec into a pod and try nslookup, curl, and nc. Check kubectl get endpoints to confirm the service has ready backends. Inspect policies and CNI logs. Because the network is entirely software-defined, most "network" problems are actually configuration problems—wrong selectors, missing endpoints, or an over-restrictive policy.