Як з tcpserver та netcat відкрити тунель у Kubernetes pod або контейнер

Прим. перев.: Ця практична замітка від творця LayerCI - чудова ілюстрація так званих tips & tricks для Kubernetes (і не тільки). Пропоноване тут рішення — лише одне з небагатьох і, мабуть, не найочевидніше (для деяких випадків може підійти згаданий у коментарях «рідний» для K8s kubectl port-forward). Однак воно дозволяє як мінімум подивитися на проблему з позиції застосування класичних утиліт та їх подальшого комбінування — одночасно простого, гнучкого та потужного (див. «Інші ідеї» наприкінці для натхнення).

Як з tcpserver та netcat відкрити тунель у Kubernetes pod або контейнер

Уявіть типову ситуацію: ви хочете, щоб порт на локальному комп'ютері чарівним чином перенаправляв трафік у pod/контейнер (або навпаки).

Можливі сценарії використання

  1. Перевірити, чи повертає HTTP endpoint /healthz pod'а в production-кластері.
  2. Підключити TCP-наладчик до pod'у на локальній машині.
  3. Отримати доступ до production-бази з локальних інструментів для роботи з БД без необхідності возитися з автентифікацією (зазвичай localhost'а має права root'а).
  4. Запустити одноразовий скрипт міграції для даних у staging-кластері без необхідності створювати для нього контейнер.
  5. Підключити сесію VNC до pod'у із запущеним віртуальним робочим столом (див. XVFB).

Декілька слів про необхідні інструменти

TCPserver - Open Source-утиліта, доступна у більшості репозиторіїв пакетів Linux. Вона дозволяє відкрити локальний порт і перенаправити на нього трафік, що отримується через stdin/stdout від будь-якої команди:

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 робить протилежне. Вона дозволяє підключитися до відкритого порту і передати отримане від нього введення/виведення на 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)

У наведеному вище прикладі netcat запитує сторінку HTTP. Прапор -C змушує його додавати CRLF у кінець рядка.

Зв'язка з kubectl: слухайте на хості та підключайтеся до pod'у

Якщо об'єднати представлені вище інструменти з kubectl, ми отримаємо команду на зразок цієї:

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

За аналогією, для доступу до порту 80 усередині pod'а достатньо буде зробити 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)

Як з tcpserver та netcat відкрити тунель у Kubernetes pod або контейнер
Схема взаємодії утиліт

У зворотний бік: слухайте у pod'є та підключайтеся до хоста

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

Ця команда дозволяє pod'у отримати доступ до порту 8000 на локальній машині.

Скрипт для Bash

Я написав спеціальний скрипт для Bash, що дозволяє керувати production-кластером Kubernetes LayerCI, використовуючи описаний вище метод:

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"
}

Якщо додати цю функцію в ~/.bashrc, можна легко відкривати тунель у команді pod kubetunnel web-pod 8080 і робити curl localhost:6666.

  • Для тунелю в Docker можна замінити основний рядок на:
    tcpserver 127.0.0.1 6666 docker exec -i "$CONTAINER" nc 127.0.0.1 "$DESTPORT"
  • для тунелю в K3s - Поміняйте її на:
    tcpserver 127.0.0.1 6666 k3s kubectl exec …
  • тощо.

інші ідеї

  • Перенаправити UDP-трафік можна командами netcat -l -u -c замість tcpserver и netcat -u замість netcat відповідно.
  • Переглянути введення/виведення через pipe viewer:

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

  • Можна стискати та розпаковувати трафік на обох кінцях за допомогою gzip.
  • Підключитися по SSH до іншого комп'ютера з відповідним файлом kubeconfig:

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

  • Можна з'єднати два pod'а у різних кластерах за допомогою mkfifo та запустити дві окремі команди kubectl.

Можливості безмежні!

PS від перекладача

Читайте також у нашому блозі:

Джерело: habr.com

Додати коментар або відгук