210

kubectl exposes commands that can be used to create a Service for an application and assigns an IP address to access it from internet.

As far as I understand, to access any application within Kubernetes cluster there should be a Service resource created and that should have an IP address which is accessible from an external network.

But in case of port-forward how does kubectl create a connection to the application without an IP address which is accessible externally?

KnowHoper
  • 4,352
  • 3
  • 39
  • 54
karthikeayan
  • 4,291
  • 7
  • 37
  • 75
  • 3
    Did you read up on https://prefetch.net/blog/2018/02/03/how-the-kubectl-port-forward-command-works/ already? – Michael Hausenblas Jul 22 '18 at 19:19
  • 2
    It's a call via the API server. It's not a general way to avoid needing a Service. It's neither fast nor, in my experience, especially reliable, but it's useful for debugging. – David Maze Jul 22 '18 at 19:22
  • @MichaelHausenblas no, just saw it... now got new qn, how socat port-forwarder does port forwarding? – karthikeayan Jul 22 '18 at 19:31
  • 1
    @DavidMaze possible for you to elaborate? – karthikeayan Jul 23 '18 at 07:34
  • 1
    @karthikeayan found another useful link https://docs.giantswarm.io/guides/accessing-services-from-the-outside/#api-access the actual traffic is going through API server endpoint Ex - https://api.CLUSTER_ID.k8s.gigantic.io/api/v1/proxy/namespaces/NAMESPACE/services/SERVICE_NAME:PORT_NAME/proxy/ – Manoj Badam Aug 29 '18 at 05:43

6 Answers6

211

To start, it's useful to note and remember that in Kubernetes, every pod gets its own ip address from 10.*, that is usable only within the cluster. Now, the port-forward feature of kubectl simply tunnels the traffic from a specified port at your local host machine to the specified port on the specified pod. API server then becomes, in a sense, a temporary gateway between your local port and the Kubernetes cluster.

kubectl port-forward forwards connections to a local port to a port on a pod. Compared to kubectl proxy, kubectl port-forward is more generic as it can forward TCP traffic while kubectl proxy can only forward HTTP traffic.

kubectl port-forward is useful for testing/debugging purposes so you can access your service locally without exposing it.

Below is the name of the pod and it will forward it's port 6379 to localhost:6379.

kubectl port-forward redis-master-765d459796-258hz 6379:6379 

which is the same as

kubectl port-forward pods/redis-master-765d459796-258hz 6379:6379

or

kubectl port-forward deployment/redis-master 6379:6379 

or

kubectl port-forward rs/redis-master 6379:6379 

or

kubectl port-forward svc/redis-master 6379:6379
Serve Laurijssen
  • 9,266
  • 5
  • 45
  • 98
lvthillo
  • 28,263
  • 13
  • 94
  • 127
  • 2
    I still not getting as because TCP traffic also travel using IP itself. – karthikeayan Jul 23 '18 at 07:35
  • 9
    Link to sample is broken – Michael Freidgeim Oct 17 '18 at 22:27
  • 2
    If you are interested in bulk port-forwarding an entire namespace or a set of services based on selectors to your local workstation you can try kubefwd https://github.com/txn2/kubefwd – cjimti Feb 18 '19 at 06:49
  • 1
    @cjimti finally i can get rid of nodeports.. this will be super useful! – karthikeayan Feb 19 '19 at 13:18
  • 2
    @Ivthillo using the same port number is a bad idea because it creates confusion. I don't understand which is pods port and which is the local one when writing the command. – Daniel May 10 '19 at 10:18
  • @Daniel I understand it can be confusing (just like port mapping with docker) but when you know the syntax there is nothing wrong with forwarding ports on the same port number – lvthillo May 10 '19 at 12:12
  • ```Unable to listen on port 443: Listeners failed to create with the following errors: [unable to create listener: Error listen tcp4 127.0.0.1:443: bind: permission denied unable to create listener: Error listen tcp6 [::1]:443: bind: permission denied] ``` Im getting this error when i use port-forward – sandeep P Mar 25 '20 at 09:01
  • But it sometimes result in error when too much traffic generated from local host. I have observed below three errors. `j.n.UnknownHostException: docker.for.mac.host.internal` `i.n.c.ConnectTimeoutException: connection timed out: docker.for.mac.host.internal/192.168.65.2:8888` `i.g.h.c.i.RequestTimeoutException: Request timeout to docker.for.mac.host.internal/192.168.65.2:8888 after 60000 ms` – Ashish Sharma Oct 16 '20 at 17:34
  • `kubectl port-forward svc/redis-master 6379:6379` - this version is actually slightly different from others as in this case port 6379 should be exposed through service. So, it can't forward traffic to a random port of the pod. An error will occur if port is not exposed: "error: Service redis-master does not have a service port 6379". – Ruslan Stelmachenko Apr 22 '21 at 18:06
  • you forgot to mention that the namespace is necessary too! – toto' Feb 10 '23 at 14:50
101

kubectl port-forward makes a specific Kubernetes API request. That means the system running it needs access to the API server, and any traffic will get tunneled over a single HTTP connection.

