Kubernetes Networking Ingress

Kubernetes Networking: Services, Ingress & CNI Explained

CM
Carlos Mendez
Cloud Architect
May 01, 2025
20 min read

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.

Flannel
Simple layer 3 overlay network. Great for beginners, but no network policy support.
Calico
Industry standard. High performance BGP routing + rich NetworkPolicy support.
Cilium
Next-gen eBPF-based networking. High performance, advanced observability.
AWS VPC CNI
EKS default. Pods get native AWS VPC IP addresses.

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.

service.yaml
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.

ingress.yaml — Host and Path routing + SSL
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).

networkpolicy.yaml
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

bash
# 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

Keep Reading

D
DevOps

Docker Networking Demystified: Bridge, Host & Overlay

8 min read Read More
C
Cloud

AWS IAM Roles vs Users vs Policies

10 min read Read More
P
Programming

Understanding Python's GIL & Multiprocessing

14 min read Read More