NGINX Ingress与重写目标

46

我有一个pod可以响应对/api/的请求。

我想进行一个重写,其中对/auth/api/的请求将转到/api/。

使用Ingress(nginx),我认为可以使用ingress.kubernetes.io/rewrite-target:注释来做到这一点,就像这样:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: myapi-ing
  annotations:
    ingress.kubernetes.io/rewrite-target: /api
    kubernetes.io/ingress.class: "nginx"
spec:
  rules:
  - host: api.myapp.com
    http:
      paths:
      - path: /auth/api
        backend:
          serviceName: myapi
          servicePort: myapi-port

然而正在发生的事情是/auth/被传递到了服务/容器中,因此正确地抛出了404错误。我可能误解了重写注释。

是否有一种通过k8s和Ingress来实现这一点的方法?

3个回答

55

我不知道这是否仍然是一个问题,但自版本0.22以来,似乎需要使用捕获组将值传递给rewrite-target值。可以在此处找到nginx示例。

从版本0.22.0开始,使用注释nginx.ingress.kubernetes.io/rewrite-target的Ingress定义与之前的版本不兼容。在版本0.22.0及以上版本中,需要显式地定义在请求URI中需要传递到重写路径的任何子字符串,必须在捕获组中进行。

根据你的具体需求,类似于下面的代码应该能解决问题:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: myapi-ing
annotations:
  ingress.kubernetes.io/rewrite-target: /api/$2
  kubernetes.io/ingress.class: "nginx"
spec:
 rules:
 - host: api.myapp.com
   http:
    paths:
     - path: /auth/api(/|$)(.*)
       backend:
         serviceName: myapi
         servicePort: myapi-port

谢谢,我必须使用新的 apiVersion: networking.k8s.io/v1beta1nginx.ingress.kubernetes.io/rewrite-target - StackEng2010
非常感谢,这是一个简单而优秀的解决方案。 - Sriharsha Kalluru

34

我创建了以下示例,它可以工作并且我将解释它。要运行这个最小化的示例,请运行以下命令:


我已经创建了一个可以运行的示例,接下来我会进行解释。要运行这个最小化的示例,请运行以下命令:
$ minikube start  
$ minikube addons enable ingress # might take a while for ingress pod to bootstrap  
$ kubectl apply -f kubernetes.yaml 
$ curl https://$(minikube ip)/auth/api/ --insecure
success - path: /api/
$ curl https://$(minikube ip)/auth/api --insecure
failure - path: /auth/api
$ curl https://$(minikube ip)/auth/api/blah/whatever --insecure
success - path: /api/blah/whatever

您会注意到,入口重写注释对末尾斜杠非常敏感。如果没有末尾斜杠,请求将不会被重写。然而,如果提供了末尾斜杠,请求URI将被重写,您的代理就会按预期工作。

在检查来自入口控制器内部的生成的nginx.conf文件后,负责此行为的代码行是:

rewrite /auth/api/(.*) api/$1 break;

这行代码告诉我们只有与第一个参数匹配的请求才会被重写为第二个参数指定的路径。

我认为这是一个值得解决的错误。

kubernetes.yaml

---
apiVersion: v1
kind: Service
metadata:
  name: ingress-rewite-example
spec:
  selector:
    app: ingress-rewite-example
  ports:
  - name: nginx
    port: 80
    protocol: TCP
    targetPort: 80
  type: NodePort

---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: ingress-rewite-example
spec:
  template:
    metadata:
      labels:
        app: ingress-rewite-example
    spec:
      containers:
      - name: ingress-rewite-example
        image: fbgrecojr/office-hours:so-47837087
        imagePullPolicy: Always
        ports:
        - containerPort: 80

---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-rewite-example
  annotations:
    ingress.kubernetes.io/rewrite-target: /api
    kubernetes.io/ingress.class: "nginx"
spec:
  rules:
  - http:
      paths:
      - path: /auth/api
        backend:
          serviceName: ingress-rewite-example
          servicePort: 80

main.go

package main

import (
  "fmt"
  "strings"
  "net/http"
)

func httpHandler(w http.ResponseWriter, r *http.Request) {
  var response string
  if strings.HasPrefix(r.URL.Path, "/api") {
    response = "success"
  } else {
    response = "failure"
  }
  fmt.Fprintf(w, response + " - path: " + r.URL.Path + "\n")
}

func main() {
    http.HandleFunc("/", httpHandler)
    panic(http.ListenAndServe(":80", nil))
}

有趣的是 - 如果我在URL上添加:curl https:// $(minikube IP)/ auth / api / blah / whatever它也不会捕获 - matt
@matt 你在评论中提供的示例是正确的(请参见我的更新示例)。请注意,我正在运行NGINX Ingress控制器的0.9.0-beta.15版本和Kubernetes的v1.8.0版本。 - frankgreco
嗨,你在哪里找到nginx.conf文件的?干杯。 - gxvigo
@GiovanniVigorelli k8s Ingress控制器的工作方式是每次添加新的Ingress资源时动态重新创建nginx.conf。因此,要查看配置,请在原始问题中应用Ingress资源,然后执行nginx Ingress控制器pod并输出当前nginx.conf的内容。 - frankgreco
在版本nginx-ingress-1.4.0中,您必须指定nginx.ingress.kubernetes.io/rewrite-target: /api(请注意前缀nginx.)。 - Gabriel Avellaneda
@GiovanniVigorelli 换句话说,执行 "kubectl exec -n NAMESPACE PODNAME cat /etc/nginx/nginx.conf" 命令。 - Fumisky Wells

2

可以使用configuration-snippet注释:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: myapi-ing
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/configuration-snippet: |
      rewrite ^/auth/api/(.*) /api/$1 break;
spec:
  rules:
  - host: api.myapp.com
    http:
      paths:
      - path: /auth/api
        backend:
          serviceName: myapi
          servicePort: myapi-port

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接