Services, Port-Forward & Expose — Full Reference¶
Reference: https://kubernetes.io/docs/concepts/services-networking/service/
See also:
nslookup.md.mdfor DNS,nodeport.md.mdfor NodePort,clusterIP.md.mdfor ClusterIP internals.
The Exercise — What Went Wrong¶
Expose
nginx-podinternally asnginx-service, then use port-forward to curl the nginx welcome page.
The raw notes mistake: --port=8080 was used to expose, but nginx listens on port 80. So the service had targetPort: 8080 pointing at a port nothing was listening on.
The habit that prevents this:
Always check the pod's actual container port before exposing. That value is your targetPort.
The Fix — Clean Sequence¶
# 1. Check what port the pod is actually on
kubectl describe pod nginx-pod | grep Port
# 2. Expose with the correct port
kubectl expose pod nginx-pod --port=80 --name=nginx-service
# 3. Port-forward in the background
kubectl port-forward service/nginx-service 9090:80 &
# 4. Curl it
curl localhost:9090
Port Confusion — The Full Table¶
| Name | Where | What it is |
|---|---|---|
containerPort |
Pod spec | Port the app inside the container listens on. Informational only. |
targetPort |
Service spec | Port traffic is forwarded TO on the container. Must match what's actually listening. |
port |
Service spec | Port the Service itself listens on. What other pods use to reach it. |
nodePort |
Service spec (NodePort only) | Port opened on every node for external access. |
| local port | port-forward |
Port on YOUR machine. What you curl locally. |
For the nginx exercise:
curl localhost:9090
↓ port-forward
service:80 (--port=80 on expose)
↓ service routes
pod:80 (targetPort defaults to port value)
↓
nginx container (actually listening on 80)
Why it broke: --port=8080 set both port and targetPort to 8080. Service routed to port 8080 on the pod. Nothing was listening on 8080. Connection refused.
kubectl expose — Full Breakdown¶
| Part | What it does |
|---|---|
pod nginx-pod |
Resource to expose |
--port=80 |
Service port AND targetPort (both default to this when --target-port is omitted) |
--name=nginx-service |
Name of the Service object |
With explicit targetPort (when app port ≠ service port):
Service listens on 80, routes to container port 8080.All expose options:
kubectl expose pod <name> --port=80 --name=svc-name # ClusterIP (default)
kubectl expose pod <name> --port=80 --type=NodePort # NodePort
kubectl expose deployment <name> --port=80 --target-port=8080 # from deployment
kubectl expose pod <name> --port=80 --dry-run=client -o yaml # generate YAML only
kubectl port-forward¶
port-forward tunnels a local port on your machine to a port on a pod or service inside the cluster. Traffic doesn't go through the Service's load balancing — it goes directly.
kubectl port-forward pod/nginx-pod 9090:80 # directly to pod
kubectl port-forward service/nginx-service 9090:80 # to service (preferred)
kubectl port-forward deployment/nginx-dep 9090:80 # to deployment (picks one pod)
& — run in background:
Without &, port-forward blocks the terminal — you can't type anything else. & puts it in the background so you can curl immediately. To stop it: kill %1 or fg then Ctrl+C.
When port-forward is useful: - Testing a service without exposing it externally - Accessing admin UIs (Kubernetes dashboard, Prometheus, Grafana) locally - Debugging — connect directly to the pod bypassing the service
Port-forward is not for production. It's a developer/debugging tool. In production, use Ingress or LoadBalancer.
Diagnosing a Broken Service¶
Step 1 — Does the service exist?
Step 2 — Does it have endpoints (pods)?
Step 3 — What port is the pod actually on?
Step 4 — Does the service port match?
Step 5 — Test connectivity from inside the cluster:
Quick Reference¶
# Check pod port first
kubectl describe pod <pod> | grep Port
# Expose
kubectl expose pod <pod> --port=80 --name=<svc>
kubectl expose pod <pod> --port=80 --target-port=8080 --name=<svc>
kubectl expose deployment <dep> --port=80 --name=<svc>
# Port-forward
kubectl port-forward service/<svc> <local-port>:<svc-port>
kubectl port-forward service/<svc> 9090:80 & # background
curl localhost:9090 # test
# Diagnose
kubectl get endpoints <svc> # should show pod IPs, not <none>
kubectl describe svc <svc> # check Port + TargetPort