【问题标题】:TLS nginx ingress in AWS EKS Cluster results in 404 Not FoundAWS EKS 集群中的 TLS nginx 入口导致 404 Not Found
【发布时间】:2021-07-18 15:40:12
【问题描述】:

我正在尝试使用 Kubernetes Ingress Nginx 控制器并在 AWS EKS 中运行一个简单的 nginx 服务器。

浏览器 (https) --> Route 53 (DNS) --> CLB --> nginx Ingress (Terminate TLS) --> 服务 --> 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 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

我已验证服务在与端口转发一起使用时返回所需的输出:

kubectl -n eshop-dev port-forward service/my-nginx 9443:9443

我不确定入口是否配置错误,或者是否是另一个问题。提前感谢您的帮助!

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

【问题讨论】:

  • 欢迎来到 StackOverflow!入口 port.number 似乎有太多缩进,不确定这是否是问题。能否请您发布 k get ingress -n eshop-dev test-ingress -oyaml 的结果?
  • 谢谢,我已经编辑了原始帖子以包含 k get ingress -n eshop-dev test-ingress -o yaml 的输出。输出太长,不允许我发表评论。
  • 谢谢!我添加了一个我认为可能是问题和解决方案的答案。让我知道它是否有效。

标签: kubernetes https kubernetes-ingress amazon-eks nginx-ingress


【解决方案1】:

从您发布的 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,这意味着与指定的 subPath 匹配的所有内容都将由服务提供。
  • 添加重写目标,如果您希望在与应用程序预期路径不同的路径上提供服务,则必须这样做。

添加类似如下的注解:

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 或单个请求,重写通常效果很好。

【讨论】:

  • 非常感谢@AndD!!!正如你提到的,我应用了带有重写目标的入口,它就像魅力一样工作:)干杯!!!
  • 太棒了!考虑到在为前端应用程序提供服务时,重写可能不是最佳解决方案,这取决于相关应用程序是否发出绝对路径请求。我添加了一个例子来解释这个问题。对于前端应用程序,最好将应用程序配置为在 Ingress 中指定的子路径处提供服务
  • 实际上,很少有其他应用程序将从同一个 k8 集群中提供服务。每个应用程序都有自己的子路径,例如:/my-nginx /test-app /order-app 等。我需要在 React 中创建一个前端应用程序,需要在路径 /test-app提供服务>
  • 我明白了。我们也使用相同的设置,但是对于 Angular 应用程序,我们只是构建应用程序以知道它们将在 Ingress 中的预期路径下提供服务,以防止 Ingress 路径出现任何问题(通常在构建过程中要传递一个参数,我思考)。但这取决于应用程序以及它是否请求具有绝对路径或相对路径的资源。我只是想清楚你将来可能会遇到这个问题xD。另一种解决方案是使用子域。我猜有很多解决方案
  • 是的,非常感谢您的提醒。它非常有帮助。
猜你喜欢
  • 1970-01-01
  • 2021-12-03
  • 1970-01-01
  • 2021-12-27
  • 2022-08-02
  • 1970-01-01
  • 2021-09-14
  • 1970-01-01
  • 2018-12-27
相关资源
最近更新 更多