NodePort vs. LoadBalancer vs. Ingress: Выбор оптимального способа публикации сервисов

Разберитесь в критическом выборе способов внешнего доступа к сервисам Kubernetes, сравнив NodePort, LoadBalancer и Ingress. Это руководство подробно описывает архитектуру, уровень работы (L4 vs. L7), сценарии использования, а также ключевые различия в стоимости и сложности каждого метода. Узнайте, когда использовать простой NodePort для тестирования, выделенный LoadBalancer для отдельных сервисов или мощный Ingress для централизованной, экономичной маршрутизации на уровне L7 и сложных сред с несколькими сервисами.

NodePort vs. LoadBalancer vs. Ingress: Выбор оптимального способа публикации сервисов

Kubernetes присваивает Pod'ам временные IP-адреса, а затем использует сервисы (Services) для обеспечения стабильного доступа к ним. Внутри кластера часто достаточно обычного сервиса ClusterIP. Вопрос становится более интересным, когда необходимо подключиться извне кластера.

Три наиболее часто упоминаемых варианта: NodePort, LoadBalancer и Ingress. Они связаны, но не взаимозаменяемы. NodePort открывает порт на каждом узле. LoadBalancer запрашивает у провайдера инфраструктуры внешний балансировщик нагрузки. Ingress определяет правила маршрутизации HTTP и требует контроллер Ingress для реализации этих правил.


1. Тип публикации сервиса: NodePort

Тип сервиса NodePort — это самый простой и примитивный способ публикации сервиса извне. Когда вы определяете сервис как NodePort, Kubernetes открывает определенный статический порт на каждом узле кластера. Любой трафик, направленный на этот порт на любом узле, маршрутизируется непосредственно к сервису.

Как работает NodePort

  1. Автоматически выбирается случайный порт в заданном диапазоне (по умолчанию: 30000-32767).
  2. Этот порт открывается на всех узлах кластера.
  3. Сервис прослушивает этот NodePort, перенаправляя трафик на соответствующие Pod'ы.

Для доступа к приложению используется http://<IP_узла>:<NodePort>.

Сценарии использования и ограничения

Особенность Описание
Сценарий использования Разработка, тестовые среды или случаи, когда внешняя балансировка нагрузки обрабатывается внешним, не облачным устройством.
Сложность Очень низкая.
Стоимость Нулевая (если не учитывать стоимость базовых виртуальных машин).
Ограничение Требует ручного управления внешними правилами брандмауэра. IP-адреса узлов часто динамические. Ограничение диапазона портов (30000-32767).

Пример NodePort

apiVersion: v1
kind: Service
metadata:
  name: my-app-nodeport
spec:
  type: NodePort
  selector:
    app: my-web-app
  ports:
    - port: 80
      targetPort: 8080
      # Опционально: указать NodePort, иначе будет выбран автоматически
      # nodePort: 30001 

Предупреждение: NodePort публикует сервис через IP-адреса узлов и высокий порт. Он может быть полезен за вашим собственным внешним балансировщиком нагрузки, особенно на bare-metal, но неудобен в качестве публичного интерфейса для production веб-приложения.


2. Тип публикации сервиса: LoadBalancer

Тип сервиса LoadBalancer — это стандартный метод публикации приложений в публичный интернет в облачных средах (AWS EKS, GCP GKE, Azure AKS).

Когда сервис определен как LoadBalancer, Kubernetes запрашивает у интеграции балансировщика нагрузки кластера предоставление внешнего балансировщика нагрузки. В управляемых облачных кластерах это часто означает облачный L4 балансировщик нагрузки. В bare-metal кластерах это может означать такой проект, как MetalLB или другую локальную интеграцию. Результатом обычно является стабильный внешний адрес, который перенаправляет трафик к сервису.

Интеграция с облачным провайдером

Ключевым отличием LoadBalancer является глубокая интеграция с базовой облачной инфраструктурой. Облачный провайдер управляет жизненным циклом балансировщика нагрузки, проверками работоспособности и маршрутизацией.

Сценарии использования и стоимость

Особенность Описание
Сценарий использования Простые публичные приложения, требующие выделенного стабильного IP-адреса. Подходит для протоколов, отличных от HTTP/S (TCP/UDP).
Сложность Низкая (с точки зрения конфигурации).
Стоимость Часто выше в облачных средах, так как каждый сервис может создавать отдельный ресурс балансировщика нагрузки.
Преимущество Обеспечивает немедленную высокую доступность и автоматические проверки работоспособности.

Пример LoadBalancer

apiVersion: v1
kind: Service
metadata:
  name: my-app-loadbalancer
spec:
  type: LoadBalancer
  selector:
    app: my-api-service
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080

После создания кластер назначит внешний IP-адрес (видимый в статусе сервиса), управляемый облачным провайдером.


3. Kubernetes Ingress: Маршрутизация на уровне L7

Ingress принципиально отличается от NodePort и LoadBalancer. Ingress — это не тип сервиса, а объект API, который определяет правила внешнего доступа, обычно HTTP и HTTPS (уровень 7).

