One of the most confusing decisions for engineers new to Kubernetes: how do I expose my application? After managing 20+ EKS clusters at Charter Communications, here's my mental model for choosing the right approach every time.
The Three Options at a Glance
NodePort
A Service type that exposes your app using a high port (30000-32767) on each worker node.
- Simple setup, no external dependencies
- Works in any environment
- Not user-friendly (IP:port access)
- Hard to manage in production
LoadBalancer
Asks your cloud provider to create an external load balancer (e.g. AWS ALB/NLB).
- Easy public access
- Cloud-native integration
- One LB per service = expensive
- No path-based routing
Ingress
Manages HTTP/HTTPS traffic with clean URLs, path/host routing, and TLS termination.
- Clean URLs & path-based routing
- TLS termination & cert management
- Single entry point for many services
- Requires an Ingress Controller
When to Use What: Decision Tree
Quick Decision Guide
Real-World Example: NodePort
apiVersion: v1
kind: Service
metadata:
name: my-app-nodeport
spec:
type: NodePort
selector:
app: my-app
ports:
- port: 80 # Service port (internal)
targetPort: 8080 # Container port
nodePort: 30080 # External port (30000-32767)
# Access: http://<any-node-ip>:30080
Real-World Example: LoadBalancer
apiVersion: v1
kind: Service
metadata:
name: my-app-lb
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing"
spec:
type: LoadBalancer
selector:
app: my-app
ports:
- port: 443
targetPort: 8080
protocol: TCP
# AWS provisions an NLB automatically
# Access: http://<lb-dns-name>
Real-World Example: Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
ingressClassName: nginx
tls:
- hosts:
- api.myapp.com
- app.myapp.com
secretName: myapp-tls
rules:
- host: api.myapp.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-service
port:
number: 80
- host: app.myapp.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: frontend-service
port:
number: 80
# Single LB serves multiple services via host/path routing
Pro Tip from Production
At Charter, we use Ingress with AWS ALB Controller for all HTTP services and LoadBalancer (NLB) for gRPC and raw TCP workloads. The key insight: don't create one LoadBalancer per microservice. With 100+ services, that's 100 AWS load balancers at ~$20/month each = $24,000/year wasted. Use Ingress to fan out from a single entry point.