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

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

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

Internet - Ingress Controller - Service - Pods

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

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

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

Что не так с Ingress?

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

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

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

person.marketplace.com
api.marketplace.com

Есть 2 Service:

person-sercice
api-service

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

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

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

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

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

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

shop.marketpalce.com
api.marketplace.com
admin.marketplace.com
person.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: Gateway

metadata:
  name: web-gateway

spec:
  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/v1
kind: HTTPRoute

metadata:
  name: shop-route

spec:
  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 A
Pod B
Pod 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?

Комментарии (0)