【问题标题】:Headers based routing with Kubernetes使用 Kubernetes 进行基于标头的路由
【发布时间】:2019-11-28 01:33:07
【问题描述】:

假设我们有一个服务复制到几个 pod。对服务的第一个请求应该随机(或通过负载平衡算法)路由到 pod,并且应该以某种方式保存映射“value_of_certain_header -> pod_location”,以便将下一个请求路由到特定的 pod。

Kubernetes 是否有任何 Ingress 控制器或其他方法可以通过请求标头实现对特定 pod 的粘性?基本上,我需要与 haproxy 对其粘性表所做的相同行为。

【问题讨论】:

标签: kubernetes routing load-balancing


【解决方案1】:

Kubernetes Ingress 在 OSI Layer7 上工作,因此它可以考虑 HTTP 标头,但它只将流量转发到 Kubernetes 服务,而不是 Pod。

不幸的是,反过来,Kubernetes Services 无法根据 HTTP 标头将流量传递到特定的 Pod,因为 Service 基本上是一组 iptables 规则,将流量传递到 Pod,只分析 OSI Layer4 上的数据(IP 地址,tcp/udp , 端口号)。

以kube-dns服务iptables规则为例:

# kube-dns service
-A KUBE-SERVICES -d 10.96.0.10/32 -p udp -m comment --comment "kube-system/kube-dns:dns cluster IP" -m udp --dport 53 -j KUBE-SVC-TCOU7JCQXEZGVUNU 
# random load balancing traffic between pods
-A KUBE-SVC-TCOU7JCQXEZGVUNU -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-AALXN3QQZ3U27IAI
-A KUBE-SVC-TCOU7JCQXEZGVUNU -j KUBE-SEP-WTX2W5TQOZGP42TM
# dns pod 1
-A KUBE-SEP-AALXN3QQZ3U27IAI -p udp -m udp -j DNAT --to-destination 10.244.0.16:53
# dns pod 2
-A KUBE-SEP-WTX2W5TQOZGP42TM -p udp -m udp -j DNAT --to-destination 10.244.0.17:53

我只能想象一种基于 HTTP 标头将流量传送到特定 pod 的现实方法。

  1. 配置自定义 Ingress 控制器,该控制器可以为每个客户端会话设置标头,并使用 pod 的已知 DNS 名称作为后端目标点。我不能推荐特定的解决方案,所以在最坏的情况下,它可以使用some examples 创建。

  2. Kubernetes StatefulSet 创建具有可预测名称的 Pod,例如 statefulset-name-0、statefulset-name-1 等。对应的 Headless Service (ClusterIP: None) 为每个 Pod 创建 DNS 名称。

例如,对于具有三个副本的 StatefulSet nginx-ss,将创建三个 Pod,Service nginx-ss 将为 Pod 创建三个 DNS A 记录:

nginx-ss-0   1/1     Running     10.244.3.72    
nginx-ss-1   1/1     Running     10.244.3.73    
nginx-ss-2   1/1     Running     10.244.1.165   

nginx-ss-0.nginx-ss.default.svc.cluster.local. 5 IN A 10.244.3.72
nginx-ss-1.nginx-ss.default.svc.cluster.local. 5 IN A 10.244.3.73
nginx-ss-2.nginx-ss.default.svc.cluster.local. 5 IN A 10.244.1.165

【讨论】:

    【解决方案2】:

    假设 'pod_location' 被运行在该 pod 上的应用程序插入 HTML 标头,Ingress(和Ingress Controller)可用于实现基于标头的路由。

    例如,Traefik v2.0 具有名为 IngressRoute 的新自定义资源定义 (CRD),它扩展了 Ingress 规范并增加了对基于 Header 的路由等功能的支持。

    在以下示例中,我有两个服务:一个公开 Nginx 部署,另一个公开 Apache 部署。使用 IngressRoute CRD,路由器的匹配项将是标头 X-Route

    apiVersion: traefik.containo.us/v1alpha1 
    kind: IngressRoute 
    metadata: 
      name: headers 
    spec: 
      entrypoints: 
        - web 
        - websecure 
      routes: 
        - match: Headers(`X-ROUTE`,`Apache`) 
          kind: Rule 
          services: 
            - name: apache 
              port: 80 
        - match: Headers(`X-ROUTE`,`nginx`) 
          kind: Rule 
          services: 
            - name: nginx 
              port: 80
    

    完整的example

    使用 X-ROUTE: Apache 标头:

    curl http://46.101.68.190/ -H 'X-ROUTE: Apache' 
    html><body><h1>It works!</h1></body></html>
    

    带有 X-ROUTE: nginx 标头:

    > curl http://46.101.68.190/ -H 'X-ROUTE: nginx'
    <!DOCTYPE html>
    <html>
    <head>
    <title>Welcome to nginx!</title>
    ...and so on...
    

    Traefik 为他们的middleware 提供了配置示例的附加信息。

    【讨论】:

      【解决方案3】:

      如果您想确保来自特定客户端的连接每次都传递到同一个 Pod,您可以通过将 service.spec.sessionAffinity 设置为“ClientIP”(默认为“无”)在服务定义 YAML 中。

      您还可以通过适当地设置 service.spec.sessionAffinityConfig.clientIP.timeoutSeconds 来设置最大会话粘性时间。 (默认值为 10800,相当于 3 小时)

      【讨论】:

      • 感谢您的回复。但我仍然需要通过特定的标头来识别客户端
      猜你喜欢
      • 2022-08-18
      • 1970-01-01
      • 1970-01-01
      • 2016-06-24
      • 2020-12-16
      • 2017-01-14
      • 1970-01-01
      • 2021-08-02
      • 1970-01-01
      相关资源
      最近更新 更多