Перейти к основному содержимому

Kubernetes-оператор Tuna — туннели, домены и Ingress ресурсами кластера

· 4 мин

Чтобы открыть сервис из кластера наружу, обычно нужны LoadBalancer, публичный IP и ingress-контроллер. В облаке за это платят, а у многих кластеров публичного адреса нет вовсе: закрытый контур, kind на ноутбуке, k3s на Raspberry Pi за роутером провайдера.

Для таких кластеров мы сделали Kubernetes-оператор. Ставите его Helm-чартом, пишете обычный Ingress с классом tuna — и сервис доступен из интернета. Кластер ходит к Tuna только исходящими соединениями, входящие порты открывать не нужно.

Анимация: оператор в кластере открывает исходящий туннель до ноды Tuna; запрос на my-app.a.2na.am/api приходит через туннель и уходит в Service api, запрос на корень — в Service web
Кластер сам открывает туннель до Tuna, а оператор разводит запросы по путям Ingress.
Коротко
  • Настоящий Ingress-контроллер. Любой Helm-чарт, который умеет создавать Ingress, публикуется через Tuna одной строкой в values.
  • Свой ключ у каждого туннеля. Он только запускает туннели, не ходит в API и отзывается вместе с ресурсом. Ключ самого оператора туннели не запускает.
  • Домены и порты — манифестами. Поддомены, свои домены и TCP-порты резервируются ресурсами рядом с приложением и живут в git.
  • Установка, настройка ключа и все ресурсы — в документации.

Было: под с tuna http​

Опубликовать кластер через Tuna можно было и раньше: запустить tuna http в поде. Так один из наших пользователей выводил наружу ingress-nginx:

spec:
replicas: 1
strategy: {type: Recreate}
template:
spec:
containers:
- name: tuna
image: yuccastream/tuna:latest
args: [http, ingress-nginx-controller.ingress-nginx.svc.cluster.local:80, --inspect=false]
env:
- {name: TUNA_TOKEN, valueFrom: {secretKeyRef: {name: app-tuna, key: TUNA_TOKEN}}}
- {name: TUNA_SUBDOMAIN, valueFrom: {secretKeyRef: {name: app-tuna, key: TUNA_SUBDOMAIN}}}

Работает, но всё собрано руками: поддомен зарезервирован в кабинете, Secret создан вручную, перед туннелем стоит отдельный ingress-nginx. А TUNA_TOKEN — токен всего аккаунта: утёк из Secret — и с ним можно поднять сколько угодно туннелей на любые адреса.

Стало: обычный Ingress​

С оператором Tuna — ещё один ingress-контроллер в кластере. Чарту не нужно ничего знать о Tuna: достаточно указать класс. Вот podinfo на зарезервированном поддомене:

values.yaml
ingress:
enabled: true
className: tuna
hosts:
- host: podinfo.a.2na.am
paths:
- path: /
pathType: Prefix

Пути внутри одного Ingress разводятся по разным Service: /api — на бэкенд, / — на фронтенд. На каждый хост оператор поднимает один туннель, а новые пути и бэкенды применяет без переподключения. Если в чарте нельзя задать класс, tuna можно сделать классом по умолчанию.

Сам поддомен тоже описывается манифестом — ресурсом Domain рядом с приложением. Так же резервируются свои домены и TCP-порты, а для одиночного сервиса есть короткий ресурс Tunnel без Ingress.

Ключ на каждый туннель​

Главное, что мы закладывали в оператор, — чтобы утечка одного секрета не открывала весь аккаунт.

  • У каждого туннеля свой временный ключ. Он умеет только запускать туннель: один протокол, не больше одного туннеля одновременно, без доступа к API. Удалили ресурс — ключ отозван. Ключи ресурсов, удалённых, пока оператор не работал, отзываются автоматически.
  • Ключ оператора туннели не запускает. Ему нужно только право записи в «Эндпоинты и домены»: резервировать адреса и выпускать ключи туннелям.
  • Только свой namespace. Tunnel и Ingress публикуют лишь Service своего namespace. IP-адреса, внешние хосты и чужие namespace отклоняются, иначе право создать Ingress в одном namespace давало бы доступ ко всему, что видит под оператора.
  • Поды без лишних прав. Непривилегированный пользователь, корневая ФС только для чтения, без capabilities.

Удобно для GitOps​

Если кластером управляет Argo CD или Flux, оператор не мешает:

  • домен или порт, который уже есть в аккаунте, подхватывается под управление, а не падает с ошибкой;
  • с reclaimPolicy: Retain резервация переживает удаление ресурса — пересоздали кластер, а домен на месте;
  • резервацию, удалённую в кабинете вручную, оператор создаст снова.

Как попробовать​

Создайте API-ключ для оператора и поставьте чарт:

helm repo add tuna https://code.tuna.am/api/packages/tuna/helm
helm install tuna-operator tuna/tuna-k8s-operator \
--namespace tuna-system --create-namespace \
--set credentials.apiKey=<API-ключ>

Какие права дать ключу, как поставить оператор через Nelm и где хранить ключ, кроме --set, — в документации.

Что дальше​

Это первая версия: API v1alpha1, поля ресурсов ещё могут поменяться. Трафик пока идёт через под оператора, а при его обновлении туннели переподключаются.

В ближайших планах:

  • Туннели прямо из Service. Service типа LoadBalancer с loadBalancerClass: tuna получит туннель сам, без Ingress и без ресурса Tunnel.
  • Синхронизация секретов. Оператор будет переносить секреты Tuna в Secret кластера и обновлять их при изменениях.
  • Маршрутизация на нодах Tuna. Правила Ingress переедут на наши ноды, трафик перестанет идти через под оператора, а следом появится Gateway API.

Не хватает какой-то возможности или оператор не заработал — напишите в поддержку.

Оставьте отзыв​

Если вам нравится пользоваться Tuna, или наоборот вы недовольны чем-либо, то пожалуйста оставьте отзыв.

Новости​

Анонсы новых функций и статей публикуем в Telegram-канале. Подписывайтесь, чтобы ничего не пропустить.

Помощь​

Мы ценим наших пользователей и детально изучаем все обращения, если у вас возникли проблемы с tuna – обязательно свяжитесь с нами одним из способов: