Kubernetes просто часть 6: Для чего нужен Gateway API?

—

от автора

Предыдущие статьи:
Kubernetes просто, часть 5: зачем нужен Ingress и как маршрутизировать HTTP-трафик
Kubernetes просто, часть 1: зачем Kubernetes, устройство кластера

Лабораторные работы:
Kubernetes просто лабы, часть 1: поднимаем кластер и знакомимся с его устройством

В прошлой части мы успели разобрать, что такое Ingress и в итоге пришли к схеме:

Internet - Ingress Controller - Service - Pods

Ingress позволил решить важную задачу — вместо отдельной внешней точки доступа для каждого приложения он представил нам возможность сделать общую точку входа для маршрутизации HTTP-трафика:

Всё это довольно разумно и, должно быть, когда я скажу, что тема, которую мы будем разбирать сегодня предназначена для выполнения практически той же задачи, у вас возникнет закономерный вопрос: «Если Ingress это уже умеет, зачем нужен еще и Gateway API?».

Давайте разбираться!

Что не так с Ingress?

Отвечу сразу — с ним всё в порядке.

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

Есть несколько приложений:

person.marketplace.comapi.marketplace.com

Есть 2 Service:

person-serciceapi-service

Мы хотим получить:

person.marketplace.com -> person-serciceapi.marketplace.com -> api-service

Создаём Ingress, описываем правила маршрутизации — получаем нужный результат.

Поэтому проблема, решаемая Gateway API не в том, что Ingress работает плохо — проблема в возможности масштабирования такой инфраструктуры. Сейчас объясню.

Представьте, наш мини-маркетплейс вырос в настоящий взрослый проект — большой конкурент серьезных компаний.

Теперь там работают уже не 2 домена, а, скажем 4:

shop.marketpalce.comapi.marketplace.comadmin.marketplace.comperson.marketplace.com

Но, что важнее, за ними стоят разные команды. Команда фронтендеров отвечает за shop.marketplace.com, команда бэкендеров за api.marketplace.com, администраторы за admin.marketplace.com и так далее.

При этом существует еще одна команда, скажем Команда Развертывания — она как раз занимается контролем общей точки входа.

Internet -> общая точка входа

К примеру, какие порты доступны снаружи и где настраивается HTTPS.

Разработчикам из других команд это совершенно не интересно, команде фронтендеров интересно shop.marketplace.com -> shop-service, остальным их домены и сервисы, соответственно.

Иначе говоря, здесь появляются две разные задачи —

«Как трафик попадает в кластер и куда отправлять трафик после входа»

Это разделение очень важно для понимания Gateway API.

Разделим две задачи

Пока забудем про названия объектов Kubernetes и сконцентрируемся на понимании желаемой архитектуры.

Нужна точка входа:

Internet -> ТОЧКА ВХОДА

Она принимает весь внешний трафик.

Но после неё нужно решить: «Куда отправлять конкретный запрос?»

Поэтому добавим ещё уровень:

Internet -> ТОЧКА ВХОДА --МАРШРУТ--> Service

Теперь у нас две отдельные сущности:

Первая отвечает за входящий трафик, вторая за правила его маршрутизации.

Именно вокруг такого разделения построена модель Gateway API.

Gateway и HTTPRoute

Теперь можно дать двум сущностям имена — точку входа зовут Gateway, а маршруты называют HTTPRoute.

Теперь всё выглядит как:

Internet - Gateway - HTTPRoute - Service - Pods

Это, на данный момент, главная схема, которую стоит запомнить. Разберем два новых компонента по-отдельности.

Gateway

Начнем с Gateway.

Достойная аналогия — вход в большое офисное здание.

Здесь нас интересует:

Какой трафик принимать?
На каком порту?
По какому протоколу?

К примеру

Internet -> HTTP:80 Gateway

В Gateway API такую задачу описывает kind: Gateway

Упрощённо:

kind: Gatewaymetadata:  name: web-gatewayspec:  gatewayClassName: example  listeners:    - name: http      protocol: HTTP      port: 80

Пока большую часть можно даже не запоминать.

Взгляните на нижнюю часть:

  listeners:    - name: http      protocol: HTTP      port: 80

Мы описываем listener (слушателя) и говорим — слушай порт 80, принимай по нему HTTP-трафик.

Пока Gateway вообще не обязан знать, что у нас есть shop-service или api-service, как мы это делали раньше в Ingress.

Мы уже обсуждали, его задача другая — принимать весь трафик. Вот мы и организовали такой вход.

Что делает HTTPRoute?

Теперь пользователь отправляет запрос на http://shop.marketplace.com

Gateway его принял, но куда отправлять его дальше?

Вот тут-то и появляется kind: HTTPRoute.Он описывает правила HTTP-маршрутизации.

К примеру:

shop.marketplace.com ->  shop-service

Создадим простой HTTPRoute:

apiVersion: gateway.networking.k8s.io/v1kind: HTTPRoutemetadata:  name: shop-routespec:  parentRefs:    - name: web-gateway  hostnames:    - shop.marketplace.com  rules:    - backendRefs:        - name: shop-service          port: 80

