How to open tunnel to Kubernetes pod or container with tcpserver and netcat

Note. transl.: This practical note from the creator of LayerCI is a great illustration of the so-called tips & tricks for Kubernetes (and not only). The solution proposed here is only one of the few and, perhaps, not the most obvious (for some cases, the β€œnative” for K8s already mentioned in the comments may be suitable kubectl port-forward). However, it allows you to at least look at the problem from the perspective of using classic utilities and combining them further - at the same time simple, flexible and powerful (see "other ideas" at the end for inspiration).

How to open tunnel to Kubernetes pod or container with tcpserver and netcat

Imagine a typical situation: you want a port on your local machine to magically redirect traffic to a pod/container (or vice versa).

Possible use cases

  1. Check what HTTP endpoint returns /healthz pod in the production cluster.
  2. Connect a TCP debugger to a pod on the local machine.
  3. Get access to the production database from local database tools without having to fiddle with authentication (localhost usually has root permissions).
  4. Run a one-time migration script for data in a staging cluster without having to create a container for it.
  5. Connect a VNC session to a pod running a virtual desktop (see XVFB).

A few words about the necessary tools

tcpserver - An open source utility available in most Linux package repositories. It allows you to open a local port and redirect traffic received via stdin / stdout from any specified command to it:

colin@colin-work:~$ tcpserver 127.0.0.1 8080 echo -e 'HTTP/1.0 200 OKrnContent-Length: 19rnrn<body>hello!</body>'&
[1] 17377
colin@colin-work:~$ curl localhost:8080
<body>hello!</body>colin@colin-work:~$

(asciinema.org)

Netcat does the opposite. It allows you to connect to an open port and pipe the I/O received from it to stdin/stdout:

colin@colin-work:~$ nc -C httpstat.us 80
GET /200 HTTP/1.0
Host: httpstat.us
HTTP/1.1 200 OK
Cache-Control: private
Server: Microsoft-IIS/10.0
X-AspNetMvc-Version: 5.1
Access-Control-Allow-Origin: *
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Set-Cookie: ARRAffinity=93fdbab9d364704de8ef77182b4d13811344b7dd1ec45d3a9682bbd6fa154ead;Path=/;HttpOnly;Domain=httpstat.us
Date: Fri, 01 Nov 2019 17:53:04 GMT
Connection: close
Content-Length: 0

^C
colin@colin-work:~$

(asciinema.org)

In the example above, netcat is requesting a page over HTTP. Flag -C makes it add CRLF to the end of the line.

Linking with kubectl: listen on the host and connect to the pod

If we combine the above tools 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

By analogy, to access port 80 inside a pod, it will be enough to do curl "127.0.0.1:80":

colin@colin-work:~$ sanic kubectl exec -it web-54dfb667b6-28n85 bash
root@web-54dfb667b6-28n85:/web# apt-get -y install netcat-openbsd
Reading package lists... Done
Building dependency tree
Reading state information... Done
netcat-openbsd is already the newest version (1.195-2).
0 upgraded, 0 newly installed, 0 to remove and 10 not upgraded.
root@web-54dfb667b6-28n85:/web# exit
colin@colin-work:~$ tcpserver 127.0.0.1 8000 sanic kubectl exec -i web-54dfb667b6-28n85 nc 127.0.0.1 8080&
[1] 3232
colin@colin-work:~$ curl localhost:8000/healthz
{"status":"ok"}colin@colin-work:~$ exit

(asciinema.org)

How to open tunnel to Kubernetes pod or container with tcpserver and netcat
Utilities interaction scheme

The other way around: listen in the pod and connect to the host

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

This command allows the pod to access port 8000 on the local machine.

Bash script

I wrote a special Bash script that allows you to manage a Kubernetes production cluster LayerCIusing the above 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"
}

If you add this feature to ~/.bashrc, you can easily open a tunnel in a pod with the command kubetunnel web-pod 8080 and do curl localhost:6666.

  • For a tunnel in Docker you can replace the main line with:
    tcpserver 127.0.0.1 6666 docker exec -i "$CONTAINER" nc 127.0.0.1 "$DESTPORT"
  • for the tunnel K3s - change it to:
    tcpserver 127.0.0.1 6666 k3s kubectl exec …
  • etc.

Other ideas

  • You can redirect UDP traffic with the commands netcat -l -u -c instead tcpserver ΠΈ netcat -u instead netcat respectively.
  • View input/output through pipe viewer:

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

  • You can compress and decompress traffic on both ends using gzip.
  • Connect via SSH to another computer with the appropriate file kubeconfig:

    tcpserver ssh workcomputer "kubectl exec -i my-pod nc 127.0.0.1 80"

  • You can connect two pods in different clusters with mkfifo and run two separate commands kubectl.

The possibilities are endless!

PS from translator

Read also on our blog:

Source: habr.com

Add a comment