What You'll Learn
How Kubernetes networking works — from Pod-to-Pod communication via CNI, exposing apps with Services (ClusterIP, NodePort, LoadBalancer), to routing external traffic via Ingress Controllers.
The Kubernetes Networking Model
Kubernetes imposes several fundamental rules on how networking must work in a cluster:
- Every Pod gets its own unique IP address (no need to map container ports to host ports)
- Pods can communicate with all other Pods across nodes without NAT
- Agents on a node (like system daemons) can communicate with all Pods on that node
1. The Container Network Interface (CNI)
Kubernetes doesn't implement the network itself. It relies on a CNI plugin (like Calico, Flannel, Cilium, or Weave) to assign IPs and set up routing between nodes.
2. Services — Stable IPs for Pods
Pods are ephemeral — they die and get new IPs. A Service provides a stable IP address and DNS name that load balances traffic across a set of Pods.
ClusterIP (Default)
Exposes the Service on an internal IP. Only reachable from within the cluster.
NodePort
Exposes the Service on each Node's IP at a static port (30000-32767). Also creates a ClusterIP.
LoadBalancer
Provisions a cloud load balancer (AWS ELB, GCP LB) that routes to the NodePort.
apiVersion: v1
kind: Service
metadata:
name: my-backend-api
namespace: production
spec:
type: ClusterIP # Only accessible inside the cluster
selector:
app: my-backend # Routes traffic to Pods with this label
ports:
- name: http
port: 80 # The port the Service listens on
targetPort: 3000 # The port the container is listening on
# Other pods can now access it via DNS:
# http://my-backend-api.production.svc.cluster.local:80
3. Ingress — HTTP/HTTPS Routing
A LoadBalancer service gives you 1 IP per service (expensive!). Ingress provides a single entry point that routes external HTTP/S traffic to different internal services based on hostname or URL path.
Ingress requires an Ingress Controller (like Nginx, Traefik, or AWS ALB Controller) running in the cluster to actually process the rules.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api-ingress
namespace: production
annotations:
# Tell the cluster to use the Nginx Ingress Controller
kubernetes.io/ingress.class: "nginx"
# Automatic SSL cert generation via cert-manager
cert-manager.io/cluster-issuer: "letsencrypt-prod"
# Nginx-specific settings
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/proxy-body-size: "8m"
spec:
tls:
- hosts:
- api.example.com
secretName: api-tls-cert # Cert-manager stores the cert here
rules:
- host: api.example.com
http:
paths:
# Route /users to the user-service
- path: /users
pathType: Prefix
backend:
service:
name: user-service
port:
number: 80
# Route everything else to the main-api
- path: /
pathType: Prefix
backend:
service:
name: main-api
port:
number: 80
4. Network Policies — Cluster Firewall
By default, all Pods in a cluster can talk to all other Pods (even across namespaces). NetworkPolicies let you restrict traffic for security (Zero Trust).
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: db-access-policy
spec:
# Apply this policy to database pods
podSelector:
matchLabels:
app: postgres-db
policyTypes:
- Ingress
ingress:
- from:
# ONLY allow traffic from backend-api pods
- podSelector:
matchLabels:
app: backend-api
ports:
- protocol: TCP
port: 5432
Debugging Kubernetes Networking
# Verify endpoints (Does the service see the pods?)
kubectl get endpoints my-service
# If it says , your selector labels don't match your pods!
# Port forward to a service locally (bypasses ingress)
kubectl port-forward svc/my-service 8080:80
# Check Ingress controller logs
kubectl logs -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx
# Spin up a debug pod to test internal DNS and connectivity
kubectl run netshoot --rm -i --tty --image nicolaka/netshoot -- bash
# Inside the pod:
# nslookup my-service.default.svc.cluster.local
# curl http://my-service:80