【问题标题】:nginx-ingress on GKE fails to route to path for configured serviceGKE 上的 nginx-ingress 无法路由到配置服务的路径
【发布时间】:2021-07-09 22:45:46
【问题描述】:

我正在尝试为 GKE 集群配置 nginx 入口并在配置的子域上定义路径。似乎即使我能够成功 ping 主机,并且域绑定正确完成,但每当我尝试访问配置的路径时,我都会收到 404。

我的目标是能够为我的入口控制器配置一个静态 IP,并在不同路径上公开多个服务。

您可以在下面找到我的部署文件 - 我要补充的另一件事是,我正在使用 Terraform 自动配置和部署 GCP 和 Kubernetes 资源。

成功配置 GKE 集群后,我首先从 here 部署官方 nginx-ingress 控制器 - 在我的 Terraform 脚本下方,该脚本使用我在 GCP 上配置的自定义静态 IP 配置和部署控制器。

resource "helm_release" "nginx" {
  name  = "nginx"
  chart = "nginx-stable/nginx-ingress"
  timeout = 900

  set {
    name = "controller.stats.enabled"
    value = true
  }

  set {
    name  = "controller.service.type"
    value = "LoadBalancer"
  }

  set {
    name  = "controller.service.loadBalancerIP"
    value = "<MY_STATIC_IP_ADDRESS>"
  }
}

在我也通过 Terraform 部署的入口配置下方:

resource "kubernetes_ingress" "ingress" {
  wait_for_load_balancer = true

  metadata {
    name = "app-ingress"

    annotations = {
        "kubernetes.io/ingress.class": "nginx"
        "nginx.ingress.kubernetes.io/rewrite-target": "/"
        "kubernetes.io/ingress.global-static-ip-name": <MY_STATIC_IP_ADDRESS>
    }
  }

  spec {
    rule {
      host = custom.my_domain.com
      http {
        path {
          backend {
            service_name = "app-service"
            service_port = 5000
          }

          path = "/app"
        }
      }
    }
  }
}

以及从 GCP 获取的最终入口配置:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
    kubernetes.io/ingress.global-static-ip-name: static-ip-name
    nginx.ingress.kubernetes.io/rewrite-target: /
  creationTimestamp: "2021-04-14T20:28:41Z"
  generation: 7
  name: app-ingress
  namespace: default
  resourceVersion: HIDDEN
  selfLink: /apis/extensions/v1beta1/namespaces/default/ingresses/app-ingress
  uid: HIDDEN
spec:
  rules:
  - host: custom.my_domain.com
    http:
      paths:
      - backend:
          serviceName: app-service
          servicePort: 5000
        path: /app
status:
  loadBalancer:
    ingress:
    - ip: <MY_STATIC_IP_ADDRESS>

kubectl describe ingress app-ingress 命令的输出:

Name:             app-ingress
Namespace:        default
Address:          <MY_STATIC_IP_ADDRESS>
Default backend:  default-http-backend:80 (192.168.10.8:8080)
Rules:
  Host                  Path  Backends
  ----                  ----  --------
  custom.my_domain.com
                        /app   app-service:5000 (192.168.10.11:5000)
Annotations:            kubernetes.io/ingress.class: nginx
                        kubernetes.io/ingress.global-static-ip-name: static-ip-name
                        nginx.ingress.kubernetes.io/rewrite-target: /
Events:
  Type    Reason          Age                From                      Message
  ----    ------          ----               ----                      -------
  Normal  AddedOrUpdated  16m (x6 over 32m)  nginx-ingress-controller  Configuration for default/app-ingress was added or updated

我使用以下配置文件部署了我试图公开的应用程序:

pvc.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: app-pvc
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
  storageClassName: default

service.yaml

apiVersion: v1
kind: Service
metadata:
  name: app-service
spec:
  type: NodePort
  ports:
    - port: 5000
      targetPort: 5000
      protocol: TCP
      name: http

deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-deployment
spec:
  replicas: 1
  template:
    spec:
      restartPolicy: Always
      volumes:
        - name: app-pvc
          persistentVolumeClaim:
            claimName: app-pvc
      containers:
      - name: app-container
        image: "eu.gcr.io/<PROJECT_ID>/<IMAGE_NAME>:VERSION_TAG"
        imagePullPolicy: IfNotPresent
        ports:
          - containerPort: 5000
        livenessProbe:
          tcpSocket:
            port: 5000
          initialDelaySeconds: 10
          periodSeconds: 10
        readinessProbe:
          tcpSocket:
            port: 5000
          initialDelaySeconds: 15
          periodSeconds: 20
        volumeMounts:
          - mountPath: "/data"
            name: app-pvc

一切都成功部署,因为我可以通过运行以下命令通过配置的服务直接连接到本地应用程序:

kubectl port-forward service/app-service 5000:5000

这使我可以在浏览器中访问应用程序,一切都按预期工作。

为了确保我配置的 &lt;MY_STATIC_IP_ADDRESS&gt; 正确绑定到 custom.my_domain.com,我尝试 ping 主机并得到正确的响应:

ping custom.my_domain.com

Pinging custom.my_domain.com [<MY_STATIC_IP_ADDRESS>] with 32 bytes of data:
Reply from <MY_STATIC_IP_ADDRESS>: bytes=32 time=36ms TTL=113
Reply from <MY_STATIC_IP_ADDRESS>: bytes=32 time=37ms TTL=113
Reply from <MY_STATIC_IP_ADDRESS>: bytes=32 time=36ms TTL=113
Reply from <MY_STATIC_IP_ADDRESS>: bytes=32 time=45ms TTL=113

