web-dev-qa-db-fra.com

entrée nginx et cible de réécriture

J'ai un pod qui répond aux demandes de/api /

Je veux faire une réécriture où les demandes de/auth/api/aller à/api /.

En utilisant un Ingress (nginx), j'ai pensé qu'avec l'annotation ingress.kubernetes.io/rewrite-target: je pouvais faire quelque chose comme ceci:

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

Ce qui se passe cependant, c'est que/auth/est passé au service/pod et un 404 est lancé à juste titre. Je dois mal comprendre l'annotation de réécriture.

Existe-t-il un moyen de le faire via k8s et entrées?

8
matt

J'ai créé l'exemple suivant qui fonctionne et que je vais expliquer. Pour exécuter cet exemple minimal, exécutez ces commandes:

$ 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

Comme vous le remarquerez, l'annotation de réécriture d'entrée semble être très particulière à propos des barres obliques de fin. Si une barre oblique de fin n'est pas présente, la demande ne sera pas réécrite. Cependant, si une barre oblique de fin est fournie, l'URI de demande sera réécrit et votre proxy fonctionnera comme prévu.

Après avoir inspecté le fichier nginx.conf Généré depuis l'intérieur du contrôleur d'entrée, la ligne de code responsable de ce comportement est:

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

Cette ligne nous indique que seules les demandes correspondant au premier argument seront réécrites avec le chemin spécifié par le deuxième argument.

Je pense que cela en vaut la peine.

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))
}
16
frankgreco

Je ne sais pas si c'est toujours un problème, mais depuis la version 0.22, il semble que vous ayez besoin d'utiliser des groupes de capture pour passer des valeurs à la valeur de réécriture-cible De l'exemple nginx disponible ici

À partir de la version 0.22.0, les définitions d'entrée utilisant l'annotation nginx.ingress.kubernetes.io/rewrite-target ne sont pas rétrocompatibles avec les versions précédentes. Dans la version 0.22.0 et au-delà, toutes les sous-chaînes de l'URI de demande qui doivent être transmises au chemin réécrit doivent être explicitement définies dans un groupe de capture.

Pour vos besoins spécifiques, quelque chose comme ça devrait faire l'affaire

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
9
Kerruba