Для реализации ALB средствами NGINX Ingress controller используется модуль ingress-nginx.

Модуль ingress-nginx устанавливает NGINX Ingress controller и управляет им с помощью кастомных ресурсов. Если узлов для размещения Ingress-контроллера больше одного, он устанавливается в отказоустойчивом режиме, с учётом особенностей инфраструктуры как облачных, так и bare-metal сред, а также различных типов Kubernetes-кластеров.

Поддерживается одновременный запуск нескольких экземпляров Ingress-контроллеров с независимой конфигурацией: одного основного и произвольного количества дополнительных. Это, например, позволяет разделять внешние и внутренние (intranet) Ingress-ресурсы приложений.

Варианты терминации трафика

Трафик к ingress-nginx может быть отправлен несколькими способами:

  • напрямую, без использования внешнего балансировщика;
  • через внешний LoadBalancer, в том числе поддерживаются:
    • Qrator,
    • Cloudflare,
    • AWS LB,
    • GCE LB,
    • ACS LB,
    • Yandex LB,
    • OpenStack LB.

Терминация HTTPS

Для каждого экземпляра NGINX Ingress Controller можно настраивать политики безопасности HTTPS, включая:

  • параметры HSTS;
  • набор доступных версий SSL/TLS и протоколов шифрования.

Также модуль интегрирован с модулем cert-manager, при взаимодействии с которым возможны автоматический заказ SSL-сертификатов и их дальнейшее использование Ingress-контроллерами.

Мониторинг и статистика

В этой реализации ingress-nginx добавлена система сбора статистики в Prometheus с множеством метрик:

  • по длительности времени всего ответа и апстрима отдельно;
  • кодам ответа;
  • количеству повторов запросов (retry);
  • размерам запроса и ответа;
  • методам запросов;
  • типам content-type;
  • географии распределения запросов и т. д.

Данные представлены в нескольких разрезах:

  • namespace;
  • vhost;
  • ingress-ресурсы;
  • location (в nginx).

Все графики сгруппированы в дашборды Grafana. Реализована возможность drill-down: например, при просмотре статистики по namespace можно перейти по ссылке на соответствующий дашборд и получить детализированные данные по vhosts в этом namespace — и далее по иерархии.

Статистика

Основные принципы сбора статистики

  1. На стадии log_by_lua_block для каждого запроса вызывается модуль, который рассчитывает необходимые данные и складывает их в буфер (у каждого NGINX worker свой буфер).
  2. На стадии init_by_lua_block для каждого NGINX worker запускается процесс, который раз в секунду асинхронно отправляет данные в формате protobuf через TCP socket в protobuf_exporter (разработка Deckhouse Kubernetes Platform).
  3. protobuf_exporter запускается sidecar-контейнером в поде с ingress-controller, принимает сообщения в формате protobuf, разбирает, агрегирует их по установленным нами правилам и экспортирует в формате для Prometheus.
  4. Prometheus каждые 30 секунд собирает метрики как в ingress-controller (там есть небольшое количество нужных метрик), так и protobuf_exporter. На основе этих данных строится статистика.

Состав и представление метрик

У всех собираемых метрик есть служебные лейблы, идентифицирующие экземпляр контроллера: controller, app, instance и endpoint (они видны в /prometheus/targets).

  • Все метрики (кроме geo), экспортируемые через protobuf_exporter, представлены в трех уровнях детализации:
    • ingress_nginx_overall_* — агрегированные метрики верхнего уровня (без детализации, у всех метрик есть лейблы namespace, vhost и content_kind);
    • ingress_nginx_detail_* — кроме лейблов уровня overall, добавляются ingress, service, service_port и location;
    • ingress_nginx_detail_backend_* — ограниченная часть данных, собирается в разрезе по бэкендам. У этих метрик, кроме лейблов уровня detail, добавляется лейбл pod_ip.
  • Для уровней overall и detail собираются следующие метрики:
    • *_requests_total — общее количества запросов (дополнительные лейблы — scheme, method);
    • *_responses_total — количество ответов (дополнительный лейбл — status);
    • *_request_seconds_{sum,count,bucket} — гистограмма времени ответа;
    • *_bytes_received_{sum,count,bucket} — гистограмма размера запроса;
    • *_bytes_sent_{sum,count,bucket} — гистограмма размера ответа;
    • *_upstream_response_seconds_{sum,count,bucket} — гистограмма времени ответа upstream-сервиса (при нескольких upstream’ах — суммарное время);
    • *_lowres_upstream_response_seconds_{sum,count,bucket} — упрощённая гистограмма (для визуализации; не подходит для расчета квантилей);
    • *_upstream_retries_{count,sum} — количество и суммарное число повторных запросов (retry) к бэкенду.
  • Для уровня overall собираются следующие метрики:
    • *_geohash_total — количество запросов по geohash (дополнительные лейблы — geohash, place).
  • Для уровня detail_backend собираются следующие метрики:
    • *_lowres_upstream_response_seconds — упрощённая гистограмма времени ответа для overall и detail;
    • *_responses_total — количество ответов (дополнительный лейбл — status_class, а не просто status);
    • *_upstream_bytes_received_sum — суммарный объём данных, полученных от бэкендов.

Примеры настройки балансировки

Для настройки балансировки используйте кастомный ресурс IngressNginxController.

