【问题标题】:308 Redirect Loop with ExternalName Service Using Ingress-NGINX使用 Ingress-NGINX 的 ExternalName 服务的 308 重定向循环
【发布时间】:2020-06-02 21:28:01
【问题描述】:

我正在使用 ingress-nginx-controller (0.32.0) 并试图将 ExternalName 服务指向一个 URL,但它陷入了 308 重定向循环。我已经看到了很多问题,我认为我的配置只有一件事。我在这里错过了什么非常小的东西吗?

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 服务:

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

入口定义:

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

外部名称服务:

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

编辑

我想通了!我想指向另一个命名空间中的服务,所以我将 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

【问题讨论】:

  • 你在用什么? EKS、KOP 还是其他?您是使用 Helm 部署 Ingress 还是使用文档中的部署?
  • @rae,你确定这正是一个对你有用的服务清单文件吗?它仍然包含一个选择器,它与 ExternalName 服务概念保持一致!
  • @Nepomucen 是的,这对我来说效果很好!它只有一个名字。没有选择器。

标签: nginx kubernetes kubernetes-ingress nginx-ingress


【解决方案1】:

我相信您看到的问题是由于您的外部服务没有像您想象的那样工作。在您的入口定义中,您正在定义服务以使用您的foo-service 上的端口 80。理论上,这会将您重定向回入口控制器的 ELB,将您的请求重定向到 https://foo.staging.bar.com 地址,然后继续。

但是,外部服务并不是这样工作的。本质上,externalName 所做的只是使用 KubeDNS/CoreDNS 运行 DNS 检查,并返回该请求的 CNAME 信息。它不处理任何类型的重定向。

例如,在这种情况下,foo.staging.bar.com:80 将返回 foo.staging.bar.com:443。您正在将该站点的请求定向到端口80,它本身将请求定向到入口控制器中的端口8080,然后将该请求重定向回ELB 的端口443。该重定向逻辑不与外部服务共存。

那么,这里的问题是,您的应用基本上会尝试这样做:

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

我对此的期望是你永远不会真正达到第三步。为什么?好吧,因为foo-service:80 并没有将您定向到端口 443,首先,但其次...所有coreDNS 在后端所做的是针对foo-service 的外部名称运行 DNS 检查,即foo.staging.bar.com。它不处理任何类型的重定向。因此,根据您的应用程序中的主机如何返回和处理,您的应用程序可能永远不会真正到达该站点和端口。因此,您无需访问该站点,而是让您的应用针对这些请求不断循环回 http://foo-service:80,这将始终导致 308 环回。

这里的关键是foo-service 是发送到NGINX Ingress 控制器的host 标头,而不是foo.staging.bar.com。因此,在重定向到443 时,我的期望是所有正在发生的事情,然后,您正在点击foo-service,并且任何重定向都被不正确地发送回foo-service:80

一个很好的测试方法是运行curl -L -v http://foo-service:80 看看会发生什么。这将遵循来自该服务的所有重定向,并为您提供有关入口控制器如何处理这些请求的上下文。

很难提供更多信息,因为我无法直接访问您的设置。但是,如果您知道您的应用程序总是会访问端口 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

这应该确保您没有任何类型的 https 重定向。不幸的是,这也可能导致ssl 验证出现问题,但这将是另一个问题。我可以推荐的最后一点是可能只使用foo.staging.bar.com 本身,而不是在这种情况下使用外部服务。

欲了解更多信息,请参阅:https://kubernetes.io/docs/concepts/services-networking/service/#externalname

希望这会有所帮助!

【讨论】:

  • 非常感谢您的澄清!
  • 我想通了!我想指向另一个命名空间中的服务,所以我将 ExternalName 服务更改为此以指向我在暂存命名空间中的服务! (用解决方案更新了我的问题)
猜你喜欢
  • 1970-01-01
  • 2019-03-08
  • 2019-05-20
  • 2021-02-22
  • 2021-06-21
  • 2022-06-21
  • 2015-03-11
  • 1970-01-01
  • 2023-01-04
相关资源
最近更新 更多