简体   繁体   English

使用 Ingress-NGINX 的 ExternalName 服务的 308 重定向循环

[英]308 Redirect Loop with ExternalName Service Using Ingress-NGINX

I'm using ingress-nginx-controller (0.32.0) and am attempting to point an ExternalName service at a URL and yet it's stuck in a loop of 308 Redirects.我正在使用ingress-nginx-controller (0.32.0) 并试图将 ExternalName 服务指向 URL ,但它陷入了 308 重定向循环。 I've seen plenty of issues out there and I figure there's just one thing off with my configuration.我已经看到了很多问题,我认为我的配置只有一件事。 Is there something really small that I'm missing here?我在这里想念的东西真的很小吗?

ConfigMap for NGINX Configuration: NGINX 配置的 ConfigMap:

kind: ConfigMap
apiVersion: v1
metadata:
  name: nginx-configuration
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
data:
  use-proxy-protocol: "true"
  use-forwarded-headers: "true"
  proxy-real-ip-cidr: "0.0.0.0/0" # restrict this to the IP addresses of ELB
  proxy-read-timeout: "3600"
  proxy-send-timeout: "3600"
  backend-protocol: "HTTPS"
  ssl-redirect: "false"
  http-snippet: |
    map true $pass_access_scheme {
      default "https";
    }
    map true $pass_port {
      default 443;
    }
    server {
      listen 8080 proxy_protocol;
      return 308 https://$host$request_uri;
    }

NGINX Service: NGINX 服务:

kind: Service
apiVersion: v1
metadata:
  name: ingress-nginx
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-ssl-cert: "XXX"
    service.beta.kubernetes.io/aws-load-balancer-backend-protocol: "tcp"
    service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "https"
    service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout: "3600"
    service.beta.kubernetes.io/aws-load-balancer-proxy-protocol: "*"
spec:
  type: LoadBalancer
  selector:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
  ports:
    - name: http
      port: 80
      targetPort: 8080
    - name: https
      port: 443
      targetPort: http

Ingress Definition:入口定义:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-members-portal
  namespace: dev
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/use-regex: "true"
spec:
  rules:
  - host: foo-111.dev.bar.com
    http:
      paths:
      - path: /login
        backend:
          serviceName: foo-service
          servicePort: 80

ExternalName Service:外部名称服务:

apiVersion: v1
kind: Service
metadata:
  name: foo-service
spec:
  type: ExternalName
  externalName: foo.staging.bar.com
selector:
  app: foo

EDIT编辑

I figured it out, I wanted to point to a service in another namespace: so I changed the ExternalName service to this:我想通了,我想指向另一个命名空间中的服务:所以我将 ExternalName 服务更改为:

apiVersion: v1
kind: Service
metadata:
  name: foo-service
spec:
  type: ExternalName
  externalName: foo-service.staging.svc.cluster.local
ports:
- port: 80
  protocol: TCP
  targetPort: 80
selector:
  app: foo

I believe the issue you're seeing is due to the fact that your external service isn't working as you think it is.我相信您看到的问题是由于您的外部服务没有像您想象的那样工作。 In your ingress definition, you are defining the service to utilize port 80 on your foo-service .在您的入口定义中,您正在定义服务以使用foo-service上的端口 80。 In theory, this would redirect you back to your ingress controller's ELB, redirect your request to the https://foo.staging.bar.com address, and move on.理论上,这会将您重定向回入口控制器的 ELB,将您的请求重定向到https://foo.staging.bar.com地址,然后继续。

However, external services don't really work that way.但是,外部服务并不是这样工作的。 Essentially, all externalName will do is run a DNS check with KubeDNS/CoreDNS, and return the CNAME information on that request.本质上,所有externalName都会对 KubeDNS/CoreDNS 运行 DNS 检查,并返回该请求的 CNAME 信息。 It doesn't handle redirects of any kind.它不处理任何类型的重定向。