Выглядит объемно, разберем по частям.

Сначала:

parentRefs:    - name: web-gateway

Упрощенно это значит — связан с web-gateway (имя нашей точки входа)

Дальше:

hostnames:  - shop.marketplace.com

То есть этот маршрут относится к запросам на shop.marketplace.com

И наконец:

- backendRefs:    - name: shop-service      port: 80

Мы выбираем куда отправлять входящие запрос. Соберем всё вместе:

Расширяемся

Теперь хотим добавить api.marketplace.com

Для него уже существует api-service, и, вы уже чувствуете, насколько удобен здесь Gateway API.

Объект Gateway у нас уже есть, создавать второй экземпляр не обязательно, точка входа может остаться прежней. Достаточно создать один новый api-route. Получаем:

Разделение ответственности оказалось действительно удобным!

Чем это лучше Ingress?

Теперь можно вернуться к вопросу из начала статьи:

Ingress тоже позволял написать, какие маршруты на какой сервис ссылаются.  Зачем тогда это было.

Ключевая идея в модели управления Gateway добавил нам новые объекты, позволяющие модульно делить выполнение работы между командами разработчиков.

Такая модульность как раз намного ближе к тому, как устроен большой Kubernetes-кластер.

А как же контроллер?

Мы уже сталкивались с похожей ситуацией в прошлой части. Сам объект Ingress содержал правила, но для реальной обработки трафика нужен был Ingress Controller.

С Gateway API идея похожая. Gateway и HTTPRoute — это объекты Kubernetes. Они описывают, какую точку входа и какие маршруты мы хотим получить, но сами по себе сетевой трафик не принимают.

В кластере должен быть установлен сетевой компонент, который умеет работать с Gateway API. Он следит за такими объектами и настраивает реальную обработку трафика.

Упрощенно:

Gateway + HTTPRoute        ↓сетевой компонент с поддержкой Gateway API        ↓реальная обработка трафика

То есть мы снова приходим к уже знакомой модели: Kubernetes хранит желаемое состояние, а соответствующий контроллер приводит реальную систему к нему.

А что тогда такое GatewayClass?

Вернемся к манифесту Gateway. В нем у нас была строка:

gatewayClassName: example

Значение example здесь появилось не случайно. Gateway должен понимать, какой установленный в кластере сетевой компонент будет его обслуживать.

Для этой связи и существует отдельный объект — GatewayClass.

сетевой компонент        ↓   GatewayClass        ↓     Gateway        ↓    HTTPRoute

На нашем текущем уровне этого понимания достаточно: GatewayClass связывает Gateway с конкретной реализацией Gateway API, которая умеет превратить наши YAML-объекты в работающую сетевую конфигурацию.

Поэтому строку:

gatewayClassName: example

можно читать примерно так: «для этого Gateway используй GatewayClass с именем example».

Сам GatewayClass обычно появляется в кластере вместе с установленной реализацией Gateway API или создается при ее настройке. В практической части мы посмотрим это руками, поэтому сейчас глубже в контроллеры и конкретные реализации уходить не будем.

Что происходит с Service?

Здесь ничего принципиально не меняется. HTTPRoute направляет запрос не в конкретный Pod, а в Service.

Gateway   ↓HTTPRoute   ↓shop-service   ↓Pod APod BPod C

Если Pod B исчезнет, ReplicaSet создаст новый Pod. У него может быть другой IP и он может оказаться на другой Node, но HTTPRoute менять не придется.

Он по-прежнему указывает на shop-service, а Service уже работает с актуальным набором backend endpoints.

Получается знакомая нам цепочка:

Gateway   ↓HTTPRoute   ↓стабильный Service   ↓динамические Pods

Собираем картину целиком

Теперь можно собрать все объекты, которые появились в этой части, в одну схему:

Internet   ↓Gateway   ↓HTTPRoute   ↓Service   ↓Pods

Gateway отвечает за точку входа. HTTPRoute описывает правило маршрутизации. Service предоставляет стабильный доступ к backend Pods.

А GatewayClass нужен уровнем выше — он связывает Gateway с той реализацией Gateway API, которая действительно умеет обслуживать такую конфигурацию.

Поэтому полную картину можно представить так:

GatewayClass     ↓Gateway     ↓HTTPRoute     ↓Service     ↓Pods

Это прежде всего схема ответственности объектов, которую нам важно закрепить.

Если эта схема понятна, детали YAML и конкретных реализаций дальше будут восприниматься намного проще.

Проверьте себя

1. Если Ingress уже умеет маршрутизировать HTTP-трафик, зачем может понадобиться Gateway API?

2. За что в нашей модели отвечает Gateway?

3. За что отвечает HTTPRoute?

4. Можно ли подключить несколько HTTPRoute к одному Gateway?

5. Почему разделение Gateway и HTTPRoute удобно, если инфраструктурой и приложениями управляют разные команды?

6. Сам объект Gateway принимает сетевые пакеты или только описывает желаемую точку входа?

7. Зачем нужен GatewayClass?

ссылка на оригинал статьи https://habr.com/ru/articles/1091780/