Перейти к основному содержимому

Ingress Controller и сетевой путь трафика в Kubernetes

Разработчику Архитектору Инженеру

Service и Ingress в Kubernetes

В Kubernetes каждый Pod получает свой IP. Этот адрес может измениться после пересоздания Pod, поэтому его не используют как постоянную точку интеграции.

Чтобы сервисы не зависели от "живых" адресов Pod, в кластере используют:

  • Service — стабильный виртуальный IP (ClusterIP) и DNS-имя для доступа внутри кластера;
  • Ingress — правила внешнего HTTP/HTTPS-доступа по host/path;
  • Ingress Controller — реальный компонент, который читает объект Ingress и применяет маршрутизацию.

Без установленного Ingress Controller ресурс Ingress сам по себе не проксирует трафик.

Подробнее:


Как Pod связывается с Service

Типовой поток внутри кластера:

  1. Вы создаете Service с selector, например app: backend.
  2. Kubernetes находит подходящие Pod и публикует их адреса в EndpointSlice (исторически — Endpoints).
  3. kube-proxy на каждой ноде получает изменения через API и обновляет правила в сетевом стеке ОС (iptables или IPVS).
  4. Клиентский Pod отправляет запрос на ClusterIP или DNS-имя сервиса.
  5. Ядро Linux на ноде применяет DNAT: виртуальный адрес сервиса подменяется на реальный IP одного из Pod-бэкендов.

Итог: приложение ходит на стабильное имя сервиса, а реальная балансировка по Pod происходит прозрачно.

Расшифровка терминов

  • ClusterIP — внутренний IP сервиса, который доступен только внутри кластера;
  • DNS-имя сервиса — имя вида my-backend-service.default.svc.cluster.local, по которому сервис находят другие Pod;
  • DNAT — подмена адреса назначения пакета, чтобы пакет дошел до конкретного Pod;
  • EndpointSlice — объект Kubernetes со списком "живых" Pod, которые готовы принимать трафик.

Мини схема сетевых объектов

Маршрут внутри Kubernetes удобно читать как цепочку:

  • Pod с клиентом отправляет запрос;
  • Service принимает запрос на свой ClusterIP;
  • EndpointSlice хранит список целевых Pod;
  • kube-proxy на ноде применяет правила и отправляет пакет в один из Pod сервиса.

Эта цепочка работает одинаково для HTTP, gRPC, Redis, PostgreSQL и других TCP-сервисов.


Пример манифеста Service (YAML)

apiVersion: v1
kind: Service
metadata:
name: my-backend-service
namespace: default
spec:
type: ClusterIP
selector:
app: my-web-app
ports:
- name: http
protocol: TCP
port: 80
targetPort: 8080

Что означает

  • kind: Service — сетевой объект доступа к группе Pod;
  • type: ClusterIP — доступ только внутри кластера;
  • selector — какие Pod включить в балансировку;
  • port — порт сервиса;
  • targetPort — порт контейнера в Pod.

Полезная команда для разбора конкретного сервиса:

kubectl describe svc my-backend-service

Команды, которые обычно запускают рядом:

kubectl get svc my-backend-service -o wide
kubectl get endpointslice -l kubernetes.io/service-name=my-backend-service
kubectl get pods -l app=my-web-app -o wide

Они показывают:

  • какой ClusterIP выдан сервису;
  • какие Pod попали в EndpointSlice;
  • на какие IP реально уйдет трафик.

Основные типы Service

Поле spec.type определяет модель доступа:

  1. ClusterIP (по умолчанию)
    Внутренний IP, доступ только внутри кластера.

  2. NodePort
    Открывает порт на каждой ноде (30000-32767) и проксирует внутрь на ClusterIP.

  3. LoadBalancer
    В облаке создает внешний балансировщик, который ведет трафик в кластер (обычно на NodePort/узлы).

  4. ExternalName
    Не проксирует трафик, а возвращает DNS CNAME на внешний адрес.

Подробный справочник типов


Входящий и исходящий трафик Pod

Egress из Pod во внешний мир

Когда Pod вызывает внешний API:

  • пакет выходит из сетевого namespace Pod на ноду;
  • нода обычно делает SNAT (подмена адреса источника на адрес ноды);
  • ответ возвращается обратно через ноду в Pod.

Термин SNAT означает подмену адреса источника. Внешний сервис видит адрес ноды, а не внутренний адрес Pod.

Ingress из внешнего мира в Pod

