如何从Kubernetes服务后面的HTTP请求中读取客户端IP地址?

Mar*_*ina 18 http kubernetes

我的Web应用程序作为SSL的nginx反向代理后面的Kubernetes pod运行.无论是代理和我的应用程序使用Kubernetes的负载均衡服务(如描述在这里).

问题是我的所有HTTP请求日志只显示内部群集IP地址,而不是实际HTTP客户端的地址.有没有办法让Kubernetes服务将这些信息传递给我的应用服务器?

Pra*_*h B 7

您可以通过两种方式将 kube-proxy 完全排除在循环之外:

  1. 使用 Ingress 配置您的 nginx 以根据源 ip 进行平衡并将流量直接发送到您的端点(https://github.com/kubernetes/contrib/tree/master/ingress/controllers#ingress-controllers

  2. 部署 haproxy serviceloadbalancer( https://github.com/kubernetes/contrib/blob/master/service-loadbalancer/service_loadbalancer.go#L51 ) 并在服务上设置 balance 注释,使其使用“源”。


pno*_*nak 7

从1.5版本开始,如果您在GCE(扩展名为GKE)或AWS中运行,则只需向服务中添加注释即可使HTTP源保留工作。

...
kind: Service
metadata:
  annotations:
    service.beta.kubernetes.io/external-traffic: OnlyLocal
...
Run Code Online (Sandbox Code Playgroud)

它基本上是直接通过节点端口公开服务,而不是提供代理-通过在每个节点上公开运行状况探针,负载平衡器可以确定将流量路由到的节点。

在1.7版中,此配置已成为GA,因此您可以"externalTrafficPolicy": "Local"在服务规范上进行设置 。

点击这里了解更多

  • 如果服务类型是“ClusterIP”怎么办? (2认同)

neo*_*yle 7

externalTrafficPolicy:本地

是您可以在负载均衡器类型或 NodePort 类型的 Kubernetes 服务的 yaml 中指定的设置。(Ingress Controllers 通常包含 yaml 来提供 LB 服务。)

externalTrafficPolicy:本地

做 3 件事:
1.禁用 SNAT,这样入口控制器 pod 就不会将源 IP 视为 Kubernetes 节点的 IP,而是应该看到真正的源 IP
2.通过添加 2 条规则摆脱额外的网络跃点
- 如果流量落在没有入口 pod 的节点的 nodeport 上,则将其丢弃。
- 如果流量到达具有入口 Pod 的节点的节点端口,则将其转发到同一节点上的 Pod。
3. 使用 /healthz 端点更新 Cloud Load Balancer 的 HealthCheck,以便 LB 不会转发到已被删除的节点,而只会转发到具有入口 pod 的节点。
(为了澄清起见重新表述:默认情况下又名“externalTrafficPolicy:Cluster”,流量在每个工作节点的 NodePorts 之间进行负载平衡。“externalTrafficPolicy:Local”允许流量仅发送到运行 Ingress Controller Pod 的节点子集. 因此,如果您有一个 100 个节点的集群,则云负载均衡器不会将流量发送到 97 个节点,而只会将其发送到运行 Ingress Controller Pod 的 ~3-5 个节点)


重要提示!
:AWS 不支持“externalTrafficPolicy: Local”。
(据说它在 GCP 和 Azure 上运行良好,据说我还记得在 Kubernetes 1.14 的次要版本中有一个回归破坏了它 + 有一些 Cilium CNI 版本也被破坏了,所以请注意默认的 externalTrafficPolicy: Cluster 是坚如磐石的稳定,如果您不需要该功能,通常应该是首选。另外请注意,如果您在它前面有一个 WAF 即服务,那么您可以利用它来查看客户端流量来自哪里。)

(它会导致 kops 和 EKS 出现问题,在 AWS 上运行的其他发行版实际上可能不受影响,更多内容见下文。)

AWS 不支持“externalTrafficPolicy:Local”是 Kubernetes 维护人员已知的一个问题,但没有详细记录。此外,一个烦人的事情是,如果你尝试它,你会有一些运气/它似乎是有效的,这让足够多的人认为它有效。

externalTrafficPolicy:本地在 AWS 上以 2 种方式中断,两个中断都有强制其工作的
变通方法:第一个中断 + 变通方法: /healthz 端点初始创建不稳定+ 协调循环逻辑中断。
在最初应用时,它将适用于某些节点而不是其他节点,然后永远不会更新。
https://github.com/kubernetes/kubernetes/issues/80579
^更详细地描述了问题。
https://github.com/kubernetes/kubernetes/issues/61486
^描述了一种使用 kops 钩子强制它工作的解决方法
(当您解决 /healthz 端点协调循环逻辑时,您可以解锁好处 #2 和 #3 更少的跳跃 + LB 只将流量发送到工作节点的子集。但是,好处 #1 源 IP 仍然是不正确的。)

第二次中断 + 2 个解决方法选项:
所需的最终结果是入口 pod 看到真实客户端的 IP。
但真正发生的是 ingress pod 从查看 k8s 节点的源 IP 转变为查看 Classic ELB 的源 IP。

解决方法选项 1.)

切换到更像 Azure LB 的网络 LB (L4 LB)。代价是无法使用 ACM(AWS 证书管理器)在 AWS LB 处终止 TLS/为您处理 TLS 证书配置和轮换。

变通方法选项 2.)
继续使用 AWS 经典 ELB,(并且您可以继续使用 ACM),您只需要将配置添加到经典 ELB(以 LB 服务的注释形式)+ 将配置添加到入口控制器。因此,两者都使用代理协议或 x 转发标头,我记得另一个 Stack Overflow 帖子涵盖了这一点,所以我不会在这里重复。