kubernetes nginx 入口控制器 return 404

kubernetes nginx ingress controller return 404

按照这个 guide,我在本地 kubernetes 服务器上创建了一个入口控制器,唯一的区别是它是作为 NodePort 创建的。

我已经完成了一些测试部署,使用各自的服务并且一切正常,这里是文件

部署 1:

apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
  name: helloworld1
spec:
  selector:
    matchLabels:
      app: helloworld1
  replicas: 1
  template:
    metadata:
      labels:
        app: helloworld1
    spec:
      containers:
      - name: hello
        image: gcr.io/google-samples/hello-app:1.0
        ports:
        - containerPort: 8080

部署2:

apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
  name: helloworld2
spec:
  selector:
    matchLabels:
      app: helloworld2
  replicas: 1
  template:
    metadata:
      labels:
        app: helloworld2
    spec:
      containers:
      - name: hello
        image: gcr.io/google-samples/hello-app:2.0
        ports:
        - containerPort: 8080

部署 3:

apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
  name: geojson-example
spec:
  selector:
    matchLabels:
      app: geojson-example
  replicas: 1
  template:
    metadata:
      labels:
        app: geojson-example
    spec:
      containers:
        - name: geojson-container
          image: "nmex87/geojsonexample:latest"
          ports:
            - containerPort: 8080

服务 1:

apiVersion: v1
kind: Service
metadata:
  name: helloworld1
spec:
#  type: NodePort
  ports:
  - port: 8080
  selector:
    app: helloworld1

服务 2:

apiVersion: v1
kind: Service
metadata:
  name: helloworld2
spec:
#  type: NodePort
  ports:
  - port: 8080
  selector:
    app: helloworld2

服务 3:

apiVersion: v1
kind: Service
metadata:
  name: geojson-example
spec:
  ports:
    - port: 8080
  selector:
    app: geojson-example

这是入口控制器:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: test-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/default-backend: geojson-example
spec:
  rules:
    - http:
        paths:
          - path: /geo
            pathType: Prefix
            backend:
              service:
                name: geojson-example
                port:
                  number: 8080
          - path: /test1
            pathType: Prefix
            backend:
              service:
                name: helloworld1
                port:
                  number: 8080
          - path: /test2
            pathType: Prefix
            backend:
              service:
                name: helloworld2
                port:
                  number: 8080

当我在 myServer:myPort/test1/test2 上执行 GET 时,一切正常,在 /geo 我得到以下答案

{
    "timestamp": "2021-03-09T17:02:36.606+00:00",
    "status": 404,
    "error": "Not Found",
    "message": "",
    "path": "/geo"
}

为什么?? 如果我创建一个 pod,并从 pod 内部,我在 geojson-example 上卷曲它有效,但从外部,我获得 404(我认为通过 nginx 入口控制器)

这是 nginx pod 的日志:

x.x.x.x - - [09/Mar/2021:17:02:21 +0000] "GET /test1 HTTP/1.1" 200 68 "-" "PostmanRuntime/7.26.8" 234 0.006 [default-helloworld1-8080] [] 192.168.168.92:8080 68 0.008 200 

x.x.x.x - - [09/Mar/2021:17:02:36 +0000] "GET /geo HTTP/1.1" 404 116 "-" "PostmanRuntime/7.26.8" 232 0.013 [default-geojson-example-8080] [] 192.168.168.109:8080 116 0.012 404 

我能做什么?

这是您的默认后端。您将 geojson-example 服务设置为默认后端。

The default backend is a service which handles all URL paths and hosts the nginx controller doesn't understand (i.e., all the requests that are not mapped with an Ingress).

Basically a default backend exposes two URLs:

/healthz that returns 200
/ that returns 404

因此,如果您希望将 geojson-example 服务作为默认后端,则不需要 /geo 路径规范。那么您的清单文件将是:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: test-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/default-backend: geojson-example
spec:
  rules:
    - http:
        paths:
          - path: /test1
            pathType: Prefix
            backend:
              service:
                name: helloworld1
                port:
                  number: 8080
          - path: /test2
            pathType: Prefix
            backend:
              service:
                name: helloworld2
                port:
                  number: 8080

或者,如果您希望 geojson-example 作为入口有效路径,则必须删除默认后端注释。那么您的清单文件将是:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: test-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
spec:
  rules:
    - http:
        paths:
          - path: /geo
            pathType: Prefix
            backend:
              service:
                name: geojson-example
                port:
                  number: 8080
          - path: /test1
            pathType: Prefix
            backend:
              service:
                name: helloworld1
                port:
                  number: 8080
          - path: /test2
            pathType: Prefix
            backend:
              service:
                name: helloworld2
                port:
                  number: 8080

就文档而言:此注释的形式为 nginx.ingress.kubernetes.io/default-backend: <svc name> 以指定自定义默认后端。此 <svc name> 是对您在其中应用此注释的同一命名空间内的服务的引用。此注释覆盖全局默认后端。

当 Ingress 规则中的服务没有活动端点时,此服务将处理响应。

您不能将相同的服务用作默认后端,也不能用于路径。当您这样做时,路径 /geo 变得无效。正如我们所知,默认后端仅服务于非活动端点。现在如果你告诉你想要 geojson-example 作为默认后端(对于非活动端点)再次在路径中如果你告诉使用 geojson-example 作为有效路径 /geo 那么它就变得无效了在这里创建一个死锁类型的情况。

您实际上不需要提供此 nginx.ingress.kubernetes.io/default-backend 注释。

你的入口应该像下面没有默认注释的那样,或者你可以使用注释但在那种情况下你需要删除 geojson-example 用于路径中的任何有效路径,或者需要使用另一个路径 /geo 的服务。您可以使用的选项如下:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: test-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
spec:
  rules:
    - http:
        paths:
          - path: /geo
            pathType: Prefix
            backend:
              service:
                name: geojson-example
                port:
                  number: 8080
          - path: /test1
            pathType: Prefix
            backend:
              service:
                name: helloworld1
                port:
                  number: 8080
          - path: /test2
            pathType: Prefix
            backend:
              service:
                name: helloworld2
                port:
                  number: 8080

或者:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: test-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/default-backend: geojson-example
spec:
  rules:
    - http:
        paths:
          - path: /geo
            pathType: Prefix
            backend:
              service:
                name: <any_other_service>    # here use another service except `geojson-example`
                port:
                  number: 8080
          - path: /test1
            pathType: Prefix
            backend:
              service:
                name: helloworld1
                port:
                  number: 8080
          - path: /test2
            pathType: Prefix
            backend:
              service:
                name: helloworld2
                port:
                  number: 8080

或者:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: test-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/default-backend: geojson-example
spec:
  rules:
    - http:
        paths:
          - path: /test1
            pathType: Prefix
            backend:
              service:
                name: helloworld1
                port:
                  number: 8080
          - path: /test2
            pathType: Prefix
            backend:
              service:
                name: helloworld2
                port:
                  number: 8080