Пример для AWS (Network Load Balancer)

При создании балансировщика используются все доступные в кластере зоны.

В каждой зоне балансировщик получает собственный публичный IP. Если в зоне есть экземпляр с Ingress-контроллером, A-запись с IP-адресом балансировщика из этой зоны автоматически добавляется к доменному имени балансировщика.

Если в зоне не остается экземпляров с Ingress-контроллером, тогда IP автоматически убирается из DNS.

В том случае, если в зоне всего один экземпляр с Ingress-контроллером, при перезапуске пода IP-адрес балансировщика этой зоны временно исключается из DNS.

apiVersion: deckhouse.io/v1
kind: IngressNginxController
metadata:
 name: main
spec:
  ingressClass: nginx
  inlet: LoadBalancer
  loadBalancer:
    annotations:
      service.beta.kubernetes.io/aws-load-balancer-type: "nlb"

Пример для GCP / Yandex Cloud / Azure

apiVersion: deckhouse.io/v1
kind: IngressNginxController
metadata:
 name: main
spec:
  ingressClass: nginx
  inlet: LoadBalancer

В GCP на узлах необходимо указать аннотацию, которая разрешает принимать подключения на внешние адреса для сервисов с типом NodePort.

Пример для OpenStack

apiVersion: deckhouse.io/v1
kind: IngressNginxController
metadata:
  name: main-lbwpp
spec:
  inlet: LoadBalancerWithProxyProtocol
  ingressClass: nginx
  loadBalancerWithProxyProtocol:
    annotations:
      loadbalancer.openstack.org/proxy-protocol: "true"
      loadbalancer.openstack.org/timeout-member-connect: "2000"

Пример для bare metal

apiVersion: deckhouse.io/v1
kind: IngressNginxController
metadata:
  name: main
spec:
  ingressClass: nginx
  inlet: HostWithFailover
  nodeSelector:
    node-role.deckhouse.io/frontend: ""
  tolerations:
  - effect: NoExecute
    key: dedicated.deckhouse.io
    value: frontend

Пример для bare metal при использовании внешнего балансировщика

Пример подходит при использовании Cloudflare, Qrator, Nginx+, Citrix ADC, Kemp и других внешних балансировщиков.

apiVersion: deckhouse.io/v1
kind: IngressNginxController
metadata:
  name: main
spec:
  ingressClass: nginx
  inlet: HostPort
  hostPort:
    httpPort: 80
    httpsPort: 443
    behindL7Proxy: true

Пример для bare metal (MetalLB в режиме BGP LoadBalancer)

Доступно только в DKP Enterprise Edition.

apiVersion: deckhouse.io/v1
kind: IngressNginxController
metadata:
  name: main
spec:
  ingressClass: nginx
  inlet: LoadBalancer
  nodeSelector:
    node-role.deckhouse.io/frontend: ""
  tolerations:
  - effect: NoExecute
    key: dedicated.deckhouse.io
    value: frontend

В случае использования MetalLB его speaker-поды должны быть запущены на тех же узлах, что и поды Ingress–контроллера.

Чтобы Ingress-контроллер получал реальные IP-адреса клиентов, его сервис должен быть создан с параметром externalTrafficPolicy: Local, исключающим межузловой SNAT. Для соблюдения этого условия MetalLB speaker анонсирует этот Service только с тех узлов, где запущены целевые поды.

Таким образом, для данного примера конфигурация модуля metallb должна быть такой:

metallb:
 speaker:
   nodeSelector:
     node-role.deckhouse.io/frontend: ""
   tolerations:
    - effect: NoExecute
      key: dedicated.deckhouse.io
      value: frontend

Пример для bare metal (балансировщик MetalLB в режиме L2 LoadBalancer)

Доступно только в Enterprise Edition.

  1. Включите модуль metallb:

    apiVersion: deckhouse.io/v1alpha1
    kind: ModuleConfig
    metadata:
      name: metallb
    spec:
      enabled: true
      version: 2
    
  2. Создайте ресурс MetalLoadBalancerClass:

    apiVersion: network.deckhouse.io/v1alpha1
    kind: MetalLoadBalancerClass
    metadata:
      name: ingress
    spec:
      addressPool:
        - 192.168.2.100-192.168.2.150
      isDefault: false
      nodeSelector:
        node-role.kubernetes.io/loadbalancer: "" # Cелектор узлов-балансировщиков.
      type: L2
    
  3. Создайте ресурс IngressNginxController:

    apiVersion: deckhouse.io/v1
    kind: IngressNginxController
    metadata:
      name: main
    spec:
      ingressClass: nginx
      inlet: LoadBalancer
      loadBalancer:
        loadBalancerClass: ingress
        annotations:
          # Количество адресов, которые будут выделены из пула, описанного в MetalLoadBalancerClass.
          network.deckhouse.io/l2-load-balancer-external-ips-count: "3"
    

Платформа создаст сервис с типом LoadBalancer, которому будет присвоено заданное количество адресов:

d8 k -n d8-ingress-nginx get svc

Пример вывода:

NAME                   TYPE           CLUSTER-IP      EXTERNAL-IP                                 PORT(S)                      AGE
main-load-balancer     LoadBalancer   10.222.130.11   192.168.2.100,192.168.2.101,192.168.2.102   80:30689/TCP,443:30668/TCP   11s