Типовой production-путь:

  1. Клиент приходит на внешний балансировщик (Service type: LoadBalancer у ingress-контроллера).
  2. Трафик попадает в Pod Ingress Controller.
  3. Контроллер читает Host и Path запроса.
  4. По правилам Ingress выбирается нужный Service.
  5. Запрос отправляется в один из Pod целевого сервиса.

Что именно проверяется в HTTP-запросе:

  • Host из заголовка;
  • путь URL, например /api или /shop;
  • порт и протокол;
  • TLS-сертификат, если используется HTTPS.

Для наглядности:

  • запрос https://app.example.com/api/users может уйти в backend-service;
  • запрос https://app.example.com/ может уйти в frontend-service.

Нужно ли приложениям в Pod обращаться к API Server

Для обычной бизнес-логики — нет.
Микросервисы обычно общаются друг с другом через Service (HTTP/gRPC), а не через Kubernetes API.

Когда обращение к API Server действительно нужно:

  • операторы и контроллеры (включая Ingress Controller);
  • CI/CD-агенты внутри кластера;
  • инфраструктурные компоненты, которым нужно читать состояние кластера.

Kubernetes подготавливает in-cluster доступ автоматически:

  • переменные среды KUBERNETES_SERVICE_HOST и KUBERNETES_SERVICE_PORT;
  • токен и CA сертификат в /var/run/secrets/kubernetes.io/serviceaccount/;
  • ограничения доступа через RBAC и ServiceAccount.

Расшифровка

  • RBAC — модель прав доступа в Kubernetes, определяет, что можно читать и изменять;
  • ServiceAccount — учетная запись Pod для обращения к API Kubernetes;
  • CA сертификат — файл для проверки, что Pod подключается к правильному API Server.

Официальные ссылки


Ingress Controller в архитектуре

Ingress — это декларация правил, а Ingress Controller — исполняющий компонент.

В контроллере обычно две части:

  • control plane: следит за изменениями Ingress, Service, Secret, EndpointSlice через API Server;
  • data plane: принимает реальный HTTP/HTTPS-трафик и проксирует его в кластер.

Что дает Ingress Controller:

  • маршрутизацию по доменам и путям;
  • TLS-терминацию;
  • L7-балансировку;
  • дополнительные политики (лимиты, redirect, CORS, auth и т.д. в зависимости от контроллера).

Термины

  • TLS-терминация — расшифровка HTTPS на входе в контроллер;
  • L7 — прикладной уровень, где важны Host, Path, заголовки и cookies;
  • Secret — объект Kubernetes для сертификатов и других чувствительных данных.

Какие контроллеры используют чаще всего

  • ingress-nginx для универсальных production-сценариев;
  • Traefik для динамической конфигурации и встроенных интеграций;
  • HAProxy Ingress для сценариев с очень высоким трафиком;
  • API gateway решения, когда нужен расширенный контроль авторизации и политик.

Пример Ingress для NGINX Ingress Controller

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app-ingress
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "20m"
spec:
ingressClassName: nginx
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-backend-service
port:
number: 80

Здесь ingressClassName: nginx явно говорит, что правила должен обработать класс nginx.

Рекомендуемый параметр в новых манифестах — ingressClassName.
Старая аннотация kubernetes.io/ingress.class встречается, но считается legacy-подходом.

Пример маршрутизации по нескольким путям

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-multi-route
spec:
ingressClassName: nginx
rules:
- host: app.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: backend-service
port:
number: 8080
- path: /
pathType: Prefix
backend:
service:
name: frontend-service
port:
number: 80

Как читать этот манифест:

  • все запросы на app.example.com/api... идут в backend-service;
  • остальные запросы идут в frontend-service;
  • приложение разделено на публичный фронтенд и отдельный API.

Подробнее по правилам:


Установка NGINX Ingress Controller через Helm

Стандартный путь установки:

helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update

helm install ingress-nginx ingress-nginx/ingress-nginx \
--namespace ingress-nginx \
--create-namespace

Что создается под капотом:

  • Deployment/Pod контроллера;
  • Service (часто LoadBalancer) как внешняя точка входа;
  • ServiceAccount, ClusterRole, ClusterRoleBinding для чтения нужных ресурсов API;
  • admission-компоненты (в зависимости от версии чарта и настроек).

Проверка:

kubectl get pods -n ingress-nginx
kubectl get svc -n ingress-nginx
kubectl get ingressclass

После установки можно применять собственные Ingress-манифесты.

Команды для диагностики установки:

kubectl describe ingressclass nginx
kubectl logs -n ingress-nginx -l app.kubernetes.io/component=controller --tail=200

Официальная документация:

