Kubernetes-оператор
Оператор публикует Service кластера через туннели Tuna и управляет доменами и TCP-портами аккаунта ресурсами Kubernetes. Кластер подключается к Tuna исходящими соединениями: LoadBalancer, публичный IP и открытые входящие порты не нужны.
Ресурсы оператора (группа k8s.tuna.am/v1alpha1):
- Tunnel — HTTP- или TCP-туннель к Service;
- Ingress с
ingressClassName: tuna— маршрутизация по путям к нескольким Service за одним доменом; - Domain — постоянный поддомен или свой домен в аккаунте;
- TCPEndpoint — зарезервированный TCP-порт с алиасом.
Это не то же самое, что tuna kubernetes: тот туннель даёт временный доступ к Kubernetes API, а оператор публикует приложения из кластера.
Требования
- Kubernetes 1.32 или новее;
- Nelm (рекомендуем) или Helm 4;
- API-ключ с записью в «Эндпоинты и домены» (
tunnels:write) или с полным доступом к API.
Установка
Чарт лежит в реестре пакетов code.tuna.am.
Nelm
Nelm показывает план изменений до применения и обновляет CRD вместе с релизом:
export NELM_FEAT_REMOTE_CHARTS=true
nelm repo add tuna https://code.tuna.am/api/packages/tuna/helm
nelm release plan install -n tuna-system -r tuna-operator tuna/tuna-k8s-operator \
--set credentials.apiKey=<API-ключ>
nelm release install -n tuna-system -r tuna-operator tuna/tuna-k8s-operator \
--set credentials.apiKey=<API-ключ>
Helm
helm repo add tuna https://code.tuna.am/api/packages/tuna/helm
helm repo update
helm install tuna-operator tuna/tuna-k8s-operator \
--namespace tuna-system --create-namespace \
--set credentials.apiKey=<API-ключ>
Где хранить ключ
-
credentials.apiKey— чарт сам создаст Secret; -
credentials.existingSecret— свой Secret с ключомapi-key, например из External Secrets Operator или Sealed Secrets; -
extraEnv— переменнаяTUNA_API_KEYот инжектора секретов, без Secret в Kubernetes. Пример для Bank-Vaults:podAnnotations:vault.security.banzaicloud.io/vault-addr: https://vault.vault.svc:8200vault.security.banzaicloud.io/vault-role: tuna-operatorextraEnv:- name: TUNA_API_KEYvalue: vault:secret/data/tuna#api-key
Остальные параметры — в values.yaml и README чарта.
Туннель к Service
apiVersion: k8s.tuna.am/v1alpha1
kind: Tunnel
metadata:
name: web
spec:
protocol: http
subdomain: my-app
upstream:
url: http://web:8080
Публичный адрес появится в статусе ресурса:
kubectl get tunnel web
Туннелю можно задать свой ключ из Secret — поле api-key, у ключа должно быть право tunnels:connect:
spec:
apiKeySecretRef:
name: team-tuna-api-key
Ingress с маршрутами по путям
Хост Ingress должен быть зарезервированным доменом: ресурсом Domain или доменом из личного кабинета. Полное имя домена покажет kubectl get domain my-app.
apiVersion: k8s.tuna.am/v1alpha1
kind: Domain
metadata:
name: my-app
spec:
subdomain: my-app
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app
spec:
ingressClassName: tuna
rules:
- host: my-app.a.2na.am
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api
port:
number: 8080
- path: /
pathType: Prefix
backend:
service:
name: web
port:
name: http
На каждый хост создаётся один туннель. Изменения путей и бэкендов применяются без переподключения. Префиксы сравниваются по сегментам пути: /api подходит для /api/users, но не для /apix. Бэкенд получает публичный заголовок Host, а также X-Forwarded-Host и X-Forwarded-Proto.
Ограничения: бэкендом может быть только Service, правила без хоста и wildcard-хосты пропускаются, несколько Ingress на один хост не согласуются между собой.
Свой домен
apiVersion: k8s.tuna.am/v1alpha1
kind: Domain
metadata:
name: api-example-com
spec:
domain: api.example.com
reclaimPolicy: Retain
DNS-записи, которые нужно создать у DNS-провайдера, появятся в status.dnsRecords. Если проверка DNS не прошла, оператор сам перезапускает её раз в 5 минут. Переключить существующий ресурс между subdomain и domain нельзя — создайте новый.
TCP-порт
apiVersion: k8s.tuna.am/v1alpha1
kind: TCPEndpoint
metadata:
name: postgres
spec:
alias: postgres
---
apiVersion: k8s.tuna.am/v1alpha1
kind: Tunnel
metadata:
name: postgres
spec:
protocol: tcp
portOrAlias: postgres
upstream:
url: tcp://postgres:5432
Справка по полям: kubectl explain tunnel.spec, kubectl explain domain.spec, kubectl explain tcpendpoint.spec. Другие примеры — в каталоге examples/ чарта.
Существующие резервации
Если домен или алиас уже есть в аккаунте — создан в кабинете или другим кластером, — Domain и TCPEndpoint подхватывают эту резервацию, а не падают с ошибкой. У такого ресурса status.adopted: true, и оператор не удалит резервацию никогда.
Для остальных ресурсов reclaimPolicy: Delete (по умолчанию) освобождает резервацию при удалении ресурса, а Retain её сохраняет. Если резервацию удалили в кабинете, оператор создаст её снова.
Состояние и ошибки
Состояние каждого ресурса — в условии Ready и в событиях Kubernetes:
kubectl describe tunnel web
У Ingress условий нет, смотрите его события: TunnelConnected, TunnelStopped, RoutesUpdated, RuleSkipped, BackendSkipped.
Безопасность
- Tunnel и Ingress публикуют только Service своего namespace. IP-адреса, внешние хосты, Service других namespace и Service типа
ExternalNameотклоняются. ПараметрagentManager.allowExternalUpstreams=trueснимает ограничение, но тогда право создавать Tunnel или Ingress в любом namespace означает право опубликовать любой адрес, доступный поду оператора. - У каждого туннеля свой временный токен, он отзывается при удалении ресурса. Токены ресурсов, удалённых, пока оператор не работал, отзываются автоматически.
- Поды работают от непривилегированного пользователя, с корневой ФС только для чтения и без capabilities. Secret и Service читает только компонент с туннелями, и только
get. - Туннели работают внутри пода оператора: трафик идёт из Tuna через под к Service. Под туннелей — одна реплика, поэтому при обновлении оператора туннели переподключаются.
Обновление
С Nelm — те же nelm release plan install и nelm release install с новой --chart-version: CRD обновятся вместе с релизом.
Helm не обновляет CRD, примените их до обновления чарта:
helm pull tuna/tuna-k8s-operator --untar --version <версия>
kubectl apply -f tuna-k8s-operator/crds/
helm upgrade tuna-operator tuna/tuna-k8s-operator --namespace tuna-system --reuse-values --version <версия>
Удаление
Сначала удалите ресурсы: у Domain и TCPEndpoint есть финализаторы, им нужен работающий оператор.
kubectl delete tunnels,domains,tcpendpoints --all --all-namespaces
nelm release uninstall -n tuna-system -r tuna-operator # или: helm uninstall tuna-operator -n tuna-system
kubectl delete crd tunnels.k8s.tuna.am domains.k8s.tuna.am tcpendpoints.k8s.tuna.am