Стадия жизненного цикла модуля: Общедоступная версия
У модуля есть требования для установки
Пример для AWS (Network Load Balancer)
При создании балансировщика используются все доступные зоны в кластере.
В каждой зоне балансировщик получает публичный IP. Если в зоне есть instance с Ingress-контроллером, A-запись с IP-адресом балансировщика из этой зоны автоматически добавляется к доменному имени балансировщика.
Если в зоне не остается instance с Ingress-контроллером, тогда IP автоматически удаляется из DNS.
В том случае, если в зоне всего один инстанс с Ingress-контроллером, при перезапуске пода IP-адрес балансировщика этой зоны будет временно исключен из DNS.
apiVersion: deckhouse.io/v2
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/v2
kind: IngressNginxController
metadata:
name: main
spec:
ingressClass: nginx
inlet: LoadBalancerВ GCP на узлах должна присутствовать аннотация, разрешающая принимать подключения на внешние адреса для сервисов с типом NodePort.
Пример для OpenStack
apiVersion: deckhouse.io/v2
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/v2
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/v2
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.
apiVersion: deckhouse.io/v2
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, CSE Pro.
-
Включите модуль
metallb:apiVersion: deckhouse.io/v1alpha1 kind: ModuleConfig metadata: name: metallb spec: enabled: true version: 2 -
Создайте ресурс MetalLoadBalancerClass:
Metallb-балансировщики должны размещаться на тех же узлах, что и ingress-контроллеры. В типовых сценариях развертывания для этого используются frontend-узлы (для развертывания ingress-контроллеров и Metallb-балансировщиков на frontend-узлах используйте в их манифестах аннотацию
node-role.deckhouse.io/frontend: "").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.deckhouse.io/frontend: "" type: L2 -
Создайте ресурс IngressNginxController:
apiVersion: deckhouse.io/v2 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.deckhouse.io/frontend: "" tolerations: - effect: NoExecute key: dedicated.deckhouse.io value: frontend operator: EqualПри создании ingress-контроллера также можно указать определенные IP-адреса из пула, которые будут ему присвоены. Для указания адресов, которые должны быть присвоены сервису, используйте аннотацию
network.deckhouse.io/load-balancer-ips. Если желаемых адресов больше одного, то также должна присутствовать аннотацияnetwork.deckhouse.io/l2-load-balancer-external-ips-count, в которой необходимо указать количество выделяемых адресов из пула (оно не должно быть меньше количества адресов, перечисленных вnetwork.deckhouse.io/load-balancer-ips). Пример использования аннотаций для присвоения сервису определенных адресов из пула. -
Платформа создаст сервис с типом
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/v2
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/v2
kind: IngressNginxController
metadata:
name: public
spec:
ingressClass: public-nginx
inlet: HostPort
hostPort:
httpPort: 8080
httpsPort: 8443
behindL7Proxy: trueПример использования cert-manager для заказа сертификатов
Модуль работает с сертификатами, которые выписывает cert-manager. Ingress-контроллер использует Secret, указанный в секции spec.tls Ingress-ресурса, поэтому главное требование — чтобы cert-manager создал этот Secret в пространстве имён Ingress-ресурса.
В примерах ниже используется ClusterIssuer с HTTP-01-solver. Создайте ClusterIssuer (или Issuer в нужном пространстве имён) согласно документации модуля cert-manager:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt
spec:
acme:
email: admin@example.com
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: letsencrypt-account-key
solvers:
- http01:
ingress:
ingressClassName: nginxЗамените адрес электронной почты и, при необходимости, ACME-сервер. При тестировании используйте staging-сервер ACME, чтобы не исчерпать лимиты Let’s Encrypt.
Для Issuer в пространстве имён используйте ту же секцию spec, укажите kind: Issuer и metadata.namespace; затем используйте аннотацию cert-manager.io/issuer или issuerRef.kind: Issuer, как показано ниже.
ingressClassName в solver должен совпадать с Ingress-классом контроллера, который обслуживает домен. В примерах ниже это nginx. Если контроллер использует другой класс, измените его и в solver, и в Ingress-ресурсе.
Для HTTP-01 домен должен указывать на Ingress-контроллер, а контроллер должен быть доступен по TCP-порту 80. Если контроллер доступен на нестандартном httpPort (см. описание httpPort в разделе inlet) или только на httpsPort, используйте DNS-01 либо пробросьте порт 80 до контроллера.
Заказ сертификата с помощью аннотации Ingress-ресурса
Добавьте аннотацию cert-manager.io/cluster-issuer в Ingress-ресурс и укажите секцию spec.tls:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app
namespace: my-namespace
annotations:
cert-manager.io/cluster-issuer: letsencrypt
spec:
ingressClassName: nginx
tls:
- hosts:
- my-app.example.com
secretName: my-app-tls
rules:
- host: my-app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app
port:
number: 80cert-manager создаст ресурс Certificate на основе аннотации и секции spec.tls, выпишет сертификат и запишет его в Secret my-app-tls. Значения hosts в spec.tls — это DNS-имена, которые заказывает cert-manager; они должны совпадать с хостами в правилах Ingress-ресурса. Ingress-контроллер автоматически обнаружит Secret и начнёт обслуживать HTTPS.
Чтобы заказать сертификат у Issuer в пространстве имён, используйте аннотацию cert-manager.io/issuer: <имя-issuer>. В этом случае Issuer и Ingress-ресурс должны находиться в одном пространстве имён.
Заказ сертификата с помощью отдельного ресурса Certificate
Создайте ресурс Certificate, который ссылается на Issuer или ClusterIssuer и целевой Secret:
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: my-app-tls
namespace: my-namespace
spec:
secretName: my-app-tls
issuerRef:
name: letsencrypt
kind: ClusterIssuer
group: cert-manager.io
dnsNames:
- my-app.example.comЗатем укажите тот же Secret в Ingress-ресурсе. Аннотация cert-manager в Ingress-ресурсе не нужна:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app
namespace: my-namespace
spec:
ingressClassName: nginx
tls:
- hosts:
- my-app.example.com
secretName: my-app-tls
rules:
- host: my-app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app
port:
number: 80Этот способ удобен, если сертификат используется несколькими Ingress-ресурсами в одном пространстве имён или управляется отдельно от них. Ресурс Certificate и Ingress-ресурс должны находиться в одном пространстве имён, так как spec.tls.secretName ссылается на Secret в пространстве имён Ingress-ресурса. Для Issuer в пространстве имён укажите issuerRef.kind: Issuer; Issuer должен находиться в том же пространстве имён, что и Certificate.
В обоих случаях cert-manager создаёт Secret, который отслеживает Ingress-контроллер. При продлении сертификата cert-manager обновляет Secret, и контроллер автоматически перечитывает сертификат.
Параметр defaultSSLCertificate на уровне модуля — это отдельный резервный сертификат, для работы с cert-manager он не требуется.