Предыдущие статьи:

Kubernetes просто, часть 4: как трафик попадает в кластер, NodePort и LoadBalancer
Kubernetes просто, часть 3: зачем нужен Service и как трафик доходит до конкретного Pod
Kubernetes просто, часть 2: что происходит после kubectl apply
Kubernetes просто, часть 1: зачем Kubernetes, устройство кластера

В прошлой части мы успели разобрать, как трафик попадает в кластер извне, из Интернета и локальных сетей.

Теперь у нас есть три типа Service

ClusterIP

NodePort

LoadBalancer

И для внешнего доступа мы пришли к следующей схеме:

Internet
   ↓
Load Balancer
   ↓
Service
   ↓
Pods

Для одного приложения всё довольно закономерно. Но давайте представим, что наш кластер постепенно растёт. Теперь в нём работают несколько приложений:

shop.example.com

admin.example.com

api.example.com

Каждому из них нужен внешний доступ. И, конечно, можно просто собрать для каждого из них Service типа LoadBalancer для его осуществления.

В итоге получаем:

Тут возникает закономерный вопрос:

Обязательно ли каждому HTTP‑приложению создавать собственную внешнюю точку входа?

Этот подход кажется нерациональным — неужто его нельзя оптимизировать?

Хочется принимать трафик в одном месте, а уже потом решать:

shop.example.com
        ↓
shop-service

api.example.com
        ↓
api-service

admin.example.com
        ↓
admin-service

А может, даже так:

example.com/shop
        ↓
shop-service

example.com/api
        ↓
api-service

Именно для такой маршрутизации в зависимости от HTTP‑адреса в Kubernetes используется Ingress. Его изучению и посвятим эту статью.

Что это такое?

Начнём с простого:

Ingress описывает правила маршрутизации HTTP/HTTPS‑трафика к Services внутри Kubernetes.

Фактически, с этим мы уже определились ранее.

До этого мы имели:

Internet
   ↓
Load Balancer
   ↓
Service
   ↓
Pods

А теперь появляется новый уровень:

Internet
   ↓
Ingress
   ├──→ Service A → Pods
   └──→ Service B → Pods

Ingress умеет «смотреть» на HTTP‑запрос и определять, какому Service его передать.

К примеру, пришёл запрос на

https://shop.example.com

Он закономерно попадёт в shop‑service.

А запрос на

https://api.example.com

Отправится в api‑service.

В итоге имеем:

Ingress ≠ Service

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

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

К примеру:

backend-service
       ├── Pod A
       ├── Pod B
       └── Pod C

Задача Ingress похожа, но уже относительно сервисов, а не подов. Он работает на уровень выше и распределяет трафик по сервисам.

Маршрутизация по домену

Посмотрим на первый сценарий, о котором мы говорили:

Имеется два адреса и два сервиса, которые им соответствуют:

api.example.com -> api-service

shop.example.com -> shop-service

Соответственно, мы хотим получить соответствующую маршрутизацию, чтобы запросы на первый адрес попадали в api‑service и аналогично для shop.

Ingress позволяет легко описать такие правила:

apiVersion: networking.k8s.io/v1
kind: Ingress

metadata:
  name: example-ingress

spec:
  rules:
    - host: shop.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: shop-service
                port:
                  number: 80

    - host: api.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: api-service
                port:
                  number: 80

На первый взгляд — YAML большой и непонятный, но идея здесь довольно лаконичная и простая.

Есть правило:

host: <адрес, к примеру api.example.com>

И backend, который его должен обслуживать:

service:
  name: <имя сервиса>
  port:
    number: <порт, на котором принимает запросы сервис>

Соответственно:

если host = shop.example.com
              ↓
отправить в shop-service:80

Аналогично для api.example.com.

Маршрутизация по пути

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

marketplace.com/catalog

marketplace.com/profile

И подобные. Часть после «/» обычно называется путём запроса.

Соответственно, хотелось бы иметь возможность маршрутизировать трафик именно в зависимости от пути.

marketplace.com/catalog -> catalog-service

marketplace.com/profile -> profile-service

В manifest это может быть отображено так:

rules:
  - host: marketplace.com
    http:
      paths:
        - path: /catalog
          pathType: Prefix
          backend:
            service:
              name: catalog-service
              port:
                number: 80

        - path: /profile
          pathType: Prefix
          backend:
            service:
              name: profile-service
              port:
                number: 80

Теперь Ingress смотрит не только на домен запроса, но и на path (его путь).

pathType

В манифесте выше появилось:

pathType: Prefix

Сейчас достаточно понимать его как:

Путь считается префиксом для маршрутизации запросов.

Иначе говоря, запросы на

marketplace/catalog

marketplace/catalog/technic

marketplace/catalog/technic/phones

Все будут маршрутизироваться по правилу префикса /catalog сервисом catalog-service.

Есть и другие варианты pathType, но сейчас углубляться в них не будем.

Ingress — набор правил

Вполне возможно, что Ingress уже усвоился в вашей голове как набор правил по маршрутизации трафика. Так и есть!

Мы создали:

kind: Ingress

В нём написали, какие маршруты на какие сервисы ссылаются. Фактически, сам объект Ingress — просто набор правил. Но кто эти правила реализует? Кто следит за тем, чтобы они выполнялись?

Здесь появляется Ingress Controller.

Упрощённо имеем:

Ingress
   │ содержит правила
   ↓
Ingress Controller
   │ реализует их
   ↓
Services

Это похоже на уже знакомый нам принцип, с desired и actual state кластера.

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

Так и здесь:

Мы описываем набор правил, а контроллер следит за объектами Ingress и настраивает соответствующую маршрутизацию трафика.

Собираем всё вместе

Представим, что у нас есть Интернет‑магазин.

В Kubernetes работают:

Frontend Pods

API Pods

Admin Pods

Для каждой группы подов создан свой Service.

shop-service

api-service

admin-service

Наружу мы хотим отдать:

shop.example.com

api.example.com

admin.example.com

Имеем в итоге:

И здесь уже хорошо видно разделение ответственности.

DNS
 ↓
Где находится внешний адрес?
----------------------------
Load Balancer
 ↓
Как попасть в кластер?
----------------------------
Ingress
 ↓
К какому HTTP backend
отправить запрос?
----------------------------
Service
 ↓
Какие Pods стоят
за этим backend?
----------------------------
Pods
 ↓
Где работает приложение?

Что запомнить

После этой части главное не запоминать большой Ingress YAML.

Гораздо важнее держать в голове цепочку:

Internet
   ↓
Ingress Controller
   ↓
Ingress rules
   ↓
Service
   ↓
Pods

Ingress описывает правила HTTP/HTTPS‑маршрутизации.

Например:

shop.example.com -> shop-service

api.example.com -> api-service

Ingress Controller — компонент, который реализует эти правила и фактически обрабатывает соответствующий входящий трафик.

А Service по‑прежнему решает уже знакомую задачу:

Service
   ↓
backend Pods

Как итог:

Ingress ≠ Service

Ingress ≠ Ingress Controller

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

1. Какую проблему решает Ingress, если у нас уже есть Service типа LoadBalancer?

2. Чем отличаются задачи Ingress и Service?

3. Есть правила:

shop.example.com -> shop-service

api.example.com -> api-service

Куда должен попасть запрос:

https://api.example.com

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