AWS EKS 集群中的 TLS nginx 入口导致 404 Not Found
TLS nginx ingress in AWS EKS Cluster results in 404 Not Found
我正在尝试使用 Kubernetes Ingress Nginx 控制器和 运行 AWS EKS 中的一个简单的 nginx 服务器。
浏览器 (https) --> Route 53 (DNS) --> CLB --> nginx Ingress (终止 TLS) --> 服务 --> POD
但我在浏览器中收到 404 错误(url 使用:https://example.com/my-nginx):
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.19.10</center>
</body>
</html>
在入口日志中 (kubectl logs -n nginx-ingress nginx-ingress-nginx-controller-6db6f85bc4-mfpwx),我可以在下面看到:
192.168.134.181 - - [24/Apr/2021:19:02:01 +0000] "GET /my-nginx HTTP/2.0" 404 154 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:88.0) Gecko/20100101 Firefox/88.0" 219 0.002 [eshop-dev-my-nginx-9443 ] [] 192.168.168.105:80 154 0.000 404 42fbe692a032bb40bf193954526369cd
这是我的部署 yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
namespace: eshop-dev
spec:
selector:
matchLabels:
run: my-nginx
replicas: 2
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- name: my-nginx
image: nginx
ports:
- containerPort: 80
服务 yaml:
apiVersion: v1
kind: Service
metadata:
namespace: eshop-dev
name: my-nginx
spec:
selector:
run: my-nginx
ports:
- name: server
port: 9443
targetPort: 80
protocol: TCP
和入口 yaml:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-ingress
namespace: eshop-dev
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: example.com
http:
paths:
- path: /my-nginx
pathType: ImplementationSpecific
backend:
service:
name: my-nginx
port:
number: 9443
tls:
- hosts:
- example.com
secretName: externaluicerts
我已验证服务 returns 与端口转发一起使用时所需的输出:
kubectl -n eshop-dev port-forward service/my-nginx 9443:9443
不知道是不是ingress配置不对还是另外一个problem.Thanks提前求助!
nginx-port-forward
这是 kubectl get ingress -n eshop-dev test-ingress -o yaml 的输出
kubectl get ingress -n eshop-dev test-ingress -o yaml
Warning: extensions/v1beta1 Ingress is deprecated in v1.14+, unavailable in v1.22+; use networking.k8s.io/v1 Ingress
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"networking.k8s.io/v1","kind":"Ingress","metadata":{"annotations":{"kubernetes.io/ingress.class":"nginx"},"name":"test-ingress","namespace":"eshop-dev"},"spec":{"rules":[{"host":"example.com","http":{"paths":[{"backend":{"service":{"name":"my-nginx","port":{"number":9443}}},"path":"/my-nginx","pathType":"ImplementationSpecific"}]}}],"tls":[{"hosts":["example.com"],"secretName":"externaluicerts"}]}}
kubernetes.io/ingress.class: nginx
creationTimestamp: "2021-04-24T13:16:21Z"
generation: 13
managedFields:
- apiVersion: networking.k8s.io/v1beta1
fieldsType: FieldsV1
fieldsV1:
f:status:
f:loadBalancer:
f:ingress: {}
manager: nginx-ingress-controller
operation: Update
time: "2021-04-24T13:16:40Z"
- apiVersion: extensions/v1beta1
fieldsType: FieldsV1
fieldsV1:
f:metadata:
f:annotations: {}
manager: kubectl-client-side-apply
operation: Update
time: "2021-04-24T13:18:36Z"
- apiVersion: networking.k8s.io/v1
fieldsType: FieldsV1
fieldsV1:
f:metadata:
f:annotations:
f:kubectl.kubernetes.io/last-applied-configuration: {}
f:kubernetes.io/ingress.class: {}
f:spec:
f:rules: {}
f:tls: {}
manager: kubectl-client-side-apply
operation: Update
time: "2021-04-24T16:33:47Z"
name: test-ingress
namespace: eshop-dev
resourceVersion: "7555944"
selfLink: /apis/extensions/v1beta1/namespaces/eshop-dev/ingresses/test-ingress
uid: a7694655-20c6-48c7-8adc-cf3a53cf2ffe
spec:
rules:
- host: example.com
http:
paths:
- backend:
serviceName: my-nginx
servicePort: 9443
path: /my-nginx
pathType: ImplementationSpecific
tls:
- hosts:
- example.com
secretName: externaluicerts
status:
loadBalancer:
ingress:
- hostname: xxxxxxxxxxxxxxxxdc75878b2-433872486.eu-west-1.elb.amazonaws.com
从您发布的 nginx-port-forward 图片来看,我看到您直接在 localhost:9443
上,这意味着您尝试访问的 Nginx 服务器在 /
[ 下提供其内容=27=]
但是在入口定义中,您定义服务将由 path: /my-nginx
提供。这可能是问题所在,因为您请求的 https://example.com/my-nginx
基本上会转到 my-nginx:9443/my-nginx
,并且根据此服务背后的 Pod,如果该路径上没有任何内容,它可能 return 404 .
要测试问题是否是我上面指定的问题,您有几种选择:
- 最简单的方法,删除
path: /my-nginx
,然后使用 path: /
。您还可以指定 pathType: Prefix
,这意味着与指定的子路径匹配的所有内容都将由服务提供。
- 添加一个重写目标,如果您想在与应用程序期望的路径不同的路径上提供服务,这是必需的。
添加类似于以下的注释:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-ingress
namespace: eshop-dev
annotations:
kubernetes.io/ingress.class: "nginx"
# this will rewrite request under / + second capture group
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: example.com
http:
paths:
# this will serve all paths under /my-nginx and capture groups for regex annotations
- path: /my-nginx(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: my-nginx
port:
number: 9443
tls:
- hosts:
- example.com
secretName: externaluicerts
- 将您的应用程序配置为知道它将在您想要的路径下提供服务。这通常是更好的方法,因为前端应用程序应该几乎总是在他们期望的路径下提供服务。
根据您发布的信息,我认为这个问题已经解决,您的设置 应该 有效。
如果您对重写目标或路径在 Ingress 中的工作方式感到好奇,这里有一些文档:
重写(https://kubernetes.github.io/ingress-nginx/examples/rewrite/#rewrite)
路径类型(https://kubernetes.io/docs/concepts/services-networking/ingress/#path-types)
更新
关于为什么将应用程序配置为直接在 Ingress 中指定的路径提供其内容(基本上是为了知道它将在哪个路径提供服务)是最好的解决方案:
假设您在 Pod 中提供一个复杂的应用程序,它将在 / 下提供其内容。主页会尝试加载其他几个资源,如 css、js 代码等,所有内容都来自根目录。基本上,如果我打开 /
,应用程序也会加载:
/example.js
/my-beautiful.css
现在,如果我在另一个路径的入口后面提供此应用程序,假设在 /test/
下使用重写目标 ,主页将会工作,因为:
/test/ --> / # this is my rewrite rule
但是随后,页面将请求 /example.js
,并且重写仅在一个方向上工作,因此浏览器将请求一个将进入 404 的资源,因为请求应该是 /test/example.js
(因为那样会重写以删除路径的 /test 部分)
因此,对于前端应用程序,重写目标可能还不够,主要是在应用程序请求具有绝对路径的资源时。仅使用 REST API 或单个请求,重写通常效果很好。
我正在尝试使用 Kubernetes Ingress Nginx 控制器和 运行 AWS EKS 中的一个简单的 nginx 服务器。
浏览器 (https) --> Route 53 (DNS) --> CLB --> nginx Ingress (终止 TLS) --> 服务 --> POD
但我在浏览器中收到 404 错误(url 使用:https://example.com/my-nginx):
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.19.10</center>
</body>
</html>
在入口日志中 (kubectl logs -n nginx-ingress nginx-ingress-nginx-controller-6db6f85bc4-mfpwx),我可以在下面看到:
192.168.134.181 - - [24/Apr/2021:19:02:01 +0000] "GET /my-nginx HTTP/2.0" 404 154 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:88.0) Gecko/20100101 Firefox/88.0" 219 0.002 [eshop-dev-my-nginx-9443 ] [] 192.168.168.105:80 154 0.000 404 42fbe692a032bb40bf193954526369cd
这是我的部署 yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
namespace: eshop-dev
spec:
selector:
matchLabels:
run: my-nginx
replicas: 2
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- name: my-nginx
image: nginx
ports:
- containerPort: 80
服务 yaml:
apiVersion: v1
kind: Service
metadata:
namespace: eshop-dev
name: my-nginx
spec:
selector:
run: my-nginx
ports:
- name: server
port: 9443
targetPort: 80
protocol: TCP
和入口 yaml:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-ingress
namespace: eshop-dev
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: example.com
http:
paths:
- path: /my-nginx
pathType: ImplementationSpecific
backend:
service:
name: my-nginx
port:
number: 9443
tls:
- hosts:
- example.com
secretName: externaluicerts
我已验证服务 returns 与端口转发一起使用时所需的输出:
kubectl -n eshop-dev port-forward service/my-nginx 9443:9443
不知道是不是ingress配置不对还是另外一个problem.Thanks提前求助!
nginx-port-forward
这是 kubectl get ingress -n eshop-dev test-ingress -o yaml 的输出
kubectl get ingress -n eshop-dev test-ingress -o yaml
Warning: extensions/v1beta1 Ingress is deprecated in v1.14+, unavailable in v1.22+; use networking.k8s.io/v1 Ingress
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"networking.k8s.io/v1","kind":"Ingress","metadata":{"annotations":{"kubernetes.io/ingress.class":"nginx"},"name":"test-ingress","namespace":"eshop-dev"},"spec":{"rules":[{"host":"example.com","http":{"paths":[{"backend":{"service":{"name":"my-nginx","port":{"number":9443}}},"path":"/my-nginx","pathType":"ImplementationSpecific"}]}}],"tls":[{"hosts":["example.com"],"secretName":"externaluicerts"}]}}
kubernetes.io/ingress.class: nginx
creationTimestamp: "2021-04-24T13:16:21Z"
generation: 13
managedFields:
- apiVersion: networking.k8s.io/v1beta1
fieldsType: FieldsV1
fieldsV1:
f:status:
f:loadBalancer:
f:ingress: {}
manager: nginx-ingress-controller
operation: Update
time: "2021-04-24T13:16:40Z"
- apiVersion: extensions/v1beta1
fieldsType: FieldsV1
fieldsV1:
f:metadata:
f:annotations: {}
manager: kubectl-client-side-apply
operation: Update
time: "2021-04-24T13:18:36Z"
- apiVersion: networking.k8s.io/v1
fieldsType: FieldsV1
fieldsV1:
f:metadata:
f:annotations:
f:kubectl.kubernetes.io/last-applied-configuration: {}
f:kubernetes.io/ingress.class: {}
f:spec:
f:rules: {}
f:tls: {}
manager: kubectl-client-side-apply
operation: Update
time: "2021-04-24T16:33:47Z"
name: test-ingress
namespace: eshop-dev
resourceVersion: "7555944"
selfLink: /apis/extensions/v1beta1/namespaces/eshop-dev/ingresses/test-ingress
uid: a7694655-20c6-48c7-8adc-cf3a53cf2ffe
spec:
rules:
- host: example.com
http:
paths:
- backend:
serviceName: my-nginx
servicePort: 9443
path: /my-nginx
pathType: ImplementationSpecific
tls:
- hosts:
- example.com
secretName: externaluicerts
status:
loadBalancer:
ingress:
- hostname: xxxxxxxxxxxxxxxxdc75878b2-433872486.eu-west-1.elb.amazonaws.com
从您发布的 nginx-port-forward 图片来看,我看到您直接在 localhost:9443
上,这意味着您尝试访问的 Nginx 服务器在 /
[ 下提供其内容=27=]
但是在入口定义中,您定义服务将由 path: /my-nginx
提供。这可能是问题所在,因为您请求的 https://example.com/my-nginx
基本上会转到 my-nginx:9443/my-nginx
,并且根据此服务背后的 Pod,如果该路径上没有任何内容,它可能 return 404 .
要测试问题是否是我上面指定的问题,您有几种选择:
- 最简单的方法,删除
path: /my-nginx
,然后使用path: /
。您还可以指定pathType: Prefix
,这意味着与指定的子路径匹配的所有内容都将由服务提供。 - 添加一个重写目标,如果您想在与应用程序期望的路径不同的路径上提供服务,这是必需的。
添加类似于以下的注释:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-ingress
namespace: eshop-dev
annotations:
kubernetes.io/ingress.class: "nginx"
# this will rewrite request under / + second capture group
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: example.com
http:
paths:
# this will serve all paths under /my-nginx and capture groups for regex annotations
- path: /my-nginx(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: my-nginx
port:
number: 9443
tls:
- hosts:
- example.com
secretName: externaluicerts
- 将您的应用程序配置为知道它将在您想要的路径下提供服务。这通常是更好的方法,因为前端应用程序应该几乎总是在他们期望的路径下提供服务。
根据您发布的信息,我认为这个问题已经解决,您的设置 应该 有效。
如果您对重写目标或路径在 Ingress 中的工作方式感到好奇,这里有一些文档:
重写(https://kubernetes.github.io/ingress-nginx/examples/rewrite/#rewrite)
路径类型(https://kubernetes.io/docs/concepts/services-networking/ingress/#path-types)
更新
关于为什么将应用程序配置为直接在 Ingress 中指定的路径提供其内容(基本上是为了知道它将在哪个路径提供服务)是最好的解决方案:
假设您在 Pod 中提供一个复杂的应用程序,它将在 / 下提供其内容。主页会尝试加载其他几个资源,如 css、js 代码等,所有内容都来自根目录。基本上,如果我打开 /
,应用程序也会加载:
/example.js
/my-beautiful.css
现在,如果我在另一个路径的入口后面提供此应用程序,假设在 /test/
下使用重写目标 ,主页将会工作,因为:
/test/ --> / # this is my rewrite rule
但是随后,页面将请求 /example.js
,并且重写仅在一个方向上工作,因此浏览器将请求一个将进入 404 的资源,因为请求应该是 /test/example.js
(因为那样会重写以删除路径的 /test 部分)
因此,对于前端应用程序,重写目标可能还不够,主要是在应用程序请求具有绝对路径的资源时。仅使用 REST API 或单个请求,重写通常效果很好。