Kubernetes Course
Kubernetes Networking Model

Kubernetes imposes a few fundamental networking rules that every conformant cluster must satisfy:
- Every Pod gets its own unique IP address, cluster-wide — no NAT is needed for Pod-to-Pod communication.
- Pods on any node can communicate with Pods on any other node without NAT, as if all Pods were on one flat network.
- Nodes can communicate with all Pods, and vice versa, without NAT.
- A container's view of its own IP is the same IP other Pods see it by — no address translation happens within a Pod.
Kubernetes doesn't implement this networking itself — it delegates to a CNI (Container Network Interface) plugin. Common choices: Calico, Cilium, Flannel, and cloud-specific implementations (AWS VPC CNI, Azure CNI). The CNI plugin is what actually assigns Pod IPs and routes traffic to satisfy the rules above.
Why Ingress? — The Limits of Services
A LoadBalancer Service works well for exposing one application externally, but provisions a separate cloud load balancer per Service — expensive and unwieldy once you have many HTTP services to expose. An Ingress solves this by providing a single entry point that routes external HTTP(S) traffic to many internal Services based on hostname and path.
Ingress Resource
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: app-ingress annotations: nginx.ingress.kubernetes.io/rewrite-target: / spec: ingressClassName: nginx rules: - host: shop.example.com http: paths: - path: /api pathType: Prefix backend: service: name: backend-service port: number: 80 - path: / pathType: Prefix backend: service: name: frontend-service port: number: 80 tls: - hosts: - shop.example.com secretName: shop-tls-secret
rules.hostroutes based on the incomingHostheader — allowing multiple domains to share one Ingress and one external IP.pathsroutes based on URL path —/apitraffic goes to the backend Service, everything else goes to the frontend.tlsterminates HTTPS at the Ingress, referencing akubernetes.io/tlsSecret containing the certificate and key.
Ingress Controllers
An Ingress resource on its own does nothing — it's just a routing specification. An Ingress Controller must be running in the cluster to actually watch Ingress objects and configure a real proxy/load balancer to implement them. Popular choices:
- ingress-nginx: The most widely used, based on NGINX.
- Traefik: Popular for its native support for automatic certificate management and dynamic configuration.
- AWS/GCP/Azure native controllers: Translate Ingress rules directly into the cloud provider's own load balancer.
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/cloud/deploy.yaml kubectl get pods -n ingress-nginx kubectl get ingress
If a cluster has multiple Ingress controllers installed, ingressClassName specifies which one should handle a given Ingress resource.
Network Policies
By default, Kubernetes networking is fully open — any Pod can reach any other Pod, across any namespace, with no restrictions. A NetworkPolicy lets you restrict traffic, implementing a "default deny, then allow specific paths" model similar to a firewall.
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: backend-allow-frontend namespace: production spec: podSelector: matchLabels: app: backend policyTypes: - Ingress ingress: - from: - podSelector: matchLabels: app: frontend ports: - protocol: TCP port: 8080
podSelectorchooses which Pods this policy applies to (here, all Pods labeledapp: backend).ingress.fromwhitelists traffic sources — here, only Pods labeledapp: frontendmay connect, on port 8080. All other inbound traffic tobackendPods is denied.- NetworkPolicies are enforced by the CNI plugin, not the Kubernetes control plane itself — Flannel, for instance, doesn't support NetworkPolicy enforcement at all, while Calico and Cilium do. Check your CNI's capabilities before relying on NetworkPolicies.
A common production pattern is a default-deny policy per namespace, with explicit allow rules layered on top:
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny-all namespace: production spec: podSelector: {} policyTypes: - Ingress - Egress