【问题标题】:ingress nginx: rewrite rule logic and location lookupingress nginx:重写规则逻辑和位置查找
【发布时间】:2019-10-01 20:06:41
【问题描述】:

我在我的 k8s 集群中部署了一个 nginx 入口控制器来访问后端应用程序。

在测试我的入口资源配置时,我注意到如果我添加了重写规则,我还需要为重写后的 URI 声明一个指向同一个服务的路径。

例如,以下入口配置不起作用:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: fieldprov-app
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /wetty
    nginx.ingress.kubernetes.io/enable-rewrite-log: "true"
    kubernetes.io/ingress.class: "field-management"
spec:
  tls:
  - hosts:
    - ccfanhe09.sce-lab.com
  rules:
    - host: ccfanhe09.sce-lab.com
      http:
        paths:
         - path: /provisioning
           backend:
            serviceName: fieldprov-app
            servicePort: 3000

控制器会将我重定向到与“/”关联的默认后端服务器

fd10::2:102 - [fd10::2:102] - - [01/Oct/2019:19:34:07 +0000] "GET /provisioning HTTP/2.0" 304 0 "-" "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0" 236 0.003 [default-fieldprov-app-3000] [] [fd10::1:10a]:
3000 0 0.003 304 64895f25fd3fb9937f66ebbcee369c81
fd10::2:102 - [fd10::2:102] - - [01/Oct/2019:19:34:07 +0000] "GET /wetty/socket.io/socket.io.js HTTP/2.0" 404 159 "https://ccfanhe10.sce-lab.com:30000/provisioning" "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:60.0) Gecko/20100101 Firef
ox/60.0" 71 0.002 [upstream-default-backend] [] 127.0.0.1:8181 159 0.003 404 8310972dd6b39f294bae7550305bd7c2
fd10::2:102 - [fd10::2:102] - - [01/Oct/2019:19:34:07 +0000] "GET /wetty/wetty.min.js HTTP/2.0" 404 159 "https://ccfanhe10.sce-lab.com:30000/provisioning" "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0" 2
4 0.001 [upstream-default-backend] [] 127.0.0.1:8181 159 0.002 404 47875d655cf4bcd02fc6212dc6142848
fd10::2:102 - [fd10::2:102] - - [01/Oct/2019:19:34:07 +0000] "GET /wetty/wetty.min.js HTTP/2.0" 404 159 "https://ccfanhe10.sce-lab.com:30000/provisioning" "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0" 2
4 0.001 [upstream-default-backend] [] 127.0.0.1:8181 159 0.000 404 08d1fd4cc72a5475d0fcfb4ca6a4cb2b``

所以对我来说,就像控制器在应用重写规则后进行第二次查找一样。

下面是我的 nginx.conf 关联到上述入口配置:

