How to open a tunnel into any pod or container with tcpserver and netcat

It's a common scenario: You want a port on your local computer to magically forward traffic to your pod/container (or vice-versa.)

Use cases

  1. Check what the /healthz HTTP endpoint of a pod is returning in a production cluster
  2. Attach a TCP debugger to a pod running locally.
  3. Access the production database from local database tools without needing to fiddle with auth (usually localhost has root auth)
  4. Run a one-time migration script on data in a staging cluster without needing to create a container for it.
  5. Connect a VNC session to a pod with a virtual desktop running in it (see: XVFB)

Introducing the tools

"tcpserver" is an open source utility that's available in most linux package repositories. It lets you open a local port and forward traffic via stdin/stdout to any command you specify.

"netcat" is the opposite. It lets you make a connection to an open port and forward the input/output provided to it through stdin/stdout:

The above example  requests an HTTP page using netcat. The -C flag sets netcat to send HTTP line endings.

Combine with kubectl: Listen on host and connect to pod

If we combine the tools above with kubectl, we get a command like this:

tcpserver 127.0.0.1 8000 kubectl exec -i web-pod nc 127.0.0.1 8080

Which then lets us curl "127.0.0.1:80" to access port 80 internally in the pod:

Diagram for what programs are connecting to what

In reverse: Listen in pod and connect to host:

nc 127.0.0.1 8000 | kubectl exec -i web-pod tcpserver 127.0.0.1 8080 cat

This command would allow the web pod to access port 8000 on the local computer.

Utility bash script

I've made a utility bash script to manage LayerCI's production kubernetes cluster with this method:

kubetunnel() {
    POD="$1"
    DESTPORT="$2"
    if [ -z "$POD" -o -z "$DESTPORT" ]; then
    	echo "Usage: kubetunnel [pod name] [destination port]"
        return 1
    fi
    pkill -f 'tcpserver 127.0.0.1 6666'
    tcpserver 127.0.0.1 6666 kubectl exec -i "$POD" nc 127.0.0.1 "$DESTPORT"&
    echo "Connect to 127.0.0.1:6666 to access $POD:$DESTPORT"
}

Appending this function to my ~/.bashrc lets me kubetunnel web-pod 8080 and curl localhost:6666 easily.

Equivalently, you can use tcpserver 127.0.0.1 6666 docker exec -i "$CONTAINER" nc 127.0.0.1 "$DESTPORT" for a dockertunnel script, or tcpserver 127.0.0.1 6666 k3s kubectl exec ... for a k3stunnel script, et cetera.

Other ideas

  • Forward UDP traffic with netcat -l -u -c instead of tcpserver and netcat -u instead of netcat respectively
  • View I/O with "pipe viewer": nc 127.0.0.1 8000 | pv --progress | kubectl exec -i web-pod tcpserver 127.0.0.1 8080 cat
  • Compress and decompress traffic with gzip at both ends.
  • Connect to another computer that has your kubeconfig on it with ssh: tcpserver ssh workcomputer "kubectl exec -i my-pod nc 127.0.0.1 80"
  • Connect two pods in two different clusters with mkfifo and starting two separate kubectl commands
  • The opportunities are limitless!