GKE 上的 nginx-ingress 无法路由到配置服务的路径

时间:2021-04-14 21:23:10

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

我正在尝试为 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

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

为了确保我配置的 <MY_STATIC_IP_ADDRESS> 正确绑定到 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 上正确注册: enter image description here

这是显示在我的 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 在评论部分分享的材料后,我得到了一个可以工作的配置。

我没有使用官方 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>

1 个答案:

答案 0 :(得分:1)

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

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

另一方面,似乎是与Rewrite target注解的定义有关的问题。根据{{​​3}}:

<块引用>

从 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 -

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