Привет, Хабр!

Недавно я столкнулся с задачей, требующей доступа к одному из сервисов внутри кластера Kubernetes. Работая над отладкой сложной микросервисной структуры, нужно было проверить работоспособность одного из компонентов, но доступ к нему был возможен только изнутри кластера. Я нашел подходящее решение - переадресация портов с помощью kubectl.

Переадресация портов — это процесс перенаправления сетевого трафика с одного порта на другой, что позволяет получать доступ к внутренним сервисам кластера Kubernetes из внешней сети.

Команда kubectl port-forward позволяет перенаправлять трафик с локального компьютера на определенный порт внутри пода

Рассмотрим подробней.

Работа команды kubectl port-forward

Команда kubectl port-forward позволяет устанавливать туннель между локальным портом и портом ресурса (пода, службы и т.д.) в кластере.

Общий синтаксис команды:

kubectl port-forward [resource-type]/[resource-name] [local-port]:[resource-port]
  • [resource-type]: тип ресурса (например, pod, svc).

  • [resource-name]: имя ресурса.

  • [local-port]: локальный порт на вашем компьютере.

  • [resource-port]: порт на ресурсе Kubernetes.

Примеры использования:

Переадресация порта пода

kubectl port-forward pod/my-pod 8080:80

Здесь перенаправляем локальный порт 8080 на порт 80 пода с именем my-pod.

Переадресация порта службы

kubectl port-forward svc/my-service 8080:80

Пример перенаправляет локальный порт 8080 на порт 80 службы с именем my-

Когда задействована команда kubectl port-forward, происходит следующее:

  1. Инициализация команды: пользователь вводит команду в терминале.

  2. Аутентификация и авторизация: CLI связывается с API-сервером Kubernetes для аутентификации пользователя и проверки его прав доступа.

  3. Получение информации о поде: CLI отправляет запрос на получение данных о целевом поде.

  4. Установка сессии порт-форвардинга: CLI инициирует соединение с API-сервером для установления сессии порт-форвардинга.

  5. Конфигурация iptables: Kubelet на узле, где запущен под, настраивает iptables для перенаправления трафика.

  6. SPDY сессия для передачи данных: Данные передаются через WebSocket/SPDY соединение между локальной машиной и подом.

Пример установки соединения до передачи данных

Предположим, есть под с именем my-pod, который слушает на порту 80, и хочется перенаправить этот порт на локальный порт 8080:

kubectl port-forward pod/my-pod 8080:80

Пользователь вводит команду kubectl port-forward pod/my-pod 8080:80. CLI начинает выполнение команды.

CLI отправляет запрос на API-сервер Kubernetes для аутентификации пользователя. Этот запрос включает Bearer Token для проверки подлинности пользователя. API-сервер проверяет токен и авторизует доступ к указанному поду.

После успешной аутентификации CLI отправляет GET-запрос на API-сервер для получения информации о целевом поде. Сервер возвращает необходимые данные, такие как имя пода, IP-адрес и порты.

CLI инициирует POST-запрос на API-сервер для установления сессии порт-форвардинга. Сервер API переключает протокол на WebSocket/SPDY, устанавливая постоянное соединение между локальной машиной и подом.

# пример кода в питоне для выполнения запроса
import requests
from requests.auth import AuthBase

class BearerAuth(AuthBase):
    def __init__(self, token):
        self.token = token

    def __call__(self, r):
        r.headers["authorization"] = "Bearer " + self.token
        return r

url = "https://<api-server>/api/v1/namespaces/default/pods/my-pod/portforward"
token = "<token>"
headers = {"Content-Type": "application/json"}

response = requests.post(url, headers=headers, auth=BearerAuth(token))
if response.status_code == 101:  # switching Protocols
    print("Connection established")
else:
    print("Failed to establish connection", response.status_code)

API-сервер инструктирует Kubelet на узле, где запущен под, настроить iptables для перенаправления трафика. Kubelet создает правила iptables, чтобы направить трафик с локального порта 8080 на порт пода 80.

После успешного установления соединения данные передаются через WebSocket/SPDY соединение. Пользовательские запросы оборачиваются в кадры WebSocket/SPDY и направляются через API-сервер к Kubelet, который затем пересылает их на под:

import websocket

def on_message(ws, message):
    print(f"Received message: {message}")

def on_error(ws, error):
    print(f"Error: {error}")

def on_close(ws):
    print("Connection closed")

def on_open(ws):
    ws.send("Hello Pod")

ws = websocket.WebSocketApp("wss://<api-server>/api/v1/namespaces/default/pods/my-pod/portforward",
                            on_message=on_message,
                            on_error=on_error,
                            on_close=on_close)
ws.on_open = on_open
ws.run_forever()

Полезные опции

Запуск в фоновом режиме

Для запуска команды в фоновом режиме можно добавить символ & в конец команды:

kubectl port-forward pod/my-pod 8080:80 &

Для остановки процесса есть команда kill с идентификатором процесса:

ps -ef | grep port-forward
kill -9 [PID]

Можно позволить Kubernetes выбрать случайный локальный порт:

kubectl port-forward svc/my-service :80

Локальный порт будет указан в выводе команды.

Для прослушивания на любом локальном IP-адресе есть команда:

kubectl port-forward --address 0.0.0.0 pod/my-pod 8080:80

Это позволяет перенаправлять трафик с любого IP-адреса на локальной машине.


Финальные слова

kubectl port-forward - простой и безопасный способ доступа к внутренним сервисам кластера. Однако, не все так радужно. Есть пару минусов:

  1. Отсутствие балансировки нагрузки: переадресация портов работает на уровне пода, минуя механизмы балансировки нагрузки Kubernetes.

  2. Единовременный доступ одного пользователя: в одно время только один пользователь может установить соединение.

Тем не менее,kubectl port-forward — все еще мощный инструмент.

Больше практических навыков по инфраструктуре приложений вы можете получить в рамках практических онлайн-курсов от экспертов отрасли.

Комментарии (1)


  1. alhimik45
    26.07.2024 20:08
    +1

    Для более продвинутых кейсов неплохо подходит kubevpn. С ним можно использовать прямо dns имена сервисов и в целом иметь доступ ко всей сетке кубера.