【问题标题】:app on path instead of root not working for Kubernetes Ingress路径上的应用程序而不是 root 不适用于 Kubernetes Ingress
【发布时间】:2020-06-21 08:43:09
【问题描述】:

我在使用 K8s Ingress 时遇到问题,我将在这里使用假示例来说明我的观点。 假设我有一个名为 Tweeta 的应用程序,而我的公司名为 ABC。我的应用程序目前位于 tweeta.abc.com 上。 但我们想将我们的应用迁移到 app.abc.com/tweeta。

我目前在 K8s 的入口如下:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: tweeta-ingress
spec:
  rules:
  - host: tweeta.abc.com
    http:
      paths:
      - path: /
        backend:
          serviceName: tweeta-frontend
          servicePort: 80
      - path: /api
        backend:
          serviceName: tweeta-backend
          servicePort: 80

为了迁移,我添加了第二个入口:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: tweeta-ingress-v2
spec:
  rules:
  - host: app.abc.com
    http:
      paths:
      - path: /tweeta
        backend:
          serviceName: tweeta-frontend
          servicePort: 80
      - path: /tweeta/api
        backend:
          serviceName: tweeta-backend
          servicePort: 80

为了保持连续性,我希望有 2 个入口同时指向我的服务。当新域准备就绪并可以工作时,我只需要拆除旧入口即可。

但是,我对这个入口的新域没有任何运气。是不是因为它托管在路径上,而 k8s 入口需要托管在 root 上?还是我需要在 nginx 端做的配置?

【问题讨论】:

  • 问题很可能是因为有两个 Ingress 资源用于相同的后端服务。您是否尝试过只有一个入口资源?还共享入口控制器 pod 的日志。您是否收到 404 错误?

标签: nginx kubernetes kubernetes-ingress


【解决方案1】:

根据我的尝试,我无法重现您的问题。所以我决定描述我是如何尝试重现它的,这样您就可以按照相同的步骤进行操作,并根据失败的位置/如果失败,我们可以找到导致问题的原因。

首先,确保您使用的是NGINX Ingress,因为它更强大。

我按照以下步骤使用 Helm 安装了 NGINX Ingress:

$ curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash
$ helm repo add stable https://kubernetes-charts.storage.googleapis.com
$ helm repo update
$ helm install nginx-ingress stable/nginx-ingress

对于部署,我们将使用来自here 的示例。

部署一个 hello, world 应用程序

  1. 使用以下命令创建部署:

    kubectl create deployment web --image=gcr.io/google-samples/hello-app:1.0
    

    输出:

    deployment.apps/web created
    
  2. 公开部署:

    kubectl expose deployment web --type=NodePort --port=8080
    

    输出:

    service/web exposed
    

创建第二个部署

  1. 使用以下命令创建 v2 部署:

    kubectl create deployment web2 --image=gcr.io/google-samples/hello-app:2.0
    

    输出:

    deployment.apps/web2 created
    
  2. 公开部署:

    kubectl expose deployment web2 --port=8080 --type=NodePort
    

    输出:

    service/web2 exposed
    

此时我们已经运行了部署和服务:

$ kubectl get deployments.apps 
NAME                            READY   UP-TO-DATE   AVAILABLE   AGE
web                             1/1     1            1           24m
web2                            1/1     1            1           22m
$ kubectl get service
NAME                            TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGE
kubernetes                      ClusterIP      10.96.0.1        <none>        443/TCP                      5d5h
nginx-ingress-controller        LoadBalancer   10.111.183.151   <pending>     80:31974/TCP,443:32396/TCP   54m
nginx-ingress-default-backend   ClusterIP      10.104.30.84     <none>        80/TCP                       54m
web                             NodePort       10.102.38.233    <none>        8080:31887/TCP               24m
web2                            NodePort       10.108.203.191   <none>        8080:32405/TCP               23m

对于入口,我们将使用问题中提供的入口,但我们必须更改后端:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: tweeta-ingress
spec:
  rules:
  - host: tweeta.abc.com
    http:
      paths:
      - path: /
        backend:
          serviceName: web
          servicePort: 8080
      - path: /api
        backend:
          serviceName: web2
          servicePort: 8080          
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: tweeta-ingress-v2
spec:
  rules:
  - host: app.abc.com
    http:
      paths:
      - path: /tweeta
        backend:
          serviceName: web
          servicePort: 8080
      - path: /tweeta/api
        backend:
          serviceName: web2
          servicePort: 8080     