For example, in this case, foo.staging.bar.com:80 would return foo.staging.bar.com:443 .例如,在这种情况下, foo.staging.bar.com:80将返回foo.staging.bar.com:443 You are directing the request for that site to port 80 , which in itself directs the request to port 8080 in the ingress controller, which then redirects that request back out to the ELB's port 443 .您正在将该站点的请求定向到端口80 ,该端口本身将请求定向到入口 controller 中的端口8080 ,然后将该请求重定向回 ELB 的端口443 That redirect logic doesn't coexist with the external service.该重定向逻辑不与外部服务共存。

The problem here, then, is that your app will essentially then try to do this:那么,这里的问题是你的应用程序基本上会尝试这样做:

http://foo-service:80 --> http://foo.staging.bar.com:80/login --> https://foo.staging.bar.com:443 http://foo-service:80 --> http://foo.staging.bar.com:80/login --> https://foo.staging.bar.com:443

My expectation on this is that you never actually reach the third step.我对此的期望是你永远不会真正达到第三步。 Why?为什么? Well because foo-service:80 is not directing you to port 443, first of all, but second of all...all coreDNS is doing in the backend is running a DNS check against the foo-service 's external name, which is foo.staging.bar.com .好吧,因为foo-service:80首先不是将您定向到端口 443,但其次...所有coreDNS在后端正在运行 DNS 检查foo-service的外部名称,即foo.staging.bar.com It's not handling any kind of redirection.它不处理任何类型的重定向。 So depending on how your host from your app is returned, and handled, your app may never actually get to that site and port.因此,根据您的应用程序中的主机如何返回和处理,您的应用程序可能永远不会真正到达该站点和端口。 So rather than reach that site, you just have your app keep looping back to http://foo-service:80 for those requests, which will always result in a 308 loopback.因此,您无需访问该站点,而是让您的应用程序不断循环回http://foo-service:80以获取这些请求,这将始终导致 308 环回。

The key here is that foo-service is the host header being sent to the NGINX Ingress controller, not foo.staging.bar.com . The key here is that foo-service is the host header being sent to the NGINX Ingress controller, not foo.staging.bar.com . So on a redirect to 443 , my expectation is that all that is happening, then, is you are hitting foo-service , and any redirects are being improperly sent back to foo-service:80 .因此,在重定向到443时,我的期望是所有正在发生的事情,就是您正在点击foo-service ,并且任何重定向都被不正确地发送回foo-service:80

A good way to test this is to run curl -L -v http://foo-service:80 and see what happens.一个很好的测试方法是运行curl -L -v http://foo-service:80看看会发生什么。 That will follow all redirects from that service, and provide you context as to how your ingress controller is handling those requests.这将遵循来自该服务的所有重定向,并为您提供有关您的入口 controller 如何处理这些请求的上下文。

It's really hard to give more information, as I don't have access to your setup directly.很难提供更多信息,因为我无法直接访问您的设置。 However, if you know that your app is always going to be hitting port 443 , it would probably be a good fix, in this case, to change your ingress and service to look something like this:但是,如果您知道您的应用程序总是会访问端口443 ,那么在这种情况下,将您的入口和服务更改为如下所示可能是一个很好的解决方案:


apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-members-portal
  namespace: dev
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/use-regex: "true"
spec:
  rules:
  - host: foo-111.dev.bar.com
    http:
      paths:
      - path: /login
        backend:
          serviceName: foo-service
          servicePort: 443
---
apiVersion: v1
kind: Service
metadata:
  name: foo-service
spec:
  type: ExternalName
  externalName: foo.staging.bar.com

That should ensure you don't have any kind of https redirect.这应该确保您没有任何类型的 https 重定向。 Unfortunately, this may also cause issues with ssl validation, but that would be another issue all together.不幸的是,这也可能导致ssl验证出现问题,但这将是另一个问题。 The last piece of I can recommend is to possibly just use foo.staging.bar.com itself, rather than an external service in this case.我可以推荐的最后一点是可能只使用foo.staging.bar.com本身,而不是在这种情况下使用外部服务。

For more information, see: https://kubernetes.io/docs/concepts/services-networking/service/#externalname有关更多信息,请参阅: https://kubernetes.io/docs/concepts/services-networking/service/#externalname

Hope this helps!希望这可以帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM