How to Access a Remote Kubernetes Application With Kubectl Port Forwarding
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.