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
- Check what the /healthz HTTP endpoint of a pod is returning in a production cluster
- Attach a TCP debugger to a pod running locally.
- Access the production database from local database tools without needing to fiddle with auth (usually localhost has root auth)
- Run a one-time migration script on data in a staging cluster without needing to create a container for it.
- 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:
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 oftcpserver
andnetcat -u
instead ofnetcat
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 separatekubectl
commands - The opportunities are limitless!