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

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:8200
    vault.security.banzaicloud.io/vault-role: tuna-operator
    extraEnv:
    - name: TUNA_API_KEY
    value: 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