Kubernetes Nginx Ingress: перенаправление трафика с использованием аннотаций



Перенаправляйте HTTP-трафик или переписывайте URL-адреса с помощью входных аннотаций Kubernetes и Nginx ingress controller. В этой статье объясняется использование аннотаций и их влияние на результирующий файл конфигурации nginx.conf.


Информация взята с Linux Recruit Blog.


nginx.ingress.kubernetes.io/rewrite-target


https://github.com/kubernetes/ingress-nginx/tree/master/docs/examples/rewrite


Пример 1:


apiVersion: networking.k8s.io/v1beta1 
kind: Ingress 
metadata:
   annotations:
     kubernetes.io/ingress.class: "nginx"
     nginx.ingress.kubernetes.io/rewrite-target: /destination$1$2
   name: destination-home
   namespace: myNamespace
 spec:
   rules:
   - host: nginx.redirect
     http:
       paths:
       - backend:
           serviceName: http-svc
           servicePort: 80 
        path: /source(/|$)(.*)

Этот делает прозрачный обратный прокси-сервер.
Он не обновляет Location header, поэтому URL-адрес в браузере не меняется.


Пример 2:


apiVersion: networking.k8s.io/v1beta1
 kind: Ingress
 metadata:
   annotations:
     kubernetes.io/ingress.class: "nginx"
     nginx.ingress.kubernetes.io/rewrite-target: https://nginx.redirect/destination$1$2
   name: destination-home
   namespace: myNamespace
 spec:
   rules:
   - host: nginx.redirect
     http:
       paths:
       - backend:
           serviceName: http-svc
           servicePort: 80
         path: /source(/|$)(.*)

Этот изменяет Location header, и URL-адрес в браузере обновляется:


HTTP/1.1 302 Moved Temporarily
curl -I  http://nginx.redirect/source
Location: https://nginx.redirect/destination
HTTP/1.1 302 Moved Temporarily
curl -I  http://nginx.redirect/source/bar
Location: https://nginx.redirect/destination/bar

Это связано с тем, что строка замены, указанная в аннотации rewrite-target, начинается с https://.


Из документации nginx:


Кроме того, в качестве единственного параметра можно указать URL для временного перенаправления с кодом 302. Такой параметр должен начинаться со строк “http://”, “https://” или “$scheme”. В URL можно использовать переменные.
..............
Если указанное регулярное выражение соответствует URI запроса, URI изменяется в соответствии со строкой замены. Директивы rewrite выполняются последовательно, в порядке их следования в конфигурационном файле. С помощью флагов можно прекратить дальнейшую обработку директив. Если строка замены начинается с “http://”, “https://” или “$scheme”, то обработка завершается и клиенту возвращается перенаправление.

Использование nginx.ingress.kubernetes.io/permanent-redirect-code : '308' аннотации не влияет на возвращаемый код, так как это контролируется правилом перезаписи в nginx.conf. Директива, добавленная в nginx.conf, аналогична:


rewrite “(?i)/source(/|$)(.*)” https://nginx.redirect/destination$1$2 break;

Синтаксис: break;
По умолчанию: —
Контекст: server, location, if

Завершает обработку текущего набора директив модуля ngx_http_rewrite_module.

Если директива указана внутри location, дальнейшая обработка запроса продолжается в этом location.

Если вам нужно управлять кодом возврата с помощью правила rewrite, то вам необходимо использовать директиву возврата после директивы перезаписи. Более подробная информация здесь: https://www.nginx.com/blog/creating-nginx-rewrite-rules .


Я предполагаю, что это можно использовать с помощью nginx.ingress.kubernetes.io/configuration-snippet : | (Я еще не пробовал).


Этот метод работает очень хорошо: определяет корневой каталог приложения (Application Root), который контроллер должен перенаправить, если он находится в / контексте:


$ echo "
 apiVersion: extensions/v1beta1
 kind: Ingress
 metadata:
   annotations:
     nginx.ingress.kubernetes.io/app-root: /destination
   name: approot
   namespace: default
 spec:
   rules:
   - host: approot.bar.com
     http:
       paths:
       - backend:
           serviceName: http-svc
           servicePort: 80
         path: /
 " | kubectl create -f -

В результирующем файле nginx.conf оператор if будет добавлен в контекст server :


if ($uri = /) {
  return 302 /destination
}

2.nginx.ingress.kubernetes.io/configuration-snippet: |


apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
   annotations:
     kubernetes.io/ingress.class: "nginx"
     nginx.ingress.kubernetes.io/configuration-snippet: |
       rewrite ^/source(/?)$ https://nginx.redirect/destination$1 permanent;
       name: destination-home
   namespace: myNamespace
 spec:
   rules:
   - host: nginx.redirect
     http:
       paths:
       - backend:
           serviceName: http-svc
           servicePort: 80
         path: /source

Этот вариант выглядит так, как будто он обеспечивает наибольший контроль над redirect/rewrite, поскольку он добавляет дополнительный фрагмент конфигурации в результирующее местоположение nginx.conf.


permanent: returns a permanent redirect with the 301 code.

