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

时间:2015-08-20 08:11:51

标签: http kubernetes

我的Web应用程序作为SSL的nginx反向代理后面的Kubernetes pod运行。代理和我的应用程序都使用Kubernetes服务进行负载平衡(如here所述)。

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

7 个答案:

答案 0 :(得分:6)

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

...
kind: Service
metadata:
  annotations:
    service.beta.kubernetes.io/external-traffic: OnlyLocal
...

它基本上通过nodeports而不是提供代理来公开服务 - 通过在每个节点上公开健康探测,负载均衡器可以确定将流量路由到哪些节点。

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

Click here to learn more

答案 1 :(得分:4)

你可以通过两种方式完全从循环中获取kube-proxy:

  1. 使用Ingress根据源IP配置您的nginx进行平衡,并将流量直接发送到您的终端(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)并在服务器上设置余额注释,使其使用“source”。

答案 2 :(得分:2)

现在,没有。

服务使用kube_proxy将流量分配到其后端。 Kube-proxy使用iptables将服务IP路由到它正在侦听的本地端口,然后打开与其中一个后端的新连接。您看到的内部IP是在您的一个节点上运行的kube-proxy的IP:端口。

仅iptables kube-proxy为in the works。这将保留原始的源IP。

答案 3 :(得分:2)

从Kubernetes 1.1开始,有一个基于iptables的kube-proxy在某些情况下解决了这个问题。它默认是禁用的;有关如何启用它的说明,请参阅this post。总之,请执行:

for node in $(kubectl get nodes -o name); do kubectl annotate $node net.beta.kubernetes.io/proxy-mode=iptables; done

对于Pod-to-Pod流量,使用iptables kube-proxy,您现在可以在目标pod中看到真正的源IP。

但是,如果您的服务正在从群集外部转发流量(例如NodePort,LoadBalancer服务),那么我们仍然必须替换(SNAT)源IP。这是因为我们正在对传入流量进行DNAT以将其路由到服务Pod(可能在另一个节点上),因此DNATing节点需要将自己插入到返回路径中以便能够取消DNAT响应。

答案 4 :(得分:2)

对于非HTTP请求(HTTPS,gRPC等),计划在Kubernetes 1.4中支持。请参阅:https://github.com/kubernetes/features/issues/27

答案 5 :(得分:2)

  

externalTrafficPolicy:本地

是您可以在Kubernetes Services的Yaml中指定类型为Load Balancer或NodePort的设置。 (入口控制器通常包括yaml来提供LB服务。)

  

externalTrafficPolicy:本地

执行3件事:
1。。禁用SNAT,以使而不是Ingress Controller Pod将源IP视为Kubernetes节点的IP,而应该看到真实的源IP
2。通过添加2条规则来摆脱多余的网络跳跃
-如果流量降落在没有入口容器的节点的节点端口上,则会被丢弃。
-如果流量落在具有入口Pod的节点的nodeport上,则会转发到同一节点上的Pod。
3。使用/ healthz端点更新Cloud Load Balancer的HealthCheck,应该这样做,以便LB不会转发到将其删除的节点,而只会转发到具有入口Pod的节点。
(为了澄清起见,重新命名:默认情况下也称为“ externalTrafficPolicy:群集”,流量在每个工作节点的NodePort之间获得负载平衡。“ externalTrafficPolicy:Local”允许将流量仅发送到具有Ingress Controller的节点的子集Pod运行在它们上。因此,如果您有一个100节点的集群,而不是云负载均衡器将流量发送到97个节点,它只会将其发送到运行Ingress Controller Pods的约3-5个节点)。


重要提示!
AWS不支持“ externalTrafficPolicy:本地”。
(据说它可以在GCP和Azure上正常工作,据说我还记得阅读过一个回归,它在次要版本的Kubernetes 1.14中破坏了它,还有一些Cilium CNI版本也被打破了,因此请注意,默认的externalTrafficPolicy:群集是坚如磐石的,如果您不需要此功能,通常应该优先选择该群集。另外,请注意,如果您将WAF即服务置于其前面,则可以来查看客户端流量的来源。)

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

AWS上不支持的

“ externalTrafficPolicy:Local”是Kubernetes维护人员已知的问题,但没有充分记录。另外,令人烦恼的是,如果尝试使用它,将会有些运气/它似乎正在起作用,这欺骗了很多人以为它起作用了。

externalTrafficPolicy:在AWS上以两种方式破坏了本地,并且两个中断都有变通方法来强制其工作:
第一个中断+解决方法::/ healthz端点初始创建很不稳定+调节循环逻辑已损坏。
在初次应用后,它将对某些节点有效,而对其他节点无效,然后再不进行更新。
https://github.com/kubernetes/kubernetes/issues/80579
^更详细地描述了问题。
https://github.com/kubernetes/kubernetes/issues/61486
^描述了一种解决方法,可以使用kops挂钩强制其工作
(当您解决/ healthz端点对帐循环逻辑时,您解锁收益#2和#3的跃点+ LB减少,仅将流量发送到辅助节点的子集。但是,收益#1的源IP仍然不正确。 )

第二次休息+ 2个解决方法选项:
理想的最终结果是一个可以看到真实客户IP的入口吊舱。
但是真正发生的是入口Pod从查看k8s节点的源IP到查看经典ELB的源IP。

解决方法选项1。)

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

解决方法选项2。)
继续使用AWS经典ELB(并且继续使用ACM),您只需将配置添加到经典ELB中(以LB服务的注释形式)+将配置添加到入口控制器。为了都使用代理协议或x转发头,我还记得另一篇有关此内容的Stack Overflow帖子,因此在此不再赘述。

答案 6 :(得分:0)

对于kubernetes 1.7+,将service.spec.externalTrafficPolicy设置为Local即可解决。 这里的更多信息:Kubernetes Docs

相关问题