Стадия жизненного цикла модуля: General Availability

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

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

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

Если в зоне не остается instance с 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)

Доступно в следующих редакциях: EE, CSE Pro (1.67).

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–контроллера.

Контроллер должен получать реальные IP-адреса клиентов — поэтому его Service создается с параметром 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)

Доступно в следующих редакциях: SE, SE+, EE, CSE Lite (1.67), CSE Pro (1.67).

  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: "" # селектор узлов-балансировщиков
      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"
      # Селектор и tolerations. Поды ingress-controller должны быть размещены на тех же узлах, что и поды MetalLB speaker.
      nodeSelector:
         node-role.kubernetes.io/loadbalancer: ""
      tolerations:
      - effect: NoSchedule
        key: node-role/loadbalancer
        operator: Exists
    
  4. Платформа создаст сервис с типом 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
    

Пример разделения доступа между публичной и административной зонами

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

  • https://example.com — публичная зона;
  • https://admin.example.com — административная зона, к которой доступ должен быть ограничен (ACL, mTLS, IP whitelist и т.д.).

При таком сценарии рекомендуем выносить административный трафик в отдельный Ingress-контроллер (при необходимости с отдельным Ingress-классом) и ограничивать доступ к нему с помощью параметра spec.acceptRequestsFrom.

Особенности использования одного Ingress-контроллера

Рассмотрим пример, когда для обслуживания запросов из публичной зоны и административного интерфейса используется один Ingress-контроллер.

Пример конфигурации Ingress-ресурсов для такого случая:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: admin-ingress
  annotations:
    nginx.ingress.kubernetes.io/whitelist-source-range: "1.2.3.4/32"
spec:
  ingressClassName: nginx # Ingress-ресурс для административного трафика связан с тем же Ingress-контроллером, что и Ingress-ресурс для публичного трафика.
  rules:
    - host: admin.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: backend
                port:
                  number: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: public-ingress
spec:
  ingressClassName: nginx # Ingress-ресурс для публичного трафика связан с тем же Ingress-контроллером, что и Ingress-ресурс для административного трафика.
  rules:
    - host: example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: backend
                port:
                  number: 80

При включенной обработке и передаче заголовков X-Forwarded-* бэкенд может опираться на заголовок x-forwarded-host при принятии решений об авторизации. И для приведенного выше примера возможна ситуация, когда через Ingress-ресурс для обслуживания публичного трафика можно подключиться к административной зоне, используя x-forwarded-host. Поэтому при использовании этой опции вы должны быть уверены, что запросы к Ingress-контроллеру направляются только от доверенных источников.

Использование раздельных Ingress-контроллеров

Чтобы избежать ситуации, описанной выше (когда при включенной обработке и передаче заголовков X-Forwarded-* можно, например, через Ingress-ресурс для обслуживания публичного трафика подключиться к административной зоне, используя x-forwarded-host), рекомендуем:

  • настроить правила доступа на уровне Ingress-ресурсов,
  • использовать разные Ingress-контроллеры,
  • на Ingress-контроллерах ограничить, с каких адресов можно подключаться к ним.

Пример конфигурации Ingress-ресурсов для такого случая:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: admin-ingress
  annotations:
    nginx.ingress.kubernetes.io/whitelist-source-range: "1.2.3.4/32"
spec:
  ingressClassName: admin-nginx # Ingress-ресурс для административного трафика связан с отдельным Ingress-контроллером.
  rules:
    - host: admin.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: backend
                port:
                  number: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: public-ingress
spec:
  ingressClassName: public-nginx # Ingress-ресурс для публичного трафика связан связан с отдельным Ingress-контроллером.
  rules:
    - host: example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: backend
                port:
                  number: 80

Пример Ingress-контроллера, который обслуживает административные Ingress-ресурсы и принимает подключения только из заданных подсетей:

apiVersion: deckhouse.io/v1
kind: IngressNginxController
metadata:
  name: admin
spec:
  ingressClass: admin-nginx
  inlet: HostPort
  acceptRequestsFrom:
    - 1.2.3.4/32
    - 10.0.0.0/16
  hostPort:
    httpPort: 80
    httpsPort: 443
    behindL7Proxy: true

В этом примере:

  • Ingress-контроллер доступен на портах узлов через инлет HostPort;
  • Параметр acceptRequestsFrom разрешает подключение к контроллеру только из перечисленных подсетей;
  • Даже если внешний балансировщик или клиент может передавать свои значения заголовков X-Forwarded-*, решение о допуске соединения до контроллера принимается по реальному адресу подключения, а не по заголовкам.
  • Административные Ingress-ресурсы (в данном примере admin-ingress) обслуживаются этим контроллером согласно настроенному Ingress-классу.

Пример Ingress-контроллера, который обслуживает Ingress-ресурсы для публичного трафика:

apiVersion: deckhouse.io/v1
kind: IngressNginxController
metadata:
  name: public
spec:
  ingressClass: public-nginx
  inlet: HostPort
  hostPort:
    httpPort: 8080
    httpsPort: 8443
    behindL7Proxy: true