【问题标题】:How to redirect URL based on http header in nginx ingress?如何根据 nginx 入口中的 http 标头重定向 URL?
【发布时间】:2020-08-03 15:24:47
【问题描述】:

我的请求是通过 Cloudflare 代理的,它根据 IP 地址在 http 标头中设置一个标头来指示国家/地区。我想根据 Nginx 入口控制器中的此标头重定向具有某些路径的请求。我该怎么做?

【问题讨论】:

  • 您好,您能否澄清一下您是尝试通过指向一个 svc 的标头“重写”请求,还是尝试通过标头将此请求路由到不同的 svc?请看这里:stackoverflow.com/questions/26223733/…。同样作为解决方案的指针,Traefik 和 Ambassador 可以选择运行基于标头的路由。
  • 谢谢@Dawid。我希望根据标头重写对一堆 SVC 的请求。该问题中建议的答案是我目前在 Nginx 中是如何做的。但想知道如何在Ingress 资源定义中实现它。看起来我需要在 Nginx Ingress Controller 的 http-snippet 配置中定义一个带有重定向 URL 的映射,然后在 Ingress resource 中使用 nginx.ingress.kubernetes.io/configuration-snippetnginx.ingress.kubernetes.io/server-snippet 进行重定向。不知道 Traefik 和 Ambassador 有这个选项。谢谢,会去看看。

标签: google-kubernetes-engine kubernetes-ingress nginx-ingress


【解决方案1】:

目前nginx-ingressIngress 资源定义不支持基于标头的路由。

我找到了一个解决方法,可以通过请求的标头(我已包含以下步骤)路由请求,并带有以下注释:

    nginx.ingress.kubernetes.io/configuration-snippet: |
      if ($http_LocationHeader = "PL") { proxy_pass http://goodbye-service.default.svc.cluster.local:5678; }

其他可能的解决方案/解决方法:


关于解决方法

假设(例如目的):

  • 有 2 个部署:hello,goodbye
  • 两者都与它们的服务相关联,名称为:hello-servicegoodbye-service

Ingress 资源将以hello 应始终响应的方式配置,但添加configuration-snippet 后,流量将重定向到goodbye

此部署的响应:

|     hello      |    goodbye     |
|----------------|----------------|
| Hello, world!  | Hello, world!  |
| Version: 2.0.0 | Version: 1.0.0 | # notice the version

带有附加服务的hello 部署示例:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello
spec:
  selector:
    matchLabels:
      app: hello
  replicas: 1
  template:
    metadata:
      labels:
        app: hello
    spec:
      containers:
      - name: hello
        image: "gcr.io/google-samples/hello-app:2.0"
        env:
        - name: "PORT"
          value: "50001"
---
apiVersion: v1
kind: Service
metadata:
  name: hello-service
spec:
  selector:
    app: hello
  ports:
    - name: hello-port
      port: 5678 # IMPORTANT
      targetPort: 50001
  type: NodePort

要获得goodbye 部署,请将hello 替换为goodbye,并将映像版本更改为1.0

通过标头重新路由请求的入口定义如下所示:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: hello-ingress 
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/configuration-snippet: |
      if ($http_LocationHeader = "PL") { proxy_pass http://goodbye-service.default.svc.cluster.local:5678; }
spec:
  rules:
  - host: 
    http:
      paths:
      - path: /
        backend:
          serviceName: hello-service 
          servicePort: hello-port

默认情况下,这个没有configuration-snippet 的 Ingress 定义将始终将流量路由到 hello-service,然后再路由到 hello pod。通过添加:

    nginx.ingress.kubernetes.io/configuration-snippet: |
      if ($http_LocationHeader = "PL") { proxy_pass http://goodbye-service.default.svc.cluster.local:5678; }

它将检查名为LocationHeader 的标头是否存在以及是否与PL 匹配。如果是,它将通过其 DNS 名称将请求发送到goodbye-service

专注于:

  • http://goodbye-service.default.svc.cluster.local:5678
  • http://service_name.namespace.svc.cluster.local:port(没有值的 DNS 名称)

应用此Ingress 资源后,您应该能够使用LocationHeader=PL 发送请求(例如使用Postman)并获得响应:

Hello, world!
Version: 1.0.0
Hostname: goodbye-5758448754-wr64c

当我尝试使用 map 指令时,我收到以下消息:

  • nginx: [emerg] "map" directive is not allowed here in /tmp/nginx-OMMITED

【讨论】:

  • 感谢@Dawid 的详细回答。我能够使用configuration-snippet 实现这一目标。至于地图,在 serverlocation 上下文中是不允许的,这就是您看到错误的原因。它必须在部署 NGINX 入口控制器时使用 http-snippet 注入。
猜你喜欢
  • 2014-12-01
  • 2016-06-22
  • 2016-06-01
  • 2020-11-07
  • 1970-01-01
  • 2022-07-21
  • 1970-01-01
  • 2018-07-11
  • 1970-01-01
相关资源
最近更新 更多