NodePort Service — Full Reference¶
Reference: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport
See also:
nslookup.md.mdfor ClusterIP,kubectl expose, CoreDNS, and DNS verification.
Exam Priority — Quickest Path¶
That's it for basic NodePort creation. If you need a specific nodePort number, you need YAML:
kubectl expose deployment my-app --name=my-svc --port=80 --type=NodePort --dry-run=client -o yaml > svc.yaml
# edit nodePort value in svc.yaml
kubectl apply -f svc.yaml
What Is NodePort¶
NodePort is a Service type that exposes your application on a static port on every node in the cluster. Traffic hitting <any-node-IP>:<nodePort> gets forwarded to the Service, which load balances to the backing pods.
External traffic
↓
<node-ip>:30080 ← NodePort (opens on every node)
↓
Service ClusterIP:80 ← Service routes internally
↓
Pod:8080 ← targetPort (container port)
Three ports involved:
| Port | Where it lives | What it is |
|---|---|---|
nodePort |
On every node's host network | The externally accessible port (30000–32767 range) |
port |
On the Service's ClusterIP | The port the Service listens on internally |
targetPort |
On the container | The port the app actually runs on |
ClusterIP vs NodePort vs LoadBalancer¶
| Type | Accessible from | How |
|---|---|---|
ClusterIP |
Inside cluster only | Stable internal IP + DNS |
NodePort |
Outside cluster | <node-ip>:<nodePort> — any node, same port |
LoadBalancer |
Outside cluster | Cloud provider creates an external load balancer |
NodePort pro: works without a cloud provider — useful for on-prem, bare metal, or testing.
NodePort con: exposes a port on every node (even nodes not running the pod). Port range is limited to 30000–32767. Not suitable for production (use LoadBalancer or Ingress instead).
NodePort YAML — Full Structure¶
apiVersion: v1
kind: Service
metadata:
name: my-nodeport-svc
namespace: default
spec:
type: NodePort
selector:
app: my-app # routes to pods with this label
ports:
- port: 80 # Service's internal port (ClusterIP side)
targetPort: 8080 # container port the app listens on
nodePort: 30080 # external port on every node (30000-32767)
# omit to let Kubernetes auto-assign
protocol: TCP
If you omit nodePort, Kubernetes assigns a random port in the 30000–32767 range. For the exam, check what port was assigned:
Creating NodePort — All Methods¶
Imperative (no control over nodePort number)¶
# From a deployment
kubectl expose deployment my-app \
--name=my-nodeport-svc \
--port=80 \
--target-port=8080 \
--type=NodePort
# From a pod
kubectl expose pod my-pod \
--name=my-nodeport-svc \
--port=80 \
--type=NodePort
YAML (full control, needed for specific nodePort)¶
kubectl expose deployment my-app \
--name=my-nodeport-svc \
--port=80 \
--type=NodePort \
--dry-run=client -o yaml > svc.yaml
# then edit nodePort value in svc.yaml
kubectl apply -f svc.yaml
Testing NodePort Access¶
From inside the cluster (same as ClusterIP):
kubectl run test --image=busybox:1.28 --rm -it --restart=Never -- wget -qO- http://my-nodeport-svc:80
From outside the cluster (using node IP):
# Get node IP
kubectl get nodes -o wide # INTERNAL-IP column
# Hit the nodePort
curl http://<node-ip>:30080
Inspect a NodePort Service¶
kubectl get svc my-nodeport-svc
kubectl describe svc my-nodeport-svc # shows selector, endpoints, NodePort value
kubectl get endpoints my-nodeport-svc # shows pod IPs — if <none>, selector is wrong
# Get just the nodePort number
kubectl get svc my-nodeport-svc -o jsonpath='{.spec.ports[0].nodePort}'
# Get the ClusterIP
kubectl get svc my-nodeport-svc -o jsonpath='{.spec.clusterIP}'
Common Exam Patterns¶
"Expose a deployment externally on port 30080":
kubectl expose deployment my-app --name=my-svc --port=80 --type=NodePort --dry-run=client -o yaml > svc.yaml
# edit: add nodePort: 30080 under ports
kubectl apply -f svc.yaml
"What port is the service exposed on externally?":
"Verify the service routes to the correct pods":
kubectl get endpoints my-svc # shows pod IPs
kubectl get pods -o wide # compare with pod IPs to confirm match
Debugging no traffic:
kubectl get endpoints my-svc # if <none> — selector doesn't match any pods
kubectl describe svc my-svc # check Selector field
kubectl get pods --show-labels # check pod labels match the selector
Quick Reference¶
# Create
kubectl expose deployment NAME --name=SVC --port=80 --type=NodePort
kubectl expose deployment NAME --name=SVC --port=80 --target-port=8080 --type=NodePort
# Inspect
kubectl get svc
kubectl describe svc NAME
kubectl get endpoints NAME
kubectl get svc NAME -o jsonpath='{.spec.ports[0].nodePort}'
# Test
curl http://<node-ip>:<nodePort>
kubectl run test --image=busybox:1.28 --rm -it --restart=Never -- wget -qO- http://SVC-NAME:PORT