Что происходит во время установки пошагово

  1. helm скачивает шаблоны чарта и рендерит YAML.
  2. kubectl-эквивалент отправляется в API Server.
  3. API Server сохраняет ресурсы в etcd.
  4. Scheduler назначает Pod контроллера на ноду.
  5. kubelet запускает контейнеры контроллера.
  6. Контроллер начинает смотреть Ingress, Service, Secret, EndpointSlice.
  7. Появляется внешний адрес сервиса контроллера.

После этого любые новые Ingress-объекты начинают применяться автоматически.

Обновление ingress-nginx

helm repo update
helm upgrade ingress-nginx ingress-nginx/ingress-nginx \
--namespace ingress-nginx

Перед обновлением полезно проверить:

  • версию Kubernetes в кластере;
  • совместимость версии чарта;
  • наличие backup значений helm get values ingress-nginx -n ingress-nginx.

Что такое kube-proxy и почему он на нодах

kube-proxy — сетевой агент Kubernetes, который работает как DaemonSet: по одному экземпляру на ноду, а не на Pod.

Почему не "на каждом Pod":

  • задача kube-proxy — настраивать сетевые правила уровня ноды в ядре ОС;
  • это системная функция маршрутизации/балансировки, общая для всех Pod на ноде;
  • запуск отдельного прокси в каждом Pod был бы избыточен и дорог по ресурсам.

Как он работает:

  1. Подписывается на Service и EndpointSlice через API Server.
  2. Обновляет правила iptables или таблицы IPVS.
  3. При обращении к ClusterIP пакет перехватывается и перенаправляется на реальный Pod-бэкенд.

Что важно помнить

  • kube-proxy работает на уровне L4, то есть на уровне TCP/UDP;
  • kube-proxy не анализирует HTTP host/path;
  • маршрутизацию по доменам и путям делает Ingress Controller на уровне L7.

Подробно

Режимы работы kube-proxy

kube-proxy может работать в нескольких режимах, на практике используют два:

  • iptables
    Правила создаются в таблицах фильтрации Linux. Режим простой и распространенный.
  • ipvs
    Используется подсистема IP Virtual Server в ядре Linux. Режим хорошо подходит для крупных кластеров и высокой нагрузки.

Выбор режима зависит от дистрибутива Kubernetes и настроек кластера.

Почему kube-proxy не виден приложению напрямую

Приложение в Pod обращается к Service по DNS имени или ClusterIP.
Дальше срабатывает сетевой стек ноды. В этой точке и работает kube-proxy.

Именно поэтому разработчик обычно не пишет в коде ничего про kube-proxy.


Как выглядит полный путь запроса

Пример: пользователь открывает https://app.example.com/api/orders.

  1. DNS указывает на внешний IP балансировщика.
  2. Балансировщик передает трафик в ingress-nginx.
  3. NGINX Ingress находит правило host/path и выбирает Service.
  4. Сервисная адресация приводит к одному из Pod-бэкендов.
  5. Ответ идет обратно тем же маршрутом к клиенту.

Внутри кластера сервисы продолжают вызывать друг друга через DNS сервисов (*.svc.cluster.local) без знания IP конкретных Pod.

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

  • внешняя линия входа через Ingress Controller;
  • внутренняя линия связи сервисов через Service и кластерный DNS.

Полный путь для внутреннего вызова между сервисами

Пример вызова frontend к backend:

  1. frontend отправляет запрос на http://backend-service.default.svc.cluster.local.
  2. Кластерный DNS возвращает ClusterIP сервиса.
  3. Пакет доходит до ноды и попадает в правила kube-proxy.
  4. Выбирается один живой Pod из EndpointSlice.
  5. Запрос обрабатывается приложением в Pod backend.

Полезные команды:

kubectl get svc backend-service
kubectl get endpointslice -l kubernetes.io/service-name=backend-service
kubectl exec -it deploy/frontend -- nslookup backend-service.default.svc.cluster.local

С их помощью легко проверить DNS и связность внутри кластера.


Разница между Ingress Controller, NodePort и LoadBalancer

  • NodePort — простой способ открыть сервис наружу, обычно для dev/тестов;
  • LoadBalancer — внешний L4-балансировщик для одного сервиса;
  • Ingress Controller — единая L7-точка входа для множества HTTP/HTTPS-сервисов по доменам и путям.

Типичный production-шаблон: один LoadBalancer перед Ingress Controller и десятки сервисов за ним.


Короткий практический чек-лист

  1. Установите Ingress Controller (например, ingress-nginx).
  2. Проверьте IngressClass и внешний адрес сервиса контроллера.
  3. Создайте Service типа ClusterIP для приложения.
  4. Создайте Ingress с ingressClassName, host, path.
  5. Проверьте маршрутизацию:
