308 使用入口 NGINX 的外部名称服务重定向循环



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

ConfigMap for NGINX Configuration:

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

我相信您看到的问题是由于您的外部服务没有像您想象的那样工作。 在入口定义中,您正在定义服务以利用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入口控制器的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

希望这有帮助!

最新更新