Как обратиться к внешнему IP-адресу Load Balancer сервиса через Ingress-контроллер в Kubernetes

Ответ

Обращение происходит через единую точку входа — внешний IP или DNS-имя LoadBalancer-сервиса самого Ingress-контроллера. Внутри кластера Ingress-контроллер маршрутизирует трафик на соответствующие backend-сервисы на основе правил, описанных в ресурсах Ingress.

Типичная архитектура:

  1. Ingress-контроллер (например, ingress-nginx) развернут как Deployment.
  2. К этому Deployment'у привязан Service типа LoadBalancer.
  3. Облачный провайдер (AWS ELB, GCP Load Balancer, Azure LB) или MetalLB в on-prem среде назначают этому сервису внешний IP-адрес.
  4. Пользователь или DNS обращается к этому внешнему IP.
  5. Ingress-контроллер анализирует HTTP-запрос (Host header, путь) и направляет его на внутренний ClusterIP-сервис вашего приложения, указанный в правиле Ingress.

Пример манифестов:

Сервис Ingress-контроллера (LoadBalancer):

apiVersion: v1
kind: Service
metadata:
  name: ingress-nginx-controller
  namespace: ingress-nginx
spec:
  type: LoadBalancer
  ports:
    - name: http
      port: 80
      targetPort: 80
      protocol: TCP
    - name: https
      port: 443
      targetPort: 443
      protocol: TCP
  selector:
    app.kubernetes.io/name: ingress-nginx

Ресурс Ingress для приложения:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx # Указываем класс контроллера
  rules:
  - host: app.mycompany.com # Домен, по которому доступно приложение
    http:
      paths:
      - path: /api
        pathType: Prefix
        backend:
          service:
            name: backend-api-service # Внутренний сервис приложения
            port:
              number: 8080
      - path: /
        pathType: Prefix
        backend:
          service:
            name: frontend-web-service
            port:
              number: 80

Как это работает на практике:

  1. После применения манифестов получаем внешний IP:
    kubectl get svc -n ingress-nginx ingress-nginx-controller
    # NAME                         TYPE           CLUSTER-IP     EXTERNAL-IP      PORT(S)
    # ingress-nginx-controller   LoadBalancer   10.96.45.211   203.0.113.100   80:32678/TCP,443:31484/TCP
  2. Настраиваем DNS-запись app.mycompany.com, указывающую на IP 203.0.113.100.
  3. Запрос http://app.mycompany.com/api/users попадает на IP 203.0.113.100:80, его принимает ingress-nginx.
  4. Контроллер, видя Host app.mycompany.com и путь /api, перенаправляет запрос на порт 8080 внутреннего сервиса backend-api-service.

Важно: Для HTTPS необходимо настроить TLS-терминацию на Ingress-контроллере, указав секрет с сертификатом в спецификации Ingress (tls секция).

Ответ 18+ 🔞

Давай разберём эту схему, а то с первого взгляда выглядит как ёперный театр. Представь, что у тебя есть кластер — это типа охраняемый посёлок, куда просто так не зайдёшь. А твоё приложение — это хата внутри этого посёлка. Как к нему попасть извне? Вот тут и появляется наш главный по тарелкам — Ingress-контроллер.

Этот контроллер — он как швейцар в дорогом отеле, только вместо ливреи у него под капотом nginx или какой-нибудь другой движок. Разворачивается он внутри кластера как обычный Deployment, но у него есть особая фишка — к нему прикручен Service типа LoadBalancer.

И вот тут начинается магия, блядь. Когда ты накатываешь этот сервис, твой облачный провайдер (AWS, GCP, Azure) или, если ты на своём железе, MetalLB — видят его и говорят: «О, чуваку нужна точка входа!». И выдают ему внешний IP-адрес. Это типа номер телефона твоего швейцара, по которому ему можно позвонить с улицы.

Вот как вся эта карусель крутится:

  1. У швейцара (Ingress-контроллера) появляется этот самый внешний IP.
  2. Ты настраиваешь DNS, чтобы твой домен app.mycompany.com вёл на этот IP. Типа прописываешь номер швейцара в телефонной книге.
  3. Пользователь стучится по адресу http://app.mycompany.com/api/users.
  4. Запрос прилетает на внешний IP, его ловит наш швейцар-контроллер.
  5. А этот швейцар — хитрая жопа. У него есть инструкция (ресурс Ingress), где расписано: «Если пришёл гость с визиткой app.mycompany.com и путь у него начинается на /api — веди его в коридор номер 8080 к службе backend-api-service. Если же путь просто / — тогда это в другую комнату, к frontend-web-service на порт 80».
  6. И контроллер маршрутизирует трафик внутрь кластера на нужный внутренний сервис приложения. Всё, довольный пользователь получил ответ.

А теперь смотри на примеры, чтобы вообще ни хуя не осталось непонятного.

Вот манифест сервиса для самого контроллера. Это и есть его «номер телефона» типа LoadBalancer:

apiVersion: v1
kind: Service
metadata:
  name: ingress-nginx-controller
  namespace: ingress-nginx
spec:
  type: LoadBalancer # Вот эта приписка заставляет облако выдать внешний IP
  ports:
    - name: http
      port: 80
      targetPort: 80
      protocol: TCP
    - name: https
      port: 443
      targetPort: 443
      protocol: TCP
  selector:
    app.kubernetes.io/name: ingress-nginx

А вот сама инструкция для швейцара — ресурс Ingress для твоего приложения. Здесь чётко сказано, куда кого пускать:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx # Говорим, что эту инструкцию читает именно nginx-швейцар
  rules:
  - host: app.mycompany.com # Если гость представился этим именем...
    http:
      paths:
      - path: /api # ...и путь у него /api
        pathType: Prefix
        backend:
          service:
            name: backend-api-service # ...то веди его сюда
            port:
              number: 8080
      - path: / # А если путь просто корень
        pathType: Prefix
        backend:
          service:
            name: frontend-web-service # ...то веди его уже сюда
            port:
              number: 80

Как это выглядит на практике? Очень просто.

  1. После деплоя смотришь, какой IP выдали:

    kubectl get svc -n ingress-nginx ingress-nginx-controller
    # NAME                         TYPE           CLUSTER-IP     EXTERNAL-IP      PORT(S)
    # ingress-nginx-controller   LoadBalancer   10.96.45.211   203.0.113.100   80:32678/TCP,443:31484/TCP

    Видишь этот EXTERNAL-IP? 203.0.113.100? Вот он, звездец! Это и есть твоя дверь в кластер.

  2. Наводишь DNS на этот IP.

  3. Всё, работает. Запрос летит по цепочке: Пользователь -> DNS -> Внешний IP (203.0.113.100) -> Ingress-контроллер -> Внутренний сервис приложения.

Важный момент на посошок: Если хочешь HTTPS (а ты хочешь, иначе пидарас шерстяной), то нужно настроить TLS. Делается это прямо в ресурсе Ingress, в секции tls, где указываешь секрет с твоим сертификатом. Контроллер сам разгрузит SSL, и внутрь кластера пойдёт уже обычный HTTP-трафик. Без этой настройки будет у тебя не шифрованное соединение, а просто пизда рулю.