## start server ccfanhe10.sce-lab.com
    server {
        server_name ccfanhe10.sce-lab.com ;

        listen 80  ;
        listen [::]:80  ;
        listen 443  ssl http2 ;
        listen [::]:443  ssl http2 ;

        set $proxy_upstream_name "-";

        # PEM sha: 692b563bafa154b7d28350ef01e7c4d53ec2afd1
        ssl_certificate                         /etc/ingress-controller/ssl/default-fake-certificate.pem;
        ssl_certificate_key                     /etc/ingress-controller/ssl/default-fake-certificate.pem;

        ssl_certificate_by_lua_block {
            certificate.call()
        }

        location ~* "^/provisioning" {

            set $namespace      "default";
            set $ingress_name   "fieldprov-app";
            set $service_name   "fieldprov-app";
        set $service_port   "{0 3000 }";
            set $location_path  "/provisioning";

            rewrite_by_lua_block {
                lua_ingress.rewrite({
                    force_ssl_redirect = true,
                    use_port_in_redirects = false,
                })
                balancer.rewrite()
                plugins.run()
            }

            header_filter_by_lua_block {

                plugins.run()
            }
            body_filter_by_lua_block {

            }

            log_by_lua_block {

                balancer.log()

                monitor.call()

                plugins.run()
            }

            if ($scheme = https) {
                more_set_headers                        "Strict-Transport-Security: max-age=15724800; includeSubDomains";
            }

            rewrite_log on;

            port_in_redirect off;

            set $balancer_ewma_score -1;
            set $proxy_upstream_name    "default-fieldprov-app-3000";
            set $proxy_host             $proxy_upstream_name;
            set $pass_access_scheme $scheme;
            set $pass_server_port $server_port;
            set $best_http_host $http_host;
            set $pass_port $pass_server_port;

            set $proxy_alternative_upstream_name "";

            client_max_body_size                    1m;

            proxy_set_header Host                   $best_http_host;

            # Pass the extracted client certificate to the backend

            # Allow websocket connections
            proxy_set_header                        Upgrade           $http_upgrade;

            proxy_set_header                        Connection        $connection_upgrade;

            proxy_set_header X-Request-ID           $req_id;
            proxy_set_header X-Real-IP              $the_real_ip;

            proxy_set_header X-Forwarded-For        $the_real_ip;

            proxy_set_header X-Forwarded-Host       $best_http_host;
            proxy_set_header X-Forwarded-Port       $pass_port;
            proxy_set_header X-Forwarded-Proto      $pass_access_scheme;

            proxy_set_header X-Original-URI         $request_uri;

            proxy_set_header X-Scheme               $pass_access_scheme;

            # Pass the original X-Forwarded-For
            proxy_set_header X-Original-Forwarded-For $http_x_forwarded_for;

            # mitigate HTTPoxy Vulnerability
            # https://www.nginx.com/blog/mitigating-the-httpoxy-vulnerability-with-nginx/
            proxy_set_header Proxy                  "";

            # Custom headers to proxied server

            proxy_connect_timeout                   5s;
            proxy_send_timeout                      60s;
            proxy_read_timeout                      60s;

            proxy_buffering                         off;
            proxy_buffer_size                       4k;
            proxy_buffers                           4 4k;
            proxy_request_buffering                 on;
            proxy_http_version                      1.1;

            proxy_cookie_domain                     off;
            proxy_cookie_path                       off;

            # In case of errors try the next upstream server before returning an error
            proxy_next_upstream                     error timeout;
            proxy_next_upstream_timeout             0;
            proxy_next_upstream_tries               3;

            rewrite "(?i)/provisioning" /wetty break;
            proxy_pass http://upstream_balancer;

            proxy_redirect                          off;

        }

        location ~* "^/" {

            set $namespace      "";
            set $ingress_name   "";
            set $service_name   "";
        set $service_port   "{0 0 }";
            set $location_path  "/";

            rewrite_by_lua_block {
                lua_ingress.rewrite({
                    force_ssl_redirect = true,
                    use_port_in_redirects = false,
                })
                balancer.rewrite()
                plugins.run()
            }

            header_filter_by_lua_block {

                plugins.run()
            }
            body_filter_by_lua_block {

            }

            log_by_lua_block {

                balancer.log()

                monitor.call()

                plugins.run()
            }

            if ($scheme = https) {
                more_set_headers                        "Strict-Transport-Security: max-age=15724800; includeSubDomains";
            }

            rewrite_log on;

            port_in_redirect off;

            set $balancer_ewma_score -1;
            set $proxy_upstream_name    "upstream-default-backend";
            set $proxy_host             $proxy_upstream_name;
            set $pass_access_scheme $scheme;
            set $pass_server_port $server_port;
            set $best_http_host $http_host;
            set $pass_port $pass_server_port;

            set $proxy_alternative_upstream_name "";

            client_max_body_size                    1m;

            proxy_set_header Host                   $best_http_host;

            # Pass the extracted client certificate to the backend

            # Allow websocket connections
            proxy_set_header                        Upgrade           $http_upgrade;

            proxy_set_header                        Connection        $connection_upgrade;

            proxy_set_header X-Request-ID           $req_id;
            proxy_set_header X-Real-IP              $the_real_ip;

            proxy_set_header X-Forwarded-For        $the_real_ip;

            proxy_set_header X-Forwarded-Host       $best_http_host;
            proxy_set_header X-Forwarded-Port       $pass_port;
            proxy_set_header X-Forwarded-Proto      $pass_access_scheme;

            proxy_set_header X-Original-URI         $request_uri;

            proxy_set_header X-Scheme               $pass_access_scheme;

            # Pass the original X-Forwarded-For
            proxy_set_header X-Original-Forwarded-For $http_x_forwarded_for;

            # mitigate HTTPoxy Vulnerability
            # https://www.nginx.com/blog/mitigating-the-httpoxy-vulnerability-with-nginx/
            proxy_set_header Proxy                  "";

            # Custom headers to proxied server

            proxy_connect_timeout                   5s;
            proxy_send_timeout                      60s;
            proxy_read_timeout                      60s;

            proxy_buffering                         off;
            proxy_buffer_size                       4k;
            proxy_buffers                           4 4k;
            proxy_request_buffering                 on;
            proxy_http_version                      1.1;

            proxy_cookie_domain                     off;
            proxy_cookie_path                       off;

            # In case of errors try the next upstream server before returning an error
            proxy_next_upstream                     error timeout;
            proxy_next_upstream_timeout             0;
            proxy_next_upstream_tries               3;

            rewrite "(?i)/" /wetty break;
            proxy_pass http://upstream_balancer;

            proxy_redirect                          off;

        }

    }
    ## end server ccfanhe10.sce-lab.com

