Браузерный маршрут и граница Gateway API
В предыдущем уроке страница получила доступ к API через Service. Теперь проследим один запрос целиком и определим, где в этой цепочке появляется внешняя маршрутизация. Для веб-разработчика это особенно важно: ошибка в origin, пути или переписывании URL часто выглядит как «Kubernetes не работает», хотя запущенные приложения и Service устроены правильно.
Локальный маршрут «Площадки» остаётся прежним: port-forward Service web, собственный reverse proxy в web и Service api. Новый контроллер в лабораторию не устанавливаем. Автор не запускал сеть или кластер. Внешние API ниже рассматриваются как архитектурные средства, а не как уже созданная инфраструктура.
Один origin для страницы и каталога
Когда читатель открывает http://127.0.0.1:8080/, браузер запоминает схему, адрес и порт как origin страницы. Относительный запрос /api/lessons использует тот же origin. При этом внутри Pod web находится другая конфигурация: API_BASE=http://api:3000. Браузерное и серверное окружения не имеют общего механизма разрешения этого имени.
Проследим цепочку:
Браузер GET http://127.0.0.1:8080/api/lessons
-> локальный port-forward
-> web:8080, обработчик пути /api/
-> Service api:3000
-> готовый Pod API, путь /api/lessons
-> JSON обратно по той же цепочке
Web сохраняет исходный путь и query string. API действительно ожидает префикс /api, поэтому удалять его не требуется. Эта договорённость должна быть явной. Если прокси перепишет запрос в /lessons, API вернёт 404, хотя соединение установилось. Ошибка пути отличается от отсутствия адресата: ответ уже доказывает, что какой-то HTTP-сервер получил обращение.
Не вставляйте http://api:3000 непосредственно в браузерный JavaScript. Ваш компьютер обычно не разрешает короткое имя Service; кроме того, изменится origin запроса и появятся требования CORS. Внутренние имена должны оставаться в серверной конфигурации. Если продукт намеренно использует отдельный публичный API origin, это допустимый вариант, но он требует другого HTTP-контракта и настройки доступа.
Наш прокси возвращает 502, когда не может получить ответ API. Такой статус означает сбой перехода между web и upstream, а не обязательно падение web. HTML при этом может продолжать открываться. В интерфейсе ошибка отображается рядом с кнопкой. Это полезная форма наблюдения: пользователь получает определённое сообщение, а разработчик сохраняет возможность различить слои.
Зачем внешнему маршруту нужен контроллер
Для публикации сайта одного Service ClusterIP недостаточно. Нужен компонент, принимающий трафик извне кластера и выполняющий правила маршрутизации. YAML с правилом не равен самому сетевому процессу. Контроллер читает декларацию, настраивает свою реализацию и сообщает состояние. Без совместимого контроллера манифест может существовать, а нужного адреса и работающего маршрута не будет.
В Kubernetes долго использовался Ingress. Его API networking.k8s.io/v1 остаётся стабильным, но развитие API заморожено. Проект Kubernetes рекомендует Gateway API для нового развития возможностей внешнего трафика; заморозка не означает автоматическое удаление существующих Ingress. Это различие прямо описано в документации Ingress.
Важно также различать Ingress как API и конкретный ingress-controller. У разных реализаций отличаются дополнительные настройки, сроки поддержки и поведение аннотаций. Старый пример с произвольной аннотацией не становится переносимым только потому, что объект называется Ingress. Поэтому в этом курсе не используется непроверенная установка контроллера из исторического урока.
Gateway API разделяет роли: GatewayClass описывает класс реализации, Gateway — слушатели и вход, HTTPRoute — маршруты приложения. Эти типы не появляются автоматически только от создания kind-кластера. Нужны CRD и выбранная реализация контроллера. Обзор модели доступен в документации Kubernetes Gateway API.
Как выразить маршрут приложения
Для «Площадки» внешняя реализация могла бы направлять весь трафик сайта к Service web. Тогда уже знакомый web продолжает проксировать API. Другой вариант — HTTPRoute отдельно направляет /api/ к Service api, а / к Service web. Во втором случае переносится ответственность за маршрутизацию, а приложение web можно упростить. Эти варианты нужно выбирать осознанно, чтобы два прокси не выполняли противоречащие преобразования пути.
Ниже только фрагмент будущего HTTPRoute после выбора и установки совместимой реализации:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: ploshchadka
namespace: ploshchadka
spec:
parentRefs:
- name: selected-gateway
hostnames:
- ploshchadka.example.test
rules:
- matches:
- path:
type: PathPrefix
value: /api/
backendRefs:
- name: api
port: 3000
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: web
port: 80
Имя selected-gateway здесь обозначает ещё не выбранный объект. Фрагмент не включён в набор применяемых манифестов и не является готовой инструкцией публикации. Он нужен для чтения структуры: backend port относится к порту Service, а не напрямую к контейнеру. Для web это 80, хотя Node-процесс слушает 8080.
У маршрута есть собственные условия принятия и разрешения ссылок. В будущем необходимо проверить, что Gateway допускает этот route, что backend существует и что контроллер умеет обработать используемые возможности. Наличие YAML-файла на диске не показывает ни одного из этих результатов. Затем отдельно проверяется реальный HTTP-путь с корректным Host.
TLS, cookies и доверие к прокси
Имя домена в иллюстрации не создаёт запись DNS. Даже после установки контроллера нужно связать публичное имя с реальным входом и проверить, что запрос приходит с нужным Host. Иначе корректное правило конкретного сайта может не совпасть с обращением, отправленным напрямую по IP.
Публичная схема влияет на поведение веб-приложения. Если TLS завершается на внешнем прокси, внутренний API может получать HTTP, хотя браузер использует HTTPS. Генерация ссылок, secure cookies и определение IP пользователя должны учитывать эту границу. Нельзя бездумно доверять любому пришедшему X-Forwarded-For: приложение должно знать доверенные прокси и правила обработки заголовков.
В нашем маленьком API нет входа пользователей, cookies или генерации абсолютных ссылок. Поэтому локальный HTTP подходит для текущего результата. Это ограничение обозначено конкретно: пример учит маршруту каталога, а не обеспечивает полный публичный веб-контур. Секреты конфигурации следующего урока тоже не превратят учебный endpoint в законченный сервис авторизации.
При будущем расследовании маршрута разделите три наблюдения. Получение HTML подтверждает вход к web. Успешный JSON каталога подтверждает переход к API. Корректный Host и сертификат относятся к внешнему входу. Если смешать эти проверки, легко принять временный локальный доступ за доказательство готовности публичного сайта.
После урока вам известна точная цепочка браузерного запроса и место контроллера в ней. Следующим шагом вынесем приветствие и учебный токен в ConfigMap и Secret, сохранив тот же HTTP-маршрут.