Skip to content
Documentation Background

Kubernetes Networking Model

  • Kubernetes does not invent its own networking stack - it maps directly onto the TCP/IP five-layer model.
  • Every API object you deploy operates at a specific layer (or bridges layers), with hard constraints on what it can and cannot see.
  • Understanding which layer an object works at tells you immediately what it can inspect, what it can route on, and what it cannot do.

LayerNameProtocol / ConceptKubernetes Object(s)What it can see / do
1PhysicalCables, NICs, radioNode hardware, CNI plugin (physical wiring)Raw bit transmission - no K8s API objects here
2Data LinkEthernet, MAC addressesCNI plugin (Calico, Cilium, Flannel) - ARP, VXLANMAC-level forwarding; MetalLB L2 mode announces Service IPs via ARP at this layer
3NetworkIP, ICMP, routingPod (each gets a routable IP), CNI routing tablesIP-to-IP routing; Pod network model guarantees NAT-less, flat L3 addressability
4TransportTCP, UDP, SCTP, portsService (ClusterIP, NodePort, LoadBalancer), kube-proxy, EndpointSlicesPort-based load balancing and session affinity; cannot inspect HTTP headers or paths
7ApplicationHTTP, gRPC, TLS, DNSIngress, Gateway API, ExternalName (CNAME)Host/path routing, TLS termination, header manipulation, redirects

  • Each Pod gets a unique routable IP on the cluster’s flat L3 network.
  • Pods communicate with each other at Layer 3 - pure IP routing, no NAT.
  • The CNI plugin (Calico, Cilium, Flannel) implements the actual L3 forwarding rules.
  • Cannot discriminate traffic by port or application content on its own - that requires a Service or NetworkPolicy.

Service (ClusterIP / NodePort / LoadBalancer) - Layer 4

Section titled “Service (ClusterIP / NodePort / LoadBalancer) - Layer 4”
  • Services operate purely at L4 (TCP/UDP) via iptables or IPVS rules managed by kube-proxy.
  • They route based on IP + port only - no HTTP headers, no hostnames, no paths.
  • sessionAffinity: ClientIP is L4 stickiness (source IP), not cookie-based (L7).
  • LoadBalancer extends to L4 at the cloud provider boundary - the cloud LB (AWS NLB, GCP LB) is typically also L4 unless you configure an ALB/HTTP LB explicitly.
  • NetworkPolicies are a L3/L4 firewall - they filter on:
    • L3: Pod IP / CIDR / namespace selector
    • L4: port + protocol (TCP/UDP)
  • They cannot filter on HTTP methods, paths, or headers.
  • Enforcement is done by the CNI plugin (not kube-proxy) - NetworkPolicy has no effect without a CNI that supports it (Calico, Cilium do; Flannel alone does not).
  • Ingress controllers (nginx, Traefik, HAProxy) operate at L7 (HTTP/HTTPS).
  • They can route on: hostname (api.example.com), path (/users, /orders), HTTP headers.
  • Handle TLS termination - decrypt HTTPS at the controller, forward plain HTTP to backend Services.
  • Sit in front of ClusterIP Services - the traffic path is: Internet -> Ingress (L7) -> ClusterIP Service (L4) -> Pod (L3).
  • The successor to Ingress, with more expressive L7 routing (header manipulation, traffic weights, cross-namespace references).
  • Also supports L4 routing via TCPRoute / UDPRoute resources for non-HTTP protocols.
  • Splits responsibility across roles: GatewayClass (infra), Gateway (L4 listener config), HTTPRoute (L7 rules).

ExternalName Service - Layer 7 (DNS / CNAME)

Section titled “ExternalName Service - Layer 7 (DNS / CNAME)”
  • ExternalName is purely a DNS trick - it emits a CNAME record at L7 (application-layer DNS).
  • No L4 proxy, no ClusterIP, no kube-proxy involvement.
  • The client resolves the CNAME and connects directly to the external host at L3/L4.
  • The cluster DNS server - operates at L7 (Application layer, DNS protocol).
  • Automatically registers A/AAAA records for every Service and SRV records for named ports.
  • Pods query CoreDNS via a /etc/resolv.conf search path injected by the Kubelet.

flowchart TD
    Client(["fa:fa-globe <b>Internet Client</b>"])
    subgraph Cloud [" <b>Cloud Infrastructure</b> "]
        LB["fa:fa-cloud <b>Cloud Load Balancer</b> [L4: TCP/UDP]<br/>AWS NLB / GCP LB / Azure LB"]
    end
    subgraph Cluster [" <b>Kubernetes Cluster</b> "]
        direction TB
        Ingress["fa:fa-route <b>Ingress Controller Pod</b> [L7: HTTP/HTTPS]<br/>TLS termination • Host & path routing • Header inspection"]
        Svc["fa:fa-network-wired <b>Service / kube-proxy</b> [L4: TCP/UDP]<br/>DNAT to Pod IP:port via iptables / IPVS / eBPF"]
        App["fa:fa-cube <b>Application Pod</b> [L7: Application]<br/>App runtime processes HTTP request"]
        
        Ingress -->|"L4: Proxies to ClusterIP Service"| Svc
        Svc -->|"L3: Routed to Pod IP via CNI"| App
    end
    Client -->|"L3/L4: TCP SYN to cloud LB public IP"| LB
    LB -->|"L4: Forwards to NodePort (30000–32767)"| Ingress

You need to…Use this objectLayer
Expose a backend only to other PodsClusterIPL4
Expose on a node port for bare-metal external accessNodePortL4
Expose with a cloud-managed public IPLoadBalancerL4
Route host.com/path-a vs host.com/path-bIngress / Gateway APIL7
Terminate TLS at the cluster boundaryIngress / Gateway APIL7
Block Pod-to-Pod traffic by namespace or IP rangeNetworkPolicyL3/L4
Give an external hostname a cluster-internal aliasExternalNameL7 (DNS)
Route directly to individual Pod IPs (StatefulSet)Headless ServiceL3
Expose a non-HTTP TCP/UDP service via GatewayTCPRoute / UDPRouteL4