How to Access a Remote Kubernetes Application With Kubectl Port Forwarding

0
How to Access a Remote Kubernetes Application With Kubectl Port Forwarding

Graphic with the Kubernetes logo

Need to debug an application running inside your Kubernetes cluster? Port forwarding is a way to connect to Pods that aren’t publicly accessible. You can use this technique to inspect databases, monitoring tools, and other applications which you want to deploy internally without a public route.

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

How Port Forwarding Works

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

Port forwarding only operates at the port level. You direct a specific port like 33060 to a target port such as 3306 in the destination network. When you send traffic to your local port 33060, it will be forwarded automatically to port 3306 at the remote end.

This technique lets you access private Kubernetes workloads that aren’t exposed by a NodePort, Ingress, or LoadBalancer. You can direct local traffic straight into your cluster, removing the need to create Kubernetes services for your internal workloads. This helps to reduce your attack surface.

Deploying a Sample Application

Let’s now see Kubernetes port forwarding in action. Begin by creating a basic deployment that you’ll connect to using port forwarding in the next section.

We’re using a MySQL database Pod as a realistic example of when you might need to use this technique. Databases aren’t normally exposed publicly so Kubernetes admins often use port forwarding to open a direct connection.

Create a YAML file for your deployment:

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 the MYSQL_ROOT_PASSWORD environment variable before using this manifest in production. Run kubectl apply to create your MySQL deployment:

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

Next use the get pods command to check the workload’s started successfully:

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

Using Kubectl to Port Forward to Kubernetes

Although MySQL’s now running in your cluster, you’ve got no way of accessing it from outside. Next set up a port forwarding session so you can use your local installations of tools like the mysql CLI to connect to your database.

Here’s 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 directed to port 3306 against the Pod running your 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 that’s running the kubectl port-forward command open for the duration of your debugging 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 the port number bindings is local:remote. The 33060:3306 example shown above maps port 33060 on localhost to 3306 in the target Pod.

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

$ kubectl port-forward deployment/mysql 3306

You may leave the local port blank instead 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’d use the randomly generated port number 34923 with your local MySQL client.

Changing the Listening Address

Kubectl binds the local port on the 127.0.0.1 (IPv4) and ::1 (IPv6) addresses by default. You can specify your own set of IPs instead by supplying an --address flag when you run the port-forward command:

# 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 and ::1, matching the command’s defaults when --address is omitted.

Summary

Port forwarding is a useful technique to access private applications inside your Kubernetes cluster. Kubectl tunnels traffic from your local network to a specific port on a particular Pod. It’s 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 endpoints that are meant to be protected. Port forwarding in Kubectl lets you securely connect straight to your applications, without having to work out which Nodes they’re running on.

Leave a Reply