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