Task-прокси
В операциях YTsaurus часто требуется разворачивать веб-сервисы. Это могут быть UI для отладки (например, Spark UI в SPYT), серверы для инференса ML-моделей или API внутри джобов.
Джобы операций исполняются на exec-нодах кластера, поэтому сервисы привязываются к сетевым портам этих нод — для приёма входящего трафика. Но при попытке прямого обращения к сервисам внутри джоба возникают сложности:
- Сетевая изоляция: у пользователя может не быть прямого сетевого доступа к IP-адресам exec-нод (они могут находиться в закрытом контуре).
- Динамическая адресация: даже при наличии сетевого доступа джобы могут переезжать между нодами, поэтому хост и порт сервисов постоянно меняются.
- Безопасность: прямое обращение к порту на ноде происходит в обход механизмов аутентификации YTsaurus. Контроль прав доступа к операции не осуществляется.
Task-прокси решает эти проблемы, предоставляя единую точку входа. Он выделяет стабильные домены (FQDN) для каждого сервиса и проверяет права доступа у пользователя перед тем, как перенаправить запрос внутрь джоба.
Как это работает
В основе Task-прокси лежит механизм Services Discovery (обнаружение сервисов). Он автоматически находит в кластере операции с веб-сервисами и генерирует для них доменные имена.
Каждый сервис описывается сущностями:
- Операция (operation): Основная единица работы в кластере YTsaurus.
- Задача (task): Тип работы внутри операции. Операция может содержать несколько задач (например, driver и executor).
- Джоб (job): Конкретный процесс. Каждая задача запускается в одном или нескольких экземплярах — джобах.
- Сервис (service): Конкретный сетевой сервис задачи. Одна задача может выставлять наружу несколько веб-сервисов (например, HTTP UI и REST API).
Task-прокси балансирует входящий трафик между всеми запущенными джобами одной задачи, направляя запрос в конкретный сервис этого джоба. Если один из джобов выйдет из строя или переедет на другую ноду, прокси автоматически перенаправит трафик на доступные экземпляры.