我不明白“^ /”位置下的重写规则。 此外,我认为将 break 关键字添加到重写规则可以避免任何额外的 URI 查找,但这不是我看到的行为。如果我不为“/wetty”创建一个指向与“/provisioning”相同的服务的位置,它就不起作用。

我正在寻找有关在这种情况下的预期行为的一些解释。

感谢您的支持!!

【问题讨论】:

  • 您使用的是什么版本的 kubernetes 和 nginx 入口控制器?这里是link 来指导如何检查 nginx 版本。要检查 Kubernetes 版本,请使用 kubectl version
  • 嗨,我使用的是 kubernetes 1.15.3 和 nginx 入口控制器 0.25.1。谢谢
  • @laaubert 你解决了吗?

标签: kubernetes-ingress nginx-ingress


【解决方案1】:

尝试使用 ingres-nginx 文档的 herehere 部分中所述的捕获组。

从版本 0.22.0 开始,使用注解 nginx.ingress.kubernetes.io/rewrite-target 的入口定义与以前的版本不向后兼容。在 0.22.0 及更高版本中,请求 URI 中需要传递到重写路径的任何子字符串都必须在 capture group 中明确定义。

Captured groups 按时间顺序保存在编号占位符中,格式为$1$2 ... $n。这些占位符可以用作rewrite-target注解中的参数。

所以你的入口配置应该是这样的:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: fieldprov-app
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /wetty/$2
    nginx.ingress.kubernetes.io/enable-rewrite-log: "true"
    kubernetes.io/ingress.class: "field-management"
spec:
  tls:
  - hosts:
    - ccfanhe09.sce-lab.com
  rules:
    - host: ccfanhe09.sce-lab.com
      http:
        paths:
         - path: /provisioning/(/|$)(.*)
           backend:
            serviceName: fieldprov-app
            servicePort: 3000

至于 nginx.conf 看起来是这样的,因为它的设置是使用 lua-nginx-module 从 nginx-controller 注入的,你可以阅读它here


更新:

如果重写规则正常工作,则不应进行任何额外的查找。我在 nginx ingress annotations 中找不到类似的东西。

您可以使用curl -I -k <URI> 命令检查重写规则是否有效:

$ curl -I -k http://approot.bar.com/
HTTP/1.1 302 Moved Temporarily
Server: nginx/1.11.10
Date: Mon, 13 Mar 2017 14:57:15 GMT
Content-Type: text/html
Content-Length: 162
Location: http://stickyingress.example.com/app1
Connection: keep-alive

【讨论】:

  • 在应用重写规则后,您的配置会避免第二次查找吗?即我不需要为 /weety 添加路径。谢谢
猜你喜欢
  • 2016-05-30
  • 1970-01-01
  • 2018-12-02
  • 2019-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-20
相关资源
最近更新 更多