How to access a remote Kubernetes application with Kubectl Port Forwarding

Do you need to debug an application running within your Kubernetes cluster? Port forwarding is a way to connect to Pods that are not publicly accessible. You can use this technique to inspect databases, monitoring tools, and other applications that you want to deploy internally without a public location.

Port forwarding is integrated into Kubectl. The CLI can initiate tunneling sessions that redirect traffic on local ports to pods in your Kubernetes cluster. Here’s how to set it up.

How port forwarding works

Port forwarding is a kind of NAT (Network Address Translation) rule that routes traffic from one network to another. In the context of Kubernetes, requests that appear to be terminated by localhost they are redirected to the cluster’s internal network.

Port forwarding works only at the port level. Direct a specific door like 33060 to a destination port such as 3306 in the destination network. When sending traffic to your local port 33060it will be automatically forwarded to the door 3306 at the far end.

This technique allows you to access private Kubernetes workloads that are not exposed by NodePort, Ingress, or LoadBalancer. You can route local traffic directly to your cluster, eliminating the need to build Kubernetes services for your internal workloads. This helps reduce the attack surface.

Deploying a sample application

Let’s now see Kubernetes port forwarding in action. Start by creating a basic distribution that you will connect to using port forwarding in the next section.

We are using a MySQL database pod as a realistic example of when this technique may need to be used. Databases are not normally exposed publicly, so Kubernetes administrators often use port forwarding to open a direct connection.

Create a YAML file for your distribution:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql
spec:
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - image: mysql:8.0
        name: mysql
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: mysql

Make sure you change the value of MYSQL_ROOT_PASSWORD environment variable before using this manifest in production. run kubectl apply to create your MySQL distribution:

$ kubectl apply -f mysql.yaml
deployment.apps/mysql created

Then use the get pods command to verify that the workload has started successfully:

$ kubectl get pods
NAME                     READY   STATUS    RESTARTS   AGE
mysql-5f54dd5789-t5fzc   1/1     Running   0          2s

Using Kubectl to perform port forwarding on Kubernetes

Although MySQL is now running in your cluster, you have no way to access it from outside. Then set up a port forwarding session so you can use your local installations of tools like mysql CLI to connect to the database.

Here is a simple example:

$ kubectl port-forward deployment/mysql 33060:3306
Forwarding from 127.0.0.1:33060 -> 3306
Forwarding from [::1]:33060 -> 3306

Connections to port 33060 will be routed to port 3306 with respect to the Pod running the MySQL deployment. You can now start a MySQL shell session that targets your database in Kubernetes:

$ mysql --host 127.0.0.1 --port 33060 -u root -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 10
Server version: 8.0.29 MySQL Community Server - GPL

Keep the shell window it is running on kubectl port-forward open command for the duration of the debug session. Port forwarding will be terminated when you press Ctrl + C or close the window.

Changing the local and remote port numbers

The syntax for port number connections is local:remote. the 33060:3306 the example shown above maps the active port 33060 localhost to 3306 in the destination Pod.

Specifying a single number, without a colon, will interpret it as both a local port and a remote port:

$ kubectl port-forward deployment/mysql 3306

Instead, you can leave the local port blank to automatically assign a random port:

$ kubectl port-forward deployment/mysql :3306
Forwarding from 127.0.0.1:34923 -> 3306
Forwarding from [::1]:34923 -> 3306

Here you would use the randomly generated port number 34923 with your local MySQL client.

Changing the listening address

Kubectl binds the local port to 127.0.0.1 (IPv4) and ::1 (IPv6) addresses by default. Instead, you can specify your own IP set by providing a --address flag when you run the port-forward commands:

# Listen on two IPv4 addresses
$ kubectl port-forward deployment/mysql :3306 --address 127.0.0.1,192.168.0.1

The flag only accepts IP addresses and the localhost keyword. The latter is interpreted to include 127.0.0.1 Other ::1corresponding to the default values ​​of the command when --address is omitted.

Summary

Port forwarding is a useful technique for accessing private applications within your Kubernetes cluster. Kubectl channels traffic from your local network to a specific port on a particular Pod. It is a relatively low-level mechanism that can handle any TCP connection. UDP port forwarding is not yet supported.

Using an ad hoc port forwarding session is a safe way to debug workloads that don’t need to be exposed externally. Creating a service for each new deployment could allow intruders and attackers to discover the endpoints that need to be protected. Port forwarding in Kubectl allows you to securely connect directly to your applications, without having to figure out which nodes they are running on.