DevOps Peach

Docker & Kubernetes · Kubernetes Services and Ingress · Lesson 2 of 3

NodePort, LoadBalancer, ExternalName

NodePort opens one port on every node, LoadBalancer asks the cloud for an external IP, ExternalName is a DNS alias to an outside service.

Practice interactively →

flowchart LR
  U["External client"] --> LB["LoadBalancer<br/>203.0.113.40:80"]
  LB --> NP["NodePort :31000<br/>on every node"]
  NP --> CIP["ClusterIP :80"]
  CIP --> P["pod :8080"]

Each type includes the previous one: LoadBalancer ⊃ NodePort ⊃ ClusterIP.

Type Reached at Notes
ClusterIP Inside the cluster only Default
NodePort <NodeIP>:<nodePort> from outside Port in the 30000–32767 range, opened on every node; calling a node without a pod still works (one extra hop)
LoadBalancer External IP/hostname from the cloud On self-built clusters/minikube, EXTERNAL-IP stays <pending> without MetalLB or minikube tunnel
ExternalName A DNS name in the cluster Only creates a CNAME record to externalName; no proxy, no endpoints
spec:
  type: NodePort
  selector: { app: web }
  ports:
  - { port: 80, targetPort: 8080, nodePort: 31000 }

Common traps:

Command Meaning
kubectl expose deployment web --type=NodePort --port=80 --target-port=8080 --name=web-np Create a NodePort
kubectl get svc web-np PORT(S) column like 80:31000/TCP
kubectl create service externalname ext-db --external-name db.example.com DNS alias to the outside

LoadBalancer in the cloud

On EKS, AKS, or GKE, creating a LoadBalancer Service makes the cloud controller provision a real load balancer. Annotations choose options such as internal versus internet-facing:

Cloud Example annotation for an internal load balancer
AWS (Load Balancer Controller) service.beta.kubernetes.io/aws-load-balancer-scheme: internal
Azure service.beta.kubernetes.io/azure-load-balancer-internal: "true"
GCP networking.gke.io/load-balancer-type: "Internal"

Each LoadBalancer Service costs money and uses a public IP, so for many HTTP apps one Ingress or Gateway in front is cheaper.

Bare-metal clusters

Without a cloud provider, MetalLB or the load balancer built into k3s (ServiceLB) assigns external IPs from a pool you define and announces them on the LAN, filling EXTERNAL-IP so LoadBalancer Services work like in the cloud.

Preserving the client IP

By default, traffic arriving at a NodePort or LoadBalancer may be forwarded to a pod on another node, and the source IP is replaced. externalTrafficPolicy: Local sends traffic only to pods on the receiving node and keeps the real client IP, which matters for logging and IP allowlists; the load balancer's health checks then skip nodes without a pod.

Restricting who can connect

loadBalancerSourceRanges limits which client CIDRs may reach a LoadBalancer Service, for example an office range, and the cloud provider turns it into firewall rules.

Choosing a type

Need Choose
Internal calls between services ClusterIP
Quick test from your laptop kubectl port-forward
Simple external access in a lab NodePort
Production TCP/UDP service (database proxy, MQTT, game server) LoadBalancer
Many HTTP/HTTPS apps behind one entry point Ingress or Gateway API in front of ClusterIP Services
Alias to an outside DNS name ExternalName

Whatever the type, the Service selects pods the same way; only how traffic reaches the ClusterIP changes.

Practice interactively →