现在让我们测试一下我们的入口:

$ curl tweeta.abc.com
Hello, world!
Version: 1.0.0
Hostname: web-6785d44d5-j8bgk

$ curl tweeta.abc.com/api
Hello, world!
Version: 2.0.0
Hostname: web2-8474c56fd-lx55n

$ curl app.abc.com/tweeta
Hello, world!
Version: 1.0.0
Hostname: web-6785d44d5-j8bgk

$ curl app.abc.com/tweeta/api
Hello, world!
Version: 2.0.0
Hostname: web2-8474c56fd-lx55n

可以看出,在您的入口中没有任何模组的情况下一切正常。

【讨论】:

  • 感谢您的帮助。我的tweeta-ingress 在此之前已经在生产中工作了。你说的“没有这个注释甚至 /api 都不能工作”是什么意思?
  • 您是否尝试过关注和使用注释?我的意思是,对我来说 /api 没有注释就无法工作,但我将它发送到同一个后端。
  • 试过但没用 :( 不过还是谢谢你。旧入口从一开始就工作。不知道为什么在路径上托管我的应用程序会给我带来问题:(
  • 我正在使用 nginx 控制器。我正在使用一个反应应用程序。是不是因为默认在 root 上响应主机?
  • 感谢您为此付出的努力。到目前为止,我仍然没有任何进展。可能是我必须与我的平台架构师核实的基础设施问题。
【解决方案2】:

我假设您的前端 Pod 期望路径 / 而后端 Pod 期望路径 /api

第一个入口配置不转换请求,它按原样进入前端(Fpod)/后端(Bpod)Pod:

http://tweeta.abc.com/     -> ingress -> svc -> Fpod: [ http://tweeta.abc.com/    ] 
http://tweeta.abc.com/api  -> ingress -> svc -> Bpod: [ http://tweeta.abc.com/api ] 

但在第二次入口时,它不能按预期工作:

http://app.abc.com/tweeta      -> ingress -> svc -> Fpod: [ http://app.abc.com/tweeta    ] 
http://app.abc.com/tweeta/api  -> ingress -> svc -> Bpod: [ http://app.abc.com/tweeta/api    ] 

Pod 请求路径从/ 更改为/tweeta,从/api 更改为/tweeta/api。我想这不是预期的行为。通常 Pods 中的应用程序不关心 Host 标头,但 Path 必须是正确的。如果您的 Pod 并非设计为响应额外的 tweeta\ 路径,则它们可能会在使用第二个入口时响应 404 (Not Found)

要修复它,您必须添加 rewrite annotation 以从 Pod 的请求中删除 tweeta 路径:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: tweeta-ingress-v2
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
  rules:
  - host: app.abc.com
    http:
      paths:
      - path: /tweeta(/|$)(.*)
        backend:
          serviceName: tweeta-frontend
          servicePort: 80
      - path: /tweeta(/)(api$|api/.*)
        backend:
          serviceName: tweeta-backend
          servicePort: 80

结果将如下所示,这正是它假设的工作方式:

http://app.abc.com/tweeta            -> ingress -> svc -> Fpod: [ http://app.abc.com/    ] 
http://app.abc.com/tweeta/blabla     -> ingress -> svc -> Fpod: [ http://app.abc.com/blabla    ] 

http://app.abc.com/tweeta/api        -> ingress -> svc -> Bpod: [ http://app.abc.com/api    ] 
http://app.abc.com/tweeta/api/blabla -> ingress -> svc -> Bpod: [ http://app.abc.com/api/blabla    ] 

要检查入口控制器日志和相应的配置使用:

$ kubectl logs -n ingress-controller-namespace ingress-controller-pods-name

$ kubectl exec -it -n ingress-controller-namespace ingress-controller-pods-name -- cat /etc/nginx/nginx.conf > local-file-name.txt && less local-file-name.txt

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-11-13
    • 2019-01-16
    • 2020-07-02
    • 1970-01-01
    • 2021-08-07
    • 2020-07-11
    • 1970-01-01
    • 2021-05-15
    相关资源
    最近更新 更多