Use port-forwarding to access pods
Learn how to use kubectl port-forward to access your Kubernetes pods locally. Hands-on guide with troubleshooting and next steps.
Focus: use port-forwarding to access pods
You have a web application running inside a Kubernetes Pod, but you can't reach it from your browser because the Pod lives in a cluster network that your laptop can't see. You could expose it with a Service of type LoadBalancer, but that costs money and takes minutes to provision—definitely not the right tool for debugging. kubectl port-forward solves this exact problem by creating a direct tunnel from your local machine to a specific Pod, letting you test endpoints, databases, and APIs in seconds without changing any cluster resources.
The problem this lesson solves
Kubernetes Pods are assigned cluster-internal IP addresses (e.g., 10.42.0.10) that are only reachable from within the cluster. If you want to access a Pod's web UI, query its REST API, or inspect a Prometheus metrics endpoint, you traditionally have two options:
- Expose a Service – Requires creating a
ClusterIP,NodePort, orLoadBalancerobject. That adds overhead, changes resource definitions, and for cloud LoadBalancers can take 30+ seconds and incur cost. - SSH into a cluster node – Niche, slow, and requires node-level access.
Port-forwarding gives you a third, faster path: a temporary, local-only tunnel that bypasses Services entirely. It's perfect for debugging, manual testing, and one-off admin tasks. The problem it solves is access latency—both in terms of time to first byte and time to rethink your architecture.
Core concept / mental model
Think of kubectl port-forward as creating a personalized, one-way data pipe between your local machine and a specific Pod. The Pod doesn't know you're from outside the cluster—it sees the connection as coming from inside.
How it works under the hood
kubectluses your kubeconfig to authenticate with the Kubernetes API server.- The API server establishes a connection to the Pod via the kubelet running on the node where the Pod is scheduled.
- A local TCP socket opens on your chosen port (e.g.,
localhost:8080). - Traffic sent to that local socket gets proxied through the API server → kubelet → Pod container, and responses flow back.
Pro tip: Port-forwarding does not create a Kubernetes Service or Endpoint object. It's purely a client-side operation. No other cluster members or users can use this tunnel.
How it works step by step
Prerequisites
- A running Pod with a container that listens on a known port (e.g., port 80 for Nginx, port 5432 for Postgres).
kubectlconfigured with access to your cluster.
Step 1 – Identify the Pod
kubectl get pods
NAME READY STATUS RESTARTS AGE
my-web-app-6b7f8c9d4-x2k3p 1/1 Running 0 12m
Step 2 – Choose local and remote ports
You'll map a local port (e.g., 4000) to a remote port inside the Pod (e.g., 5000 for a Flask app, 3000 for a Node.js app).
kubectl port-forward pod/my-web-app-6b7f8c9d4-x2k3p 4000:5000
Forwarding from 127.0.0.1:4000 -> 5000
Forwarding from [::1]:4000 -> 5000
Handling connection for 4000
Step 3 – Test the connection
Open a second terminal and use curl or your browser:
curl http://localhost:4000/healthz
{"status": "ok"}
You're now talking directly to the Pod's application, as if it were running locally.
Hands-on walkthrough
Let's run through a full example with a simple Python HTTP server Pod.
1. Create a test Pod
# simple-server.yaml
apiVersion: v1
kind: Pod
metadata:
name: test-server
spec:
containers:
- name: py-server
image: python:3.10-slim
command: ["python", "-m", "http.server", "8888"]
ports:
- containerPort: 8888
kubectl apply -f simple-server.yaml
kubectl wait --for=condition=Ready pod/test-server
2. Forward a port
kubectl port-forward pod/test-server 8888:8888 &
The & runs it in the background. You'll see:
Forwarding from 127.0.0.1:8888 -> 8888
3. Access the Pod
curl http://localhost:8888/
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Directory listing for /</title>
</head>
<body>
...
You've just port-forwarded to a Python HTTP server running in a Kubernetes Pod.
4. Forwarding to a Service (alternative)
You can also forward to a Service instead of a Pod:
kubectl port-forward service/my-service 8080:80
This load-balances across the Service's Pods, which can be useful for testing a Service endpoint without exposing it externally.
Compare options / when to choose what
| Method | Setup time | Persistence | Use case |
|---|---|---|---|
kubectl port-forward |
Instant | Session-only (dies with process) | Debugging, manual testing, one-off admin tasks |
kubectl expose + NodePort |
Seconds | Persistent (until deleted) | Quick internal access without cloud LB |
Service of type LoadBalancer |
30s–2min | Persistent (costs money) | Production traffic from internet |
Ingress |
Minutes | Persistent | TLS termination, host-based routing |
When to choose port-forwarding: - You're debugging a single Pod's behavior. - You need to access a database Pod from your local GUI client. - You want to test a service that isn't exposed yet. - You're on a development cluster without external load balancer support (e.g., Minikube, Kind, or local K3s).
When not to use it:
- For production traffic (use a Service or Ingress).
- When multiple people need concurrent access (each person needs their own port-forward).
- For long-running connections (port-forwarding is not designed for high availability).
Troubleshooting & edge cases
Common error: "unable to do port forwarding: error upgrading connection"
This usually means the Pod is down, the API server can't reach the node's kubelet, or the Pod doesn't have the specified port open.
Fix:
kubectl describe pod <pod-name> # Check Events and container ports
kubectl logs <pod-name> # Verify the application is listening
Error: "Address already in use"
Local port 4000 is already taken by another process.
Fix:
- Kill the existing kubectl port-forward process: pkill -f "port-forward"
- Or choose a different local port: kubectl port-forward pod/my-pod 6000:5000
Port forwarding drops after a few seconds
Kubernetes API server has an idle timeout (often 5 minutes). If no data flows, it may close the connection.
Fix: Keep the connection alive with periodic requests, or use a tool like curl --keepalive-time 60.
Forwarding to a UDP-only service
kubectl port-forward only supports TCP. For UDP applications (e.g., DNS, some game servers), you'll need a NodePort or a LoadBalancer.
What you learned & what's next
You now understand:
- How kubectl port-forward creates a temporary TCP tunnel from your local machine to a Pod or Service.
- How to forward traffic to specific ports, including multiple ports simultaneously (kubectl port-forward pod/my-pod 8080:80 443:443).
- When to use port-forwarding vs. Services vs. Ingress.
- How to diagnose common issues like "address already in use" and "unable to do port forwarding".
Next step: Now that you can access Pods directly, you're ready to learn about ConfigMaps and Secrets — how to inject configuration into your Pods without rebuilding images. This skill complements port-forwarding by helping you debug configuration issues before you even scale your app.
Hands-on exercise: Create two Pods (one Nginx on port 80, one custom app on port 3000). Use kubectl port-forward to access both simultaneously from different local ports. Verify you can reach both, then delete the setup with kubectl delete pod ....
Practice recap
Create a Pod that runs a simple Nginx web server on port 80. Use kubectl port-forward pod/nginx-pod 8080:80 and navigate to http://localhost:8080 in your browser. Then, experiment with the --address flag to allow another workstation on the same LAN to access the tunnel (remember security implications). Finally, delete the Pod and clean up any background port-forward processes with pkill -f "port-forward".
Common mistakes
- Forgetting to include the
pod/prefix:kubectl port-forward pod/my-pod 8080:80— omitting it may forward to a Service by default. - Forwarding to a Pod that hasn't started its application yet — check
kubectl logsfirst to confirm the port is actually open. - Using
localhostfrom a container inside the cluster: Port-forwarding only works from the machine that runskubectl, not from inside other Pods. - Expecting UDP support:
kubectl port-forwardhandles TCP only; UDP services need a different approach.
Variations
- Forward to multiple ports at once:
kubectl port-forward pod/my-pod 8080:80 443:443opens two tunnels in one command. - Forward to a Service instead of a Pod:
kubectl port-forward service/my-service 8080:80distributes traffic across the Service's endpoints. - Use
--addressto bind to all interfaces:kubectl port-forward --address 0.0.0.0 pod/my-pod 8080:80allows other machines on your network to connect (use with caution).
Real-world use cases
- Debugging a microservice's REST endpoint live in a dev cluster without exposing it to the internet.
- Connecting a local GUI database client (like pgAdmin) directly to a Postgres Pod running in Kubernetes.
- Testing a Prometheus exporter's metrics endpoint from a local laptop before setting up ServiceMonitor rules.
Key takeaways
kubectl port-forwardcreates a client-side TCP tunnel from your local machine to a Pod or Service.- It requires zero changes to your cluster resources — no Services, no load balancers, no extra network policies.
- Always specify the Pod or Service resource type explicitly (
pod/orservice/) to avoid confusion. - Port-forwarding is session-scoped: it dies when you press Ctrl+C or the process terminates.
- It only supports TCP — not UDP. Use NodePort or LoadBalancer for UDP workloads.
- Common errors like 'address already in use' or 'unable to do port forwarding' can be solved by checking port availability, Pod logs, and kubectl connectivity.
Keep learning
Related tutorials, quizzes, and articles for this topic.
Discussion
Questions, corrections, and tips help everyone reading this page.
0 comments
Add a comment
No comments yet — start the thread.