Como abrir um túnel em um pod ou contêiner do Kubernetes com tcpserver e netcat

Nota do tradutor.: Esta nota prática do criador do LayerCI é uma excelente ilustração dos chamados tips & tricks para Kubernetes (e não só). A solução proposta aqui é apenas uma das poucas e, provavelmente, não a mais óbvia (para alguns casos pode ser adequado o já mencionado nos comentários "nativo" para K8s. kubectl port-forward). No entanto, ela permite, no mínimo, olhar para o problema sob a perspectiva da aplicação de utilitários clássicos e sua combinação subsequente — ao mesmo tempo simples, flexível e poderoso (veja "outras ideias" no final para inspiração).

Como abrir um túnel em um pod ou contêiner do Kubernetes com tcpserver e netcat

Imagine uma situação típica: você deseja que uma porta no seu computador local encaminhe magicamente o tráfego para um pod/container (ou vice-versa).

Possíveis cenários de uso

  1. Verificar o que retorna o endpoint HTTP /healthz do pod no cluster de produção.
  2. Conectar um depurador TCP ao pod na máquina local.
  3. Acessar a base de produção a partir de ferramentas locais para trabalhar com banco de dados, sem precisar lidar com autenticação (normalmente o localhost tem privilégios de root).
  4. Executar um script temporário de migração de dados no cluster de staging, sem precisar criar um contêiner para isso.
  5. Conectar uma sessão VNC ao pod com um desktop virtual em execução (veja XVFB).

Algumas palavras sobre as ferramentas necessárias

Tcpserver — Uma utilidade de código aberto disponível na maioria dos repositórios de pacotes Linux. Ela permite abrir uma porta local e redirecionar para ela o tráfego obtido através de stdin/stdout de qualquer comando especificado:

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

(asciinema.org)

Netcat faz o oposto. Ele permite conectar-se a uma porta aberta e transmitir a entrada/saída recebida para 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: Sex, 01 Nov 2019 17:53:04 GMT
Connection: close
Content-Length: 0

^C
colin@colin-work:~$

(asciinema.org)

No exemplo acima, netcat solicita uma página via HTTP. A flag -C faz com que ele adicione CRLF ao final da linha.

Conectando com kubectl: escutando no host e conectando-se ao pod

Se unirmos as ferramentas apresentadas acima com kubectl, teremos um comando como este:

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

Analogamente, para acessar a porta 80 dentro do pod, basta fazer 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
Lendo listas de pacotes... Feito
Construindo árvore de dependência
Lendo informações de estado... Feito
netcat-openbsd já é a versão mais nova (1.195-2).
0 atualizado, 0 recém-instalado, 0 removido e 10 não atualizados.
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)

Como abrir um túnel em um pod ou contêiner do Kubernetes com tcpserver e netcat
Esquema de interação das ferramentas

Na direção oposta: escute no pod e conecte-se ao host

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

Este comando permite que o pod acesse a porta 8000 na máquina local.

Script para Bash

Eu escrevi um script especial para Bash que permite gerenciar um cluster de produção Kubernetes LayerCI, utilizando o método descrito acima:

kubetunnel() {
    POD="$1"
    DESTPORT="$2"
    if [ -z "$POD" -o -z "$DESTPORT" ]; then
        echo "Uso: kubetunnel [nome do pod] [porta de destino]"
        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 "Conecte-se a 127.0.0.1:6666 para acessar $POD:$DESTPORT"
}

Se você adicionar essa função em ~/.bashrc, você pode facilmente abrir um túnel no pod com o comando kubetunnel web-pod 8080 e fazer curl localhost:6666.

  • Para o túnel em Docker você pode substituir a linha principal por:
    tcpserver 127.0.0.1 6666 docker exec -i "$CONTAINER" nc 127.0.0.1 "$DESTPORT"
  • para o túnel em K3s — mude para:
    tcpserver 127.0.0.1 6666 k3s kubectl exec …
  • etc.

Outras ideias

  • Você pode redirecionar o tráfego UDP com os comandos netcat -l -u -c em vez de tcpserver e netcat -u em vez de netcat respectivamente.
  • Veja a entrada/saída através do pipe viewer:

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

  • É possível comprimir e descomprimir o tráfego em ambas as extremidades usando gzip.
  • Conecte-se via SSH ao outro computador com o arquivo correspondente kubeconfig:

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

  • É possível conectar dois pods em diferentes clusters usando mkfifo e iniciar dois comandos separados kubectl.

As possibilidades são infinitas!

P.S. do tradutor

Confira também em nosso blog:

Fonte: habr.com

Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS 🔥 Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS | ProHoster