Ingress действует как центральная точка входа, позволяя осуществлять сложную маршрутизацию на основе имен хостов и путей URL. Этот подход необходим для управления несколькими сервисами за одним IP-адресом.

Роль контроллера Ingress

Чтобы правила Ingress работали, необходимо сначала развернуть контроллер Ingress, такой как ingress-nginx, Traefik, HAProxy или контроллер облачного провайдера. Сервисные сетки, такие как Istio, также могут обеспечивать управление трафиком типа gateway, но это не то же самое, что базовый API Ingress Kubernetes.

Сам контроллер Ingress обычно публикуется с помощью одного сервиса LoadBalancer или NodePort.

Расширенные возможности Ingress

Ingress проявляет себя наилучшим образом, когда требуются расширенные функции управления трафиком:

  1. Оптимизация затрат: Используйте один облачный балансировщик нагрузки (для публикации контроллера) вместо одного балансировщика на каждый сервис приложения.
  2. Виртуальный хостинг: Маршрутизация трафика на основе имен хостов (api.example.com направляется к сервису A; www.example.com — к сервису B).
  3. Маршрутизация на основе пути: Маршрутизация трафика на основе путей URL (/v1/users направляется к сервису A; /v2/posts — к сервису B).
  4. Терминация SSL/TLS: Централизованное управление сертификатами и их расшифровка.

Пример ресурса Ingress

Этот пример направляет трафик для api.example.com/v1 к сервису my-api-v1.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: example-ingress
spec:
  ingressClassName: nginx # Укажите используемый контроллер
  rules:
  - host: api.example.com
    http:
      paths:
      - path: /v1
        pathType: Prefix
        backend:
          service:
            name: my-api-v1
            port:
              number: 80
  # ... другие правила для разных сервисов/хостов

4. Сравнение и руководство по выбору

Выбор оптимального метода включает оценку таких факторов, как среда, сложность, набор функций и эксплуатационные расходы.

Таблица сравнения функций

Особенность NodePort LoadBalancer Ingress
Уровень L4 (TCP/UDP) L4 (TCP/UDP) L7 (HTTP/S)
Стабильность (IP) Нестабильный (использует IP узла) Стабильный (выделенный облачный IP) Стабильный (использует IP контроллера)
Стоимость Низкая (высокие эксплуатационные расходы) Высокая (стоимость ресурса на сервис) Умеренная (один балансировщик для контроллера)
Логика маршрутизации Простая пересылка портов Простая пересылка портов Имя хоста, путь, терминация SSL
Зависимость от облака Нет Зависит от интеграции с провайдером Зависит от контроллера и метода публикации
Готовность к production Иногда, обычно за другим балансировщиком Да для простого L4 доступа Да для маршрутизации HTTP/S

Критерии принятия решения: выбор метода публикации

  1. Только для внутреннего использования или тестирования: Если вам нужно просто проверить связность внутри кластера или вы управляете внешними сетевыми настройками самостоятельно (например, в среде bare-metal), используйте NodePort.

  2. Для простого выделенного L4 доступа: Если ваше приложение использует протоколы, отличные от HTTP (например, пользовательские протоколы TCP или UDP), или у вас есть только одно публичное приложение, которому требуется немедленный выделенный L4 доступ, используйте LoadBalancer.

  3. Для сложного L7 доступа с несколькими сервисами: Если у вас есть несколько сервисов для публикации, требуется маршрутизация на основе пути или имени хоста, необходима централизованная терминация SSL или вы хотите минимизировать облачные расходы, используя один внешний IP, используйте Ingress.

Для многих production HTTP/S приложений Ingress является обычным выбором, поскольку он централизует сертификаты и маршрутизацию. Для баз данных, брокеров сообщений, игровых серверов, сырых TCP-сервисов или всего, что не является HTTP, сервис LoadBalancer может быть более понятным. Для bare-metal кластеров NodePort все еще может быть частью архитектуры, но обычно он размещается за соответствующим внешним балансировщиком нагрузки или правилом брандмауэра.

Как они сочетаются в реальных кластерах

Один из запутанных моментов заключается в том, что эти варианты могут накладываться друг на друга. Объект Ingress сам по себе не публикует пакеты. Контроллер получает трафик каким-то образом, и этим "каким-то образом" часто является сервис LoadBalancer в облачном кластере:

Интернет
  -> Облачный балансировщик нагрузки
  -> Сервис типа LoadBalancer для ingress-nginx
  -> Pod'ы контроллера Ingress
  -> Правило Ingress
  -> Сервис ClusterIP
  -> Pod'ы приложения

На bare-metal путь может использовать NodePort:

Интернет или офисная сеть
  -> Внешний балансировщик нагрузки / брандмауэр
  -> IP_узла:NodePort
  -> Pod'ы контроллера Ingress
  -> Сервис приложения

Вот почему говорить "используйте Ingress вместо LoadBalancer" немного неточно. Ingress часто все еще использует балансировщик нагрузки, но позволяет многим HTTP-приложениям использовать одну точку входа.

Практические примеры

Используйте NodePort, когда вы отлаживаете лабораторный кластер, временно публикуете сервис в частной сети или интегрируетесь с уже управляемым вами оборудованием балансировки нагрузки. Не заставляйте пользователей запоминать https://app.example.com:31427, если это действительно не внутренний инструмент.