Having this is really useful for debugging (if one specific pod is acting up you can connect to it directly; in a microservice environment you can talk to a back-end service you wouldn't otherwise expose) but it's not an alternative to setting up service objects. When I've worked with kubectl port-forward it's been visibly slower than connecting to a pod via a service, and I've found seen the command just stop after a couple of minutes. Again these aren't big problems for debugging, but they're not what I'd want for a production system.

tsuna
  • 1,836
  • 14
  • 21
David Maze
  • 130,717
  • 29
  • 175
  • 215
  • 1
    I agree but i think that is also very useful in production for security: with a simple run script, you can use port forwarding to access admin tools and sensible data that you don't want to expose to outside of the cluster – Carmine Ingaldi May 20 '19 at 08:32
  • 2
    Is it meant to be used in a production environment? – Mexicoder Mar 10 '20 at 18:11
  • 2
    Agreed that it's not meant for production / services, but about the duration the docs say: "The forwarding session ends when the selected pod terminates, and rerun of the command is needed to resume forwarding." https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#port-forward – Kamal May 10 '21 at 14:49
53

If you want to forward to a different port in localhost. Try this

kubectl port-forward <pod-name> <localhost-port>:<pod-port>
kubectl port-forward sample-pod-sadasds-sxawdd 8090:6379

The above command forwards to localhost 8090 from pod 6379

Markus Zeller
  • 8,516
  • 2
  • 29
  • 35
Vihar Manchala
  • 667
  • 6
  • 14
39

The port-forward command, Forwards one (or more) local ports to a pod.

This command is very useful for example in blue/green deployments where you would want to troubleshoot a misbehaving pod.

To take things even further, you could even execute some preliminary tests to the pods you feel could be more error-prone right inside your CI/CD pipeline in Jenkins by using multiple conditions, declarative pipeline.

Usage examples:

Listen on port 8888 locally, forwarding to 5000 in the pod

kubectl port-forward pod/mypod 8888:5000

Listen on port 8888 on all addresses, forwarding to 5000 in the pod

kubectl port-forward --address 0.0.0.0 pod/mypod 8888:5000

Listen on a random port locally, forwarding to 5000 in the pod

kubectl port-forward pod/mypod :5000

Listen on port 8888 on localhost and selected IP, forwarding to 5000 in the pod

kubectl port-forward --address localhost,10.19.21.23 pod/mypod 8888:5000

Listen on ports 5000 and 6000 locally, forwarding data to/from ports 5000 and 6000 in the pod

kubectl port-forward pod/mypod 5000 6000

Listen on ports 5000 and 6000 locally, forwarding data to/from ports 5000 and 6000 in a pod selected by the deployment

kubectl port-forward deployment/mydeployment 5000 6000

Listen on ports 5000 and 6000 locally, forwarding data to/from ports 5000 and 6000 in a pod selected by the service

kubectl port-forward service/myservice 5000 6000
Skeptic
  • 1,254
  • 14
  • 18
  • 1
    An important detailed only stressed in this answer is "in a pod selected by the service". Thus you never port-forward to a service LB. Restarting the (randomly selected) pod of this service will break the connection as steted here: https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#port-forward – Andreas L Sep 19 '22 at 05:49
  • I can not say the nasty words I've been thinking when port-forwarding works outside... Nice Answer! – Raúl Garcia Dec 12 '22 at 09:45
7

kubectl port-forward is the easiest communication method with the Pod, but under the hood, this method is much more complicated. The communication goes through several Kubernetes components, so if anything is broken in the communication path, you will not be able to talk to the pod, even if the pod itself is accessible via regular communication channels.

The server proxy runs via kubectl port-forward command forwards the connection to the Kubernetes API Server living in Master node, then the API Server delivers the connection to the Kubelet on the node hosting your Pod, and then the Kubelet forwards the connection to the application running in the pod's container.

NOTE

The application in the container must be bound to a port on the loopback device for the Kubelet to reach it. If it listens only on the pod’s eth0 network interface, you won’t be able to reach it with the kubectl port-forward command.

Marko Lukša "Kubernetes in Action, Second Edition"

TIP

kubectl port-forward allows you to forward communication also to Services and has several other useful features. Run kubectl port-forward --help to learn more.

Mikolaj
  • 1,231
  • 1
  • 16
  • 34
4

To access something inside the cluster, there ae a couple of different options available to,

  1. Cluster IP service with Ingress-Nginx
  2. NodePort Service to expose the pod directly to the outside world.

Above both approach will require to write config file, In case if you want to access a pod without writing a config file then it comes to third option.

  1. Port Forward: We can run a command at our terminal that tells our kubernets cluster to port-forward a port off a very specific pod inside of our cluster when we use this port forwarding thing that's going to cause our cluster to essentially behaves as though it has a node port service running inside it. It's going to expose this pod or a very specific port on it to the outside world and allow us to connect to it directly from our local machine.

Let's go by an example:

const stan = nats.connect('ticketing', 'abc', {
  url: 'http://localhost:5000',
});

Our goal is to establish a connection between stan and a pod inside a kubernets cluster.

first we will need the pod name, you can get the name by command kubectl get pods

kubectl get pods

I am assuming my pod name is nats-depl-855d477f4d-xgbd7, and it is accessiable via a cluster IP service

apiVersion: v1
kind: Service
metadata:
  name: nats-srv
spec:
  selector:
    app: nats
  ports:
    - name: client
      protocol: TCP
      port: 4222
      targetPort: 4222

now to establish the connection run the below command:

kubectl port-forward nats-depl-855d477f4d-xgbd7 5000:4222

5000: is the port of my local machine

4222 : is the port of the pod I want to get access

Rafiq
  • 8,987
  • 4
  • 35
  • 35