Ping statistics for <MY_STATIC_IP_ADDRESS>:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 36ms, Maximum = 45ms, Average = 38ms

即使一切似乎都按预期工作,每当我尝试在浏览器中导航到 custom.my_domain.com/app 时,我都会在浏览器中不断收到以下响应,即使在等待超过 30m 以确保入口配置已在 GCP 上正确注册:

这是显示在我的 nginx-controller pod 日志中的条目:

<HIDDEN_LOCAL_IP> - - [14/Apr/2021:21:18:10 +0000] "GET /app/ HTTP/1.1" 404 232 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:88.0) Gecko/20100101 Firefox/88.0" "-"

更新 #1

看来,如果我更新我的入口以直接在 / 路径上公开目标服务,它会按预期工作。下面是更新的配置。不过,如果我尝试设置任何其他路径,它似乎不起作用。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
    kubernetes.io/ingress.global-static-ip-name: static-ip-name
    nginx.ingress.kubernetes.io/rewrite-target: /
  creationTimestamp: "2021-04-14T20:28:41Z"
  generation: 7
  name: app-ingress
  namespace: default
  resourceVersion: HIDDEN
  selfLink: /apis/extensions/v1beta1/namespaces/default/ingresses/app-ingress
  uid: HIDDEN
spec:
  rules:
  - host: custom.my_domain.com
    http:
      paths:
      - backend:
          serviceName: app-service
          servicePort: 5000
        path: /
status:
  loadBalancer:
    ingress:
    - ip: <MY_STATIC_IP_ADDRESS>

更新 #2

在查看了 @jccampanero 在 cmets 部分分享的材料后,我能够得到一个工作配置。

我没有使用官方 nginx 网站上引用的nginx-stable,而是使用了here,并相应地更新了我的 Terraform 脚本,以使用与我完全相同的配置。

之后,我必须按照文档here 更新我的入口 - 在更新的配置下方:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
    kubernetes.io/ingress.global-static-ip-name: static-ip-name
    nginx.ingress.kubernetes.io/rewrite-target: /$2
  creationTimestamp: "2021-04-14T20:28:41Z"
  generation: 7
  name: app-ingress
  namespace: default
  resourceVersion: HIDDEN
  selfLink: /apis/extensions/v1beta1/namespaces/default/ingresses/app-ingress
  uid: HIDDEN
spec:
  rules:
  - host: custom.my_domain.com
    http:
      paths:
      - backend:
          serviceName: app-service
          servicePort: 5000
        path: /app(/|$)(.*)
status:
  loadBalancer:
    ingress:
    - ip: <MY_STATIC_IP_ADDRESS>

【问题讨论】:

  • 我认为问题可能与nginx.ingress.kubernetes.io/rewrite-target 注释有关。没有那个注释一切正常吗?可能不是,但正如您在docs 中看到的那样,从 Nginx 入口控制器的 0.22.0 版本开始,由于使用了捕获组,注释的行为发生了变化,这可能与您的问题有关。
  • 我最初尝试在没有该注释的情况下部署它,但行为完全相同。我已经浏览了您共享的文档,但找不到合适的解决方案。即使这不是我正在寻找的解决方案,我也在尝试的是为每个入口配置公开一个服务并使用多个静态 IP 地址,一个用于我公开的每个服务。这可能会导致将它们暴露在单个子域上。尽管如此,如前所述,这只是一个实验,看看我是否可以让入口在我的子域上工作。
  • @jccampanero 我刚刚尝试使用 nginx.ingress.kubernetes.io/app-root 注释重新部署整个堆栈,我得到了完全相同的行为。
  • 抱歉回复晚了,非常感谢您的反馈。很抱歉@vladzam,是的,nginx.ingress.kubernetes.io/app-root 注释可能对您的情况无效。我的意思是问题可能与nginx.ingress.kubernetes.io/rewrite-target 注释的定义有关,您提供的是'/',但可能需要提供/$1 之类的内容。我将尝试在我的本地环境中部署新版本的控制器并查看。无论如何,现在似乎有几个版本的 Nginx 入口控制器和其中一些(续)
  • 在某些情况下不要正确处理重写目标注释:请考虑阅读此相关SO question,以及linked GitHub issue,以及这两个12。除了提到的注释之外,我认为您的设置看起来不错:话虽如此,但我不想让您感到困惑,(续)

标签: nginx kubernetes networking google-cloud-platform nginx-ingress


【解决方案1】:

正如问题 cmets 和问题本身所指出的,@vladzam 很好地记录了问题的原因有两个。

一方面,通过 Helm stable 通道可用的 nginx 入口控制器似乎是 deprecated 支持新的 ingress-nginx 控制器 - 请参阅 the Github repoofficial documentation

另一方面,这似乎是与Rewrite target注解的定义有关的问题。根据docs

从版本 0.22.0 开始,使用注解 nginx.ingress.kubernetes.io/rewrite-target 的入口定义与以前的版本不向后兼容。在 0.22.0 及更高版本中,请求 URI 中需要传递到重写路径的任何子字符串都必须在捕获组中明确定义。

因此,有必要修改入口资源的定义以考虑此更改。例如:

$ echo '
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$2
  name: rewrite
  namespace: default
spec:
  rules:
  - host: rewrite.bar.com
    http:
      paths:
      - backend:
          serviceName: http-svc
          servicePort: 80
        path: /something(/|$)(.*)
' | kubectl create -f -

问题本身提供了准确的入口资源定义。

【讨论】:

    猜你喜欢
    • 2021-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-03
    • 2018-07-22
    • 2019-02-17
    • 1970-01-01
    • 2018-12-12
    相关资源
    最近更新 更多