Используйте LoadBalancer, когда одному сервису нужен стабильный внешний адрес и достаточно L4 пересылки. Публичный TCP API, UDP-сервис или одна внутренняя административная конечная точка могут быть проще таким образом. Это также полезно, когда протокол приложения не вписывается в обычную маршрутизацию HTTP по хосту/пути.

Используйте Ingress, когда у вас есть веб-приложения. Если api.example.com, docs.example.com и app.example.com находятся в одном кластере, Ingress дает вам одно место для управления маршрутизацией хостов и TLS. Добавьте cert-manager, и обновление сертификатов может стать обычным рабочим процессом кластера вместо ручной задачи на сервере.

Вопросы безопасности и эксплуатации

Объект публикации — это только одна часть решения для production. Вам также нужно знать, кто может получить доступ к конечной точке, где происходит терминация TLS, как сохраняются исходные IP-адреса и как отслеживаются сбои.

С NodePort тщательно проверяйте правила брандмауэра. Kubernetes может открыть порт на каждом узле, но ваша сеть все равно решает, может ли внешний мир получить к нему доступ. В облачных средах группы безопасности или правила брандмауэра часто должны разрешать диапазон NodePort. На bare-metal та же проблема может быть в периметральном брандмауэре. Если вы предполагаете, что частный инструмент администрирования должен быть доступен только через VPN, обеспечьте это как вне Kubernetes, так и внутри него.

С LoadBalancer изучите аннотации, специфичные для провайдера. Они часто контролируют, является ли балансировщик нагрузки внутренним или доступным из интернета, какой протокол он использует, какой путь проверки работоспособности он проверяет и сохраняет ли он исходный IP-адрес клиента. Эти детали различаются у разных провайдеров, поэтому не предполагайте, что манифест, скопированный из одного облака, будет вести себя так же в другом.

С Ingress центр эксплуатации перемещается к контроллеру. Вам нужны журналы и метрики от Pod'ов контроллера, а не только от Pod'ов приложения. Если маршрут не работает, сервис и Pod'ы могут быть работоспособны, в то время как контроллер отклонил правило, использовал неправильный ingress class, пропустил секрет TLS или направил на неправильный путь бэкенда. Быстрый контрольный список поможет:

kubectl get ingress
kubectl describe ingress example-ingress
kubectl get svc -n ingress-nginx
kubectl logs -n ingress-nginx deploy/ingress-nginx-controller

Также будьте внимательны к TLS. Ingress обычно завершает HTTPS на контроллере и отправляет HTTP на бэкенд-сервис. Это нормально для многих внутренних кластеров, но некоторые команды требуют шифрования на всем пути до Pod'а приложения. Если это ваше требование, настройте TLS бэкенда намеренно, а не предполагайте, что Ingress предоставляет его автоматически.

Типичные сценарии отказов

Если NodePort работает с одного узла, но не с другого, проверьте, работоспособны ли kube-proxy или CNI кластера на проблемном узле. Также проверьте, разрешает ли внешний брандмауэр трафик на все IP-адреса узлов, которые вы планируете использовать.

Если сервис LoadBalancer остается в состоянии Pending, кластер, вероятно, не может предоставить внешний балансировщик нагрузки. В управляемом Kubernetes это может означать отсутствие интеграции облачного контроллера, разрешений, тегов подсетей, квот или настроек, специфичных для провайдера. В bare-metal Kubernetes это обычно означает, что не установлена реализация балансировщика нагрузки.

Если Ingress возвращает страницу бэкенда по умолчанию или 404 от контроллера, запрос достиг контроллера, но не совпал с вашим правилом хоста или пути. Проверьте DNS, заголовок Host, ingressClassName, тип пути, а также правильность имени сервиса и порта. Если вы получаете сертификат TLS для неправильного имени хоста, проверьте секрет, на который ссылается Ingress, и не претендует ли другое правило Ingress на тот же хост.

Простой ярлык для принятия решения

Начните с протокола. Если это HTTP или HTTPS и более одного приложения могут в конечном итоге использовать одну точку входа, используйте Ingress. Если это сырой TCP или UDP и нужен стабильный внешний адрес, используйте LoadBalancer. Если вы тестируете, интегрируетесь с собственным сетевым оборудованием или строите bare-metal путь, NodePort может быть частью ответа.

Затем проверьте операционную модель. Небольшая команда, управляющая одним публичным API, может предпочесть один LoadBalancer, потому что это очевидно и легко отлаживать. Команда платформы, размещающая десятки веб-сервисов, обычно предпочитает Ingress, потому что общая маршрутизация, сертификаты и политики важнее, чем дополнительный уровень контроллера.

Заключительные замечания

Выбирайте на основе протокола и операций, а не на основе того, какой объект звучит более продвинуто. NodePort — это строительный блок. LoadBalancer — это простой внешний L4 доступ. Ingress — это маршрутизация HTTP/S через контроллер. В небольшом кластере все три могут присутствовать в одной архитектуре, и это нормально, если у каждого есть четкая задача.