Дополнительная документация здесь.


3. nginx.ingress.kubernetes.io/server-snippet :|


Используйте осторожно. Хотя его можно использовать аналогично приведенному выше (только аннотация немного отличается), он добавит вашу пользовательскую конфигурацию в серверный блок в результирующем файле nginx.conf, таким образом, вступив в силу для всего сервера. Перенаправление/перезапись, размещенные здесь, будут обработаны перед любым другим оператором в директиве о местоположении (управляемой входящим ресурсом kubernetes), поэтому это может привести к нежелательному поведению.


Дополнительная документация здесь.


4. nginx.ingress.kubernetes.io/permanent-redirect


apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
   annotations:
     nginx.ingress.kubernetes.io/permanent-redirect: https://nginx.redirect/destination
     nginx.ingress.kubernetes.io/permanent-redirect-code: '308'
   name: destination-home
   namespace: myNamespace
 spec:
   rules:
   - host: nginx.redirect
     http:
       paths:
       - backend:
           serviceName: http-svc
           servicePort: 80
         path: /source

Довольно понятно, работает отлично


curl -I  http://nginx.redirect/source
HTTP/1.1 308 
Permanent Redirect 
Location: https://nginx.redirect/destination
curl -I  http://nginx.redirect/source/bar 
HTTP/1.1 308 
Permanent Redirect 
Location: https://nginx.redirect/destination

Он добавляет оператор if в файл nginx.conf в разделе /source следующим образом:


if ($uri ~* /source) {
     return 308 https://nginx.redirect/destination;
    }

Дополнительная документация: annotations.md#permanent-redirect и здесь.


Permanent Redirect


Эта аннотация позволяет возвращать постоянное перенаправление вместо отправки данных в вышестоящий канал. Например:


nginx.ingress.kubernetes.io/permanent-redirect: 
https://www.google.com 

перенаправил бы все в Google.


Permanent Redirect Code


Эта аннотация позволяет изменять код состояния, используемый для постоянных перенаправлений. Например nginx.ingress.kubernetes.io/permanent-redirect-code : '308'вернет вам постоянное перенаправление (permanent-redirect) с кодом 308.


Temporal Redirect


Эта аннотация позволяет вам возвращать временное перенаправление (код возврата 302) вместо отправки данных в вышестоящий канал. Например nginx.ingress.kubernetes.io/temporal-redirect : https://www.google.com перенаправил бы все в Google с кодом возврата 302 (Временно перемещен)


Немного рекламы: На платформе https://rotoro.cloud/ вы можете найти курсы с практическими занятиями:


Комментарии (10)


  1. indestructable
    22.10.2021 15:02

    Уточнение - это все работает для nginx ingress (для собственной инсталляции кубернетиса), и не работает в облаке (по крайней мере для AWS).


    1. chemtech Автор
      22.10.2021 16:34

      А можете уточнить эти все примеры не будут там работать?

      А вот такой код?

      apiVersion: networking.k8s.io/v1beta1
      kind: Ingress
      metadata:
        name: myingress
        namespace: dev
        annotations:
          kubernetes.io/ingress.class: nginx
          nginx.ingress.kubernetes.io/use-regex: "true"
          nginx.ingress.kubernetes.io/rewrite-target: /$1
      spec:
        tls:
          - hosts:
            - xxx.example.com
            secretName: tls-secret
        rules:
        - host: xxx.example.com
          http:
            paths:
            - backend:
                serviceName: service1
                servicePort: 80 
              path: /(service1/.*)
            - backend:
                serviceName: service2
                servicePort: 80 
              path: /service2/(.*)
            - backend:
                serviceName: service3
                servicePort: 80
              path: /(.*)


      1. celebrate
        23.10.2021 14:08

        Если в облако поставить nginx-ingress, то конечно будет работать.


        1. indestructable
          23.10.2021 23:01

          Не подскажете, как в АВС в такой схеме делать доступ извне? Создавать еще один лоад балансер?


          1. celebrate
            24.10.2021 00:01

            Не понял вопроса. Можно вместо нжинкс ингресса юзать ALB Ingress Controller. Ну либо использовать тот же самый нжинкс ингресс. Не вижу никакой проблемы.


            1. indestructable
              25.10.2021 13:10

              Да, но в нем не доступны 80% функций описанных в статье (нет перезаписи урлов и тп), только стандартный функционал АВС аппликейшн лоад балансера.


              1. celebrate
                25.10.2021 14:17
                +1

                Что мешает юзать nginx-ingress в AWS?


                1. indestructable
                  25.10.2021 18:23

                  Вопрос в том, нужен ли АВС аппликейшн лоад балансер в случае такого использования?


                  1. OkGoLove
                    25.10.2021 19:00

                    Ставите service type: LoadBalancer и получаете готовый L4 балансер с ingress за ним


  1. ZhilyaevDmitriy
    23.10.2021 18:19
    +1

    Спасибо за очередной перевод!

    От себя добавлю, что многие аннотации конфликтуют друг с другом. И об этом тоже интересно услышать.