kubectl get ingress -A
kubectl describe ingress my-app-ingress
kubectl logs -n ingress-nginx -l app.kubernetes.io/component=controller --tail=200

Так вы проходите весь путь между Pod и Service внутри кластера и внешний доступ через Ingress Controller.


Практический стенд для новичка

Ниже минимальный набор объектов, который можно развернуть и проверить руками.

Шаг 1 деплой приложения

apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-web
spec:
replicas: 2
selector:
matchLabels:
app: demo-web
template:
metadata:
labels:
app: demo-web
spec:
containers:
- name: demo-web
image: hashicorp/http-echo:1.0.0
args:
- "-text=hello from demo-web"
ports:
- containerPort: 5678

Шаг 2 сервис для Pod

apiVersion: v1
kind: Service
metadata:
name: demo-web-service
spec:
selector:
app: demo-web
ports:
- port: 80
targetPort: 5678

Шаг 3 ingress для внешнего входа

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: demo-web-ingress
spec:
ingressClassName: nginx
rules:
- host: demo.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: demo-web-service
port:
number: 80

Команды проверки:

kubectl apply -f demo-deploy.yaml
kubectl apply -f demo-service.yaml
kubectl apply -f demo-ingress.yaml

kubectl get deploy,pods,svc,ingress
kubectl describe ingress demo-web-ingress

Для локального кластера можно добавить demo.local в hosts и проверить через браузер или curl.


TLS сертификаты и HTTPS

В production обычно нужен HTTPS. Базовый сценарий:

  • сертификат хранится в Secret типа kubernetes.io/tls;
  • Ingress ссылается на этот secret в секции tls;
  • Ingress Controller завершает TLS и передает HTTP во внутренние сервисы.

Пример секции tls:

spec:
tls:
- hosts:
- app.example.com
secretName: app-example-tls

Для автоматизации часто ставят cert-manager.

Полезные ссылки:


Отладка проблем с трафиком

Ingress создан, сайт не открывается

Проверяйте по порядку:

  • есть ли внешний адрес у сервиса ingress-nginx-controller;
  • совпадает ли host в Ingress и доменное имя запроса;
  • существует ли целевой Service;
  • есть ли у сервиса живые endpoints.

Команды:

kubectl get svc -n ingress-nginx
kubectl get ingress -A
kubectl describe ingress demo-web-ingress
kubectl get endpointslice -l kubernetes.io/service-name=demo-web-service

Service есть, но трафик не идет в Pod

Обычно причина в одном из пунктов:

  • в selector сервиса указана метка, которой нет у Pod;
  • targetPort не совпадает с портом контейнера;
  • Pod в статусе NotReady, поэтому не попадает в endpoints.

Команды:

kubectl get pods -l app=demo-web --show-labels
kubectl describe svc demo-web-service
kubectl describe pod POD_NAME

Ошибки 404 и 502 от NGINX Ingress

  • 404 часто означает, что не найдено правило по host/path;
  • 502 часто означает, что backend сервис найден, но целевой Pod недоступен.

Команда для чтения причин:

kubectl logs -n ingress-nginx -l app.kubernetes.io/component=controller --tail=300

Безопасность сетевого периметра

Базовые рекомендации:

  • хранить TLS-секреты в отдельном namespace и ограничивать доступ через RBAC;
  • закрывать доступ к сервисам без необходимости внешней публикации;
  • использовать NetworkPolicy, чтобы ограничить межсервисные соединения;
  • разделять публичные и внутренние сервисы по namespace;
  • включать логи ingress-контроллера и собирать метрики.

Официальная ссылка:


Частые ошибки новичков

  • Путают port и targetPort в Service.
  • Создают Ingress, но не устанавливают Ingress Controller.
  • Пишут host, который не резолвится в DNS.
  • Забывают ingressClassName и ожидают автоподхват в любом кластере.
  • Проверяют только kubectl get, без kubectl describe и логов.
  • Используют NodePort для production без дополнительных защитных слоев.

Полезные команды для ежедневной работы

kubectl get svc,ingress,endpointslice -A
kubectl describe svc SERVICE_NAME -n NAMESPACE
kubectl describe ingress INGRESS_NAME -n NAMESPACE
kubectl logs -n ingress-nginx -l app.kubernetes.io/component=controller --tail=200
kubectl get pods -n ingress-nginx -o wide
kubectl get events -A --sort-by=.metadata.creationTimestamp

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

Что изучать дальше в разделе


Содержание