Services and Networking
Kubernetes gives every pod its own IP address. No NAT, no port mapping between pods — container A can talk to container B using B's pod IP directly. This flat networking model is elegant, but pod IPs are ephemeral. Pods die and get replaced constantly, and their IPs change every time. You need a stable way to find and reach your workloads. That's what Services, DNS, and Ingress solve.
Kubernetes Networking — LoadBalancer Traffic Flow
The Networking Model — Every Pod Gets an IP
Kubernetes requires that every pod can communicate with every other pod across nodes without NAT. The Container Network Interface (CNI) plugin you install — Calico, Cilium, Flannel, AWS VPC CNI — implements this requirement. Each plugin does it differently (overlay networks, BGP peering, native VPC routing), but the contract is the same: flat pod-to-pod connectivity.
This means your application code doesn't need to know which node it's running on. A pod on Node 1 talks to a pod on Node 3 the same way it talks to a pod on the same node.
Service Types — Stable Endpoints for Ephemeral Pods
A Service is a stable abstraction over a set of pods selected by labels. When pods come and go, the Service keeps a consistent endpoint.
ClusterIP (default)
Allocates an internal-only virtual IP. Other pods in the cluster can reach the Service, but nothing outside can.
apiVersion: v1
kind: Service
metadata:
name: my-app-svc
spec:
type: ClusterIP
selector:
app: my-app
ports:
- port: 80
targetPort: 8080
NodePort
Exposes the Service on a static port (30000–32767) on every node's IP. Useful for development or when you're running on bare metal without a cloud load balancer.
spec:
type: NodePort
ports:
- port: 80
targetPort: 8080
nodePort: 30080
LoadBalancer
Provisions a cloud load balancer (AWS NLB/ALB, GCP LB, Azure LB) that routes external traffic into the cluster. This is the most common way to expose production services.
ExternalName
A DNS CNAME alias pointing to an external service. No proxying — just DNS resolution. Useful for giving an in-cluster DNS name to an external database or API.
kube-proxy — The Traffic Cop
kube-proxy runs on every node and maintains the networking rules that make Services work. When a pod sends traffic to a Service's ClusterIP, kube-proxy intercepts it and forwards it to one of the backing pods.
Two modes matter:
- iptables mode (default): Creates iptables rules for each Service/endpoint combination. Fast for small clusters, but rule updates become expensive at scale (thousands of Services mean tens of thousands of iptables rules).
- IPVS mode: Uses Linux kernel IPVS (IP Virtual Server) for load balancing. Better performance at scale, supports more load balancing algorithms (round-robin, least connections, weighted). Use this if you have 1000+ Services.
CoreDNS — Service Discovery Without Hardcoding
Every Service gets a DNS entry automatically:
<service-name>.<namespace>.svc.cluster.local
So my-app-svc in the default namespace is reachable at my-app-svc.default.svc.cluster.local. Inside the same namespace, just my-app-svc works.
CoreDNS watches the Kubernetes API for Service changes and updates DNS records in real time. Headless Services (those with clusterIP: None) return individual pod A records instead of a single virtual IP — essential for StatefulSets where you need to address specific pods.
Ingress — HTTP Routing at the Edge
An Ingress resource defines HTTP/HTTPS routing rules — host-based routing, path-based routing, TLS termination. But it's just a spec. You need an Ingress controller (NGINX, Traefik, HAProxy, cloud-native options like AWS ALB Ingress Controller) to actually implement it.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
spec:
rules:
- host: app.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api-svc
port:
number: 80
- path: /
pathType: Prefix
backend:
service:
name: frontend-svc
port:
number: 80
tls:
- hosts:
- app.example.com
secretName: tls-secret
Gateway API — The Future of Ingress
Gateway API is the successor to Ingress, designed to fix its limitations. It separates concerns into three layers:
- GatewayClass: The infrastructure provider (who runs the load balancer)
- Gateway: The actual listener configuration (ports, protocols, TLS)
- HTTPRoute / TCPRoute: The routing rules (what goes where)
This separation means platform teams configure Gateways while application teams define Routes — a much cleaner operational model than Ingress, where everything was lumped into one resource.
The Full Request Path
When an external request hits your cluster, here's the complete chain:
- DNS resolves
app.example.comto the load balancer's IP - Load balancer forwards to a node (NodePort)
- kube-proxy's iptables/IPVS rules rewrite the destination to a pod IP
- The request arrives at the pod's container on the target port
- Response travels back through the same chain
Every hop is observable. When debugging networking issues, start from the pod and work outward: can the pod reach the Service? Can other pods reach it? Can you curl the NodePort from the node? Is the load balancer health check passing?
Enjoyed this breakdown?
Get notified when new lessons go live.