如何解决AWS EKS 集群中的 TLS nginx 入口导致 404 Not Found
我正在尝试使用 Kubernetes Ingress Nginx 控制器并在 AWS EKS 中运行一个简单的 Nginx 服务器。
浏览器(https) --> Route 53 (DNS) --> CLB --> Nginx Ingress (Terminate TLS) --> Service --> POD
但我在浏览器中收到 404 错误(使用的网址: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 42f3526392fbe26325cb5b63925cb5b693
这是我的部署 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
我已验证服务在与端口转发一起使用时返回所需的输出:
kubectl -n eshop-dev port-forward service/my-Nginx 9443:9443
我不确定入口是否配置不正确,还是其他问题。提前感谢您的帮助!
这里是 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 服务器在 /
下提供其内容
但在入口定义中,您定义服务将由 path: /my-nginx
提供。这可能是问题所在,因为您请求的 https://example.com/my-nginx
基本上会转到 my-nginx:9443/my-nginx
,并且根据此服务背后的 Pod,如果该路径上没有任何内容,它可能会返回 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: /$2
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 或单个请求,重写通常效果很好。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。