<a id="transportserver-resource"></a>

# TransportServer

* **og:description:**
  Ресурс TransportServer для настройки балансировки нагрузки TCP, UDP и TLS Passthrough в ANIC

Ресурс TransportServer позволяет настраивать балансировку нагрузки по
протоколам TCP, UDP и TLS Passthrough. Он реализован как [пользовательский
ресурс](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/).

Это справочная документация по ресурсу TransportServer.

## Предварительные требования

- Для TCP и UDP ресурс TransportServer должен использоваться совместно с
  ресурсом GlobalConfiguration, который должен быть создан отдельно.
- Для TLS Passthrough обязательно включите параметр командной строки
  `-enable-tls-passthrough` в ANIC.

## Спецификация TransportServer

Ресурс TransportServer определяет конфигурацию балансировки нагрузки для
трафика TCP, UDP или TLS Passthrough. Ниже приведено несколько примеров:

- Балансировка нагрузки TCP:
  ```yaml
  apiVersion: k8s.angie.software/v1alpha1
  kind: TransportServer
  metadata:
  name: dns-tcp
  spec:
  listener:
      name: dns-tcp
      protocol: TCP
  tls:
      secret: cafe-secret
  upstreams:
  - name: dns-app
    service: dns-service
    port: 5353
    action:
    pass: dns-app
  ```
- Балансировка нагрузки UDP:
  ```yaml
  apiVersion: k8s.angie.software/v1alpha1
  kind: TransportServer
  metadata:
  name: dns-udp
  spec:
  listener:
      name: dns-udp
      protocol: UDP
  upstreams:
  - name: dns-app
    service: dns-service
    port: 5353
    upstreamParameters:
    udpRequests: 1
    udpResponses: 1
    action:
    pass: dns-app
  ```
- Балансировка нагрузки TLS Passthrough:
  ```yaml
  apiVersion: k8s.angie.software/v1alpha1
  kind: TransportServer
  metadata:
  name: secure-app
  spec:
  listener:
      name: tls-passthrough
      protocol: TLS_PASSTHROUGH
  host: app.example.com
  upstreams:
  - name: secure-app
    service: secure-app
    port: 8443
    action:
    pass: secure-app
  ```