Автоматическое обнаружение (Services Discovery) работает для:
- Vanilla-операций с настроенными аннотациями.
- SPYT-операций (Standalone-кластера и Direct Submit) — они обнаруживаются автоматически без дополнительных настроек.
Запуск HTTP-сервиса
Чтобы запустить операцию с веб-сервисом, доступным через Task-прокси:
- Укажите параметр
port_countв спецификации задачи. YTsaurus выделит свободные порты на exec-ноде и передаст их номера в переменные окруженияYT_PORT_0,YT_PORT_1и т. д. - Добавьте
task_proxy={enabled=%true}в спецификацию операции.
Пример команды запуска двух экземпляров (job_count=2) HTTP-сервера на одном порту (port_count=1):
yt vanilla \
--tasks '{example_http_server={job_count=2; command="python3 -m http.server ${YT_PORT_0}"; port_count=1}}' \
--spec '{annotations={task_proxy={enabled=%true;}}}'
При такой конфигурации Task-прокси автоматически обнаружит сервис, присвоит ему протокол HTTP и имя port_0.
Как узнать адрес сервиса
После запуска операции Task-прокси сгенерирует уникальный домен для каждого сервиса. Доменное имя состоит из baseDomain (указывается администратором кластера), к которому добавляется уникальный хеш от дескриптора сервиса.
Механизм Service Discovery сканирует операции и записывает информацию о доступных точках входа в таблицу //sys/task_proxies/services (путь может быть изменен администратором в параметре dirPath).
Ниже приведён пример содержимого таблицы. Каждая строка описывает свой сервис:
| domain | operation_id | task_name | service | protocol |
|---|---|---|---|---|
| 645236d8.my-cluster.ytsaurus.example.net | a6e04b98-bf982394-5103e8-55754a49 | example_http_server | port_0 | http |
| ae5cf6f5.my-cluster.ytsaurus.example.net | a8ef7695-3de07913-5103e8-e29a6707 | example_grpc_server | server | grpc |
| 2ef4261c.my-cluster.ytsaurus.example.net | a6e04b98-bf982394-5103e8-55754a49 | master | ui | http |
| 51a6d485.my-cluster.ytsaurus.example.net | a6e04b98-bf982394-5103e8-55754a49 | history | ui | http |
| 37a5f11c.my-cluster.ytsaurus.example.net | 6699a5a9-37c731e3-5103e8-b05d7dd0 | driver | ui | http |
- Первая строка представляет vanilla-операцию с примером HTTP-сервера.
- Вторая — пример gRPC-сервера. О том, как запустить его с использованием расширенного формата аннотации Task-прокси, читайте далее.
- Третья и четвёртая строки соответствуют standalone-кластеру SPYT, запущенному с History Server.
- Пятая строка относится к SPYT direct submit.
Способы подключения к сервисам
Для доступа к сервису необходимо пройти аутентификацию. Поддерживаются:
- Токены: OAuth-токен или IAM-токен (в заголовке
Authorization). - Cookie: Аутентификационная кука (имя куки задаётся администратором).
Через браузер
Для доступа к UI (например, Spark UI) просто откройте домен сервиса (https://645236d8...) в браузере. Если вы авторизованы в интерфейсе YTsaurus, доступ будет предоставлен автоматически через cookie.
Через Ingress (публичный доступ)
Если в кластере настроен Ingress-контроллер, вы можете обращаться к домену напрямую через интернет. В данном случае настройки DNS и TLS не выполняются в рамках Task-прокси, а осуществляются отдельно администраторами вашей инсталляции.
curl \
-H "Authorization: Bearer ${IAM_TOKEN}" \
"https://645236d8.my-cluster.ytsaurus.example.net"
Напрямую в Task-прокси (внутри K8s)
Если вы находитесь внутри сетевого периметра (например, в Kubernetes, где развернут Task-прокси), можно обращаться к сервису K8s напрямую. В этом случае обязательно укажите домен сервиса в заголовке Host.
curl \
-H "Host: 645236d8.my-cluster.ytsaurus.example.net" \
-H "Authorization: OAuth ${YT_TOKEN}" \
"http://task-proxy.${NAMESPACE}.svc.cluster.local:80"
Альтернатива Wildcard-доменам
Если инфраструктура не поддерживает wildcard-домены (вида *.ytsaurus.example.net), используйте заголовок x-yt-taskproxy-id. В качестве значения передайте левую часть домена (хеш).
curl \
-H "Authorization: Bearer ${IAM_TOKEN}" \
-H "x-yt-taskproxy-id: 645236d8" \
"https://task-proxy.my-cluster.ytsaurus.example.net"
Расширенный формат аннотации
Аннотация task_proxy={enabled=%true} применяет настройки по умолчанию. Это означает, что при её использовании каждый сервис получает:
- имя
port_${PORT_INDEX}; - порт с индексом, соответствующим порядку появления задач в спецификации операции;
- протокол HTTP.
Если вы хотите выставить другие настройки — например, использовать протокол gRPC, задать собственное имя сервиса или выбрать конкретный порт из списка — используйте расширенный формат аннотации. Для этого в ней потребуется указать поле tasks_info. С примерами можно ознакомиться ниже.
Запуск gRPC-сервиса
Запустим пример gRPC-сервера с использованием расширенной аннотации:
yt vanilla \
--tasks '{example_grpc_server={job_count=2; command="./yt-sample-grpc-service"; file_paths = ["//home/yt-sample-grpc-service"]; port_count=1}}' \
--spec '{annotations={task_proxy={enabled=%true; tasks_info={example_grpc_server={server={protocol="grpc"; port_index=0}}}}}}'
Разбор параметра tasks_info:
example_grpc_server— имя задачи (task).server— имя сервиса (в данном примере он один, но одна задача может содержать несколько сервисов).protocol="grpc"— указание протокола.port_index=0— использование первого порта изport_count(соответствуетYT_PORT_0).
Обращение к gRPC-сервису
Для gRPC-запросов также потребуется авторизация.
Через Ingress (публичный доступ)
Обратите внимание, что порт для gRPC на Ingress-контроллере может отличаться (в примере ниже — 9090).
grpcurl \
-H "Cookie: YTCypressCookie ${AUTH_COOKIE_VALUE}" \
"ae5cf6f5.my-cluster.ytsaurus.example.net:9090" \
"helloworld.Greeter/SayHello"
Напрямую в Task-прокси (внутри K8s)
grpcurl \
-plaintext \
-authority "ae5cf6f5.my-cluster.ytsaurus.example.net" \
-H "Authorization: Bearer ${IAM_TOKEN}" \
"task-proxy.${NAMESPACE}.svc.cluster.local:80" \
"helloworld.Greeter/SayHello"