| Поле                 | Описание                                                                                                                                                                                                                                                                  | Тип                                       | Обязательно   |
|----------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------|---------------|
| `listener`           | Прослушиватель, через который Angie будет принимать входящие соединения и датаграммы.                                                                                                                                                                                     | [Listener](#listener)                     | Да            |
| `host`               | Хост (доменное имя) сервера. Это должен быть допустимый поддомен, как определено в RFC 1123, например `my-app` или `hello.example.com`. Домены с подстановочными знаками, такие как `*.example.com`, не допускаются. Требуется для балансировки нагрузки TLS Passthrough. | `string`                                  | Нет           |
| `tls`                | Конфигурация терминации TLS. Не поддерживается для балансировки нагрузки TLS Passthrough.                                                                                                                                                                                 | [TLS](#tls)                               | Нет           |
| `upstreams`          | Список апстримов.                                                                                                                                                                                                                                                         | [upstream[ ]](#upstream)                  | Да            |
| `upstreamParameters` | Параметры апстрима.                                                                                                                                                                                                                                                       | [UpstreamParameters](#upstreamparameters) | Нет           |
| `action`             | Действие, выполняемое для клиентского соединения или датаграммы.                                                                                                                                                                                                          | [Action](#action)                         | Да            |
| `ingressClassName`   | Указывает, какой экземпляр ANIC должен обрабатывать ресурс TransportServer.                                                                                                                                                                                               | `string`                                  | Нет           |
| `streamSnippets`     | Задает пользовательский фрагмент в контексте `stream`.                                                                                                                                                                                                                    | `string`                                  | Нет           |
| `serverSnippets`     | Задает пользовательский фрагмент в контексте `server`.                                                                                                                                                                                                                    | `string`                                  | Нет           |

<a id="listener"></a>

### Listener

Ссылается на прослушиватель, через который Angie будет принимать входящий
трафик к TransportServer. Для TCP и UDP прослушиватель должен быть определен в
ресурсе GlobalConfiguration.
При ссылке на прослушиватель должны совпадать как имя, так и протокол. Для TLS
Passthrough используйте встроенный прослушиватель с именем `tls-passthrough`
и протоколом `TLS_PASSTHROUGH`.

Пример:

```yaml
listener:
  name: dns-udp
   protocol: UDP
```

| Поле       | Описание                 | Тип      | Обязательно   |
|------------|--------------------------|----------|---------------|
| `name`     | Имя прослушивателя.      | `string` | Да            |
| `protocol` | Протокол прослушивателя. | `string` | Да            |

<a id="tls"></a>

### TLS

Поле tls определяет конфигурацию TLS для TransportServer. Обратите внимание,
что текущая реализация поддерживает терминацию TLS на нескольких портах, где
каждому приложению принадлежит выделенный порт. При этом ANIC
терминирует TLS-соединения на каждом порту, где каждое приложение использует свой
собственный сертификат или ключ, и направляет соединения соответствующему
приложению (сервису) на основе этого входящего порта (т. е. любое
TLS-соединение независимо от настроек SNI на порту будет перенаправлено в
приложение, соответствующее этому порту).

Пример конфигурации показан ниже:

```yaml
secret: cafe-secret
```

| Поле     | Описание                                                                                                                                                                                                                                                                                                                                                                   | Тип      | Обязательно   |
|----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------|---------------|
| `secret` | Имя секрета с сертификатом TLS и ключом. Секрет должен принадлежать тому же<br/>пространству имен, что и транспортный сервер. Секрет должен иметь тип<br/>`kubernetes.io/tls` и содержать ключи с именами `tls.crt` и<br/>`tls.key`, содержащие сертификат и закрытый ключ, как описано<br/>[здесь](https://kubernetes.io/docs/concepts/services-networking/ingress/#tls). | `string` | Нет           |

<a id="upstream"></a>

### Upstream

Определяет конечное место назначения для TransportServer. Например:

```yaml
name: secure-app
service: secure-app
port: 8443
maxFails: 3
maxConns: 100
failTimeout: 30s
loadBalancingMethod: least_conn
```

| Поле                  | Описание                                                                                                                                                                                                                                                                                                                                                                                     | Тип      | Обязательно   |
|-----------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------|---------------|
| `name`                | Имя апстрима. Это должна быть допустимая метка DNS, как определено в RFC<br/>1035. Например, допустимы значения `hello` и `upstream-123`. Имя<br/>должно быть уникальным среди всех апстримов ресурса.                                                                                                                                                                                       | `string` | Да            |
| `service`             | Название [сервиса](https://kubernetes.io/docs/concepts/services-networking/service/).<br/>Сервис должен принадлежать к тому же пространству имен, что и ресурс.<br/>Если сервиса не существует, Angie предположит, что у него нет конечных<br/>точек, и будет закрывать клиентские соединения и игнорировать<br/>датаграммы.                                                                 | `string` | Да            |
| `port`                | Порт службы. Если у сервиса этот порт не задан, Angie предположит, что у<br/>него нет конечных точек, и будет закрывать клиентские соединения и<br/>игнорировать датаграммы. Значение должно находиться в диапазоне<br/>`1..65535`.                                                                                                                                                          | `int`    | Да            |
| `maxFails`            | Задает [число](https://angie.software//angie/docs/configuration/modules/stream/stream_upstream.md#s-u-server) неудачных попыток установить связь с<br/>сервером, которые должны произойти в течение времени, заданного<br/>параметром `failTimeout`, чтобы сервер считался недоступным.<br/>Значение по умолчанию: `1`.                                                                      | `int`    | Нет           |
| `maxConns`            | Задает максимальное число <s_u_server> подключений к проксируемому<br/>серверу. Значение по умолчанию равно нулю, что означает отсутствие<br/>ограничений. Значение по умолчанию равно `0`.                                                                                                                                                                                                  | `int`    | Нет           |
| `failTimeout`         | Задает [время](https://angie.software//angie/docs/configuration/modules/stream/stream_upstream.md#s-u-server), в течение которого должно произойти<br/>указанное количество неудачных попыток установить связь с сервером, чтобы<br/>считать сервер недоступным, и период времени, в течение которого сервер<br/>будет считаться недоступным. Значение по умолчанию равно `10`<br/>секундам. | `string` | Нет           |
| `loadBalancingMethod` | Метод балансировки нагрузки между серверами апстрима. По умолчанию<br/>соединения распределяются между серверами по методу взвешенной<br/>циклической балансировки. Доступные методы и подробности смотрите в<br/>разделе [Апстрим](https://angie.software//angie/docs/configuration/modules/stream/stream_upstream.md#stream-upstream).                                                     | `string` | Нет           |

<a id="upstreamparameters"></a>

### UpstreamParameters

Различные параметры апстрима:

```yaml
upstreamParameters:
  udpRequests: 1
  udpResponses: 1
  connectTimeout: 60s
  nextUpstream: true
  nextUpstreamTimeout: 50s
  nextUpstreamTries: 1
```

| Поле                  | Описание                                                                                                                                                                                                                                                                                                                            | Тип      | Обязательно   |
|-----------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------|---------------|
| `udpRequests`         | Количество датаграмм, после получения которых следующая датаграмма от<br/>того же клиента запускает новый сеанс. См. директиву<br/>[proxy_requests](https://angie.software//angie/docs/configuration/modules/stream/stream_proxy.md#s-proxy-requests). Значение по умолчанию равно `0`.                                             | `int`    | Нет           |
| `udpResponses`        | Количество датаграмм, ожидаемых от проксируемого сервера в ответ на<br/>клиентскую датаграмму. См. директиву [proxy_responses](https://angie.software//angie/docs/configuration/modules/stream/stream_proxy.md#s-proxy-responses). По<br/>умолчанию количество датаграмм не ограничено.                                             | `int`    | Нет           |
| `connectTimeout`      | Тайм-аут установки соединения с проксируемым сервером. См. директиву<br/>[proxy_connect_timeout](https://angie.software//angie/docs/configuration/modules/stream/stream_proxy.md#s-proxy-connect-timeout).<br/>Значение по умолчанию - `60` секунд.                                                                                 | `string` | Нет           |
| `nextUpstream`        | Если соединение с проксируемым сервером установить не удается,<br/>определяет, будет ли клиентское соединение передано на следующий сервер.<br/>См. директиву [proxy_next_upstream](https://angie.software//angie/docs/configuration/modules/stream/stream_proxy.md#s-proxy-next-upstream).<br/>Значение по умолчанию равно `true`. | `bool`   | Нет           |
| `nextUpstreamTries`   | Количество попыток до передачи соединения к следующему серверу. См.<br/>директиву [proxy_next_upstream_tries](https://angie.software//angie/docs/configuration/modules/stream/stream_proxy.md#s-proxy-next-upstream-tries).<br/>Значение по умолчанию равно `0`.                                                                    | `int`    | Нет           |
| `nextUpstreamTimeout` | Время, отведенное для передачи соединения к следующему серверу. См.<br/>директиву [proxy_next_upstream_timeout](https://angie.software//angie/docs/configuration/modules/stream/stream_proxy.md#s-proxy-next-upstream-timeout).<br/>Значение по умолчанию - `0`.                                                                    | `string` | Нет           |

### SessionParameters

Различные параметры для TCP-соединений и UDP-сеансов.

```yaml
sessionParameters:
  timeout: 50s
```

| Поле      | Описание                                                                                                                                                                                                                                                                                               | Тип      | Обязательно   |
|-----------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------|---------------|
| `timeout` | Тайм-аут между двумя последовательными операциями чтения или записи в<br/>соединениях с клиентом или проксируемым сервером. См. директиву<br/>[proxy_timeout](https://angie.software//angie/docs/configuration/modules/stream/stream_proxy.md#s-proxy-timeout).<br/>Значение по умолчанию равно `10m`. | `string` | Нет           |

<a id="action"></a>

### Action

Действие, которое необходимо выполнить для клиентского соединения или
датаграммы.

В приведенном ниже примере клиентские подключения и датаграммы
передаются на апстрим в `dns-app`:

```yaml
action:
  pass: dns-app
```

| Поле   | Описание                                                                                               | Тип      | Обязательно   |
|--------|--------------------------------------------------------------------------------------------------------|----------|---------------|
| `pass` | Передает соединения и датаграммы апстриму. Апстрим<br/>с таким именем должен быть определен в ресурсе. | `string` | Да            |

## Использование TransportServer

Для работы с ресурсами TransportServer можно использовать обычные
команды `kubectl`, аналогично ресурсам Ingress.

Например, следующая команда создает ресурс TransportServer, определенный
в `transport-server-passthrough.yaml`, с именем `secure-app`:

```console
kubectl apply -f transport-server-passthrough.yaml

transportserver.k8s.angie.software/secure-app created
```

Вы можете получить ресурс, выполнив:

```console
kubectl get transportserver secure-app

NAME         AGE
secure-app   46sm
```

В `kubectl get` и подобных командах также можно использовать короткое имя
`ts` вместо `transportserver`.

### Использование фрагментов

Фрагменты позволяют вставлять элементы конфигурации Angie в различные контексты
конфигурации Angie. В приведенном ниже примере мы используем фрагменты для
настройки [контроля доступа](https://angie.software//angie/docs/configuration/modules/stream/stream_access.md#stream-access) на TransportServer:

```yaml
apiVersion: k8s.angie.software/v1alpha1
kind: TransportServer
metadata:
  name: cafe
spec:
  host: cafe.example.com
  serverSnippets: |
    deny  192.168.1.1;
    allow 192.168.1.0/24;
  upstreams:
  - name: tea
    service: tea-svc
    port: 80
```

Фрагменты также можно указать для потока. В приведенном ниже примере мы
используем фрагменты для [ограничения количества подключений](https://angie.software//angie/docs/configuration/modules/stream/stream_limit_conn.md#stream-limit-conn):

```yaml
apiVersion: k8s.angie.software/v1alpha1
kind: TransportServer
metadata:
  name: cafe
spec:
  host: cafe.example.com
  streamSnippets: limit_conn_zone $binary_remote_addr zone=addr:10m;
  serverSnippets: limit_conn addr 1;
  upstreams:
  - name: tea
    service: tea-svc
    port: 80
```

Фрагменты предназначены для продвинутых пользователей Angie, которым
требуется больше контроля над генерируемой конфигурацией Angie.

Однако из-за недостатков, описанных ниже, фрагменты по умолчанию отключены.
Чтобы использовать фрагменты, задайте аргумент командной строки
`enable-snippets`.

Недостатки использования фрагментов:

-  *Сложность*. Чтобы использовать фрагменты, требуется:
  - Понимать примитивы конфигурации Angie и реализовать правильную
    конфигурацию Angie.
  - Понимать, как ANIC генерирует конфигурацию Angie, чтобы фрагмент не
    мешал другим функциям конфигурации.
-  *Сниженная надежность*. Неправильный фрагмент делает конфигурацию
  Angie недействительной, что приведет к ошибке при перезагрузке. Это
  помешает применить какие-либо обновления конфигурации, включая
  обновления для другого ресурса TransportServer, пока фрагмент не
  будет исправлен.
-  *Последствия для безопасности*. Фрагменты предоставляют доступ к
  примитивам конфигурации Angie, и эти примитивы не проверяются самим
  ANIC.

#### NOTE
Пока конфигурация Angie содержит недопустимый фрагмент,
Angie будет продолжать работать с последней допустимой конфигурацией.

#### NOTE
Чтобы настроить фрагменты в контексте `stream`,
используйте ключ `stream-snippets` ConfigMap.

### Валидация

Для ресурса TransportServer доступны два типа валидации:

-  *Структурная валидация* с помощью `kubectl` и сервера Kubernetes
  API.
-  *Всесторонняя валидация* с помощью ANIC.

#### Структурная валидация

Пользовательское определение ресурса для TransportServer включает
структурную схему OpenAPI, которая описывает тип каждого поля ресурса.

Если вы попытаетесь создать (или обновить) ресурс с нарушением
структурной схемы (например, используете строковое значение для поля
порта апстрима), сервер `kubectl` и Kubernetes API отклонят такой
ресурс:

- Пример проверки `kubectl`:
  ```console
  kubectl apply -f transport-server-passthrough.yaml

    error: error validating "transport-server-passthrough.yaml": error validating data: ValidationError(TransportServer.spec.upstreams[0].port): invalid type for software.angie.k8s.v1alpha1.TransportServer.spec.upstreams.port: got "string", expected "integer"; if you choose to ignore these errors, turn validation off with --validate=false
  ```
- Пример проверки сервера Kubernetes API:
  ```console
  kubectl apply -f transport-server-passthrough.yaml --validate=false

    The TransportServer "secure-app" is invalid: []: Invalid value: map[string]interface {}{ ... }: validation failure list:
    spec.upstreams.port in body must be of type integer: "string"
  ```

Если ресурс не отклонен (то есть не нарушает структурную схему), ANIC
проверит его дополнительно.

#### Всесторонняя валидация

ANIC проверяет поля ресурса TransportServer. Если ресурс
недействителен, ANIC отклонит его: ресурс продолжит существовать
в кластере, но ANIC будет его игнорировать.

Вы можете проверить, успешно ли ANIC применил конфигурацию
TransportServer. Для примера TransportServer `secure-app` мы можем запустить:

```console
kubectl describe ts secure-app

. . .
Events:
  Type    Reason          Age   From                      Message
-----
Normal  AddedOrUpdated  3s    angie-ingress-controller  Configuration for default/secure-app was added or updated
```

Обратите внимание, что раздел `Events` (События) включает событие `Normal` с
причиной `AddedOrUpdated`, которое информирует нас о том, что конфигурация была
успешно применена.

Если вы создадите недопустимый ресурс, ANIC отклонит его и выдаст
событие `Rejected`. Например, если вы создадите TransportServer `secure-app` с
действием `pass`, которое ссылается на несуществующий апстрим, вы получите:

```console
kubectl describe ts secure-app

. . .
Events:
  Type     Reason    Age   From                      Message
-----
Warning  Rejected  2s    angie-ingress-controller  TransportServer default/secure-app is invalid and was rejected: spec.action.pass: Not found: "some-app"
```

Обратите внимание, что раздел событий включает событие `Warning` с причиной
`Rejected`.

#### NOTE
Если вы внесете ошибку в уже существующий ресурс, ANIC отклонит
его и удалит соответствующую конфигурацию из Angie.

### Настройка с помощью ConfigMap

Ключи `ConfigMap`
(за исключением `stream-snippets`, `stream-log-format`,
`resolver-addresses`, `resolver-ipv6`, `resolver-valid` и
`resolver-timeout`) не влияют на ресурсы TransportServer.
