k8s获取client ip
通常,为了访问kubernetes集群中的pod,我们会使用service的形式。以下,就不同的 service 类型来探讨对source ip的影响。kubernetes的官网对此也有说明:https://kubernetes.io/docs/tutorials/services/source-ip/在此简单总结一下(网络插件使用calico, 其他插件可能有不同,在此不做讨论):...
通常,为了访问kubernetes集群中的pod,我们会使用service
的形式。以下,就不同的 service
类型来探讨对source ip
的影响。
kubernetes的官网对此也有说明:
https://kubernetes.io/docs/tutorials/services/source-ip/
在此简单总结一下(网络插件使用calico, 其他插件可能有不同,在此不做讨论):
ClusterIP
在创建service
的时候,如果不声明type
字段,则默认为 ClusterIP
. 其原理就是利用iptables 对发送到clusterip
的报文进行转发。
[root@walker-1 hehe]# kubectl describe svc nginx
Name: nginx
Namespace: default
Labels: app=nginx
Selector: app=nginx
Type: ClusterIP
IP: 10.96.9.42
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 192.168.187.212:80
Session Affinity: None
如果是ClusterIP
, 一般用于集群内pod之间的访问。
1. 如果client和server在同一个node上,那么从server观察到的source ip
为client的真实IP。
2. 如果client和server分别处于node A, node B上,那么从server段观察到source ip
的就是 node B的IP(pod外出的流量会被做SNAT)。
NodePort
NodePort
可以认为是构建在 ClusterIP
之上的。如果指定service 类型为NodePort
,那么在每个 node 上都会监听同一个端口,并通过iptables对其进行转发。
请求有两种情况:
- pod不在所请求的node上
toplogy:
client
\ ^
\ \
v \
node 1 <--- node 2
| ^ SNAT
| | --->
v |
endpoint
- 客户端将请求发送到node 2
- node 2 根据iptables 中的转发策略,将报文转发至pod所在节点 node 1
- node 1 根据本地路由将报文发送给 pod
- node 1 将pod的响应报文做SNAT后,发给node 2
- node 2 回复给client
(此时pod所见的source ip
为node 2的IP)
- pod在所请求的node上
toplogy:
client
| ^
| |SNAT
v |
node 1
| ^
| |
v |
endpoint
- 客户端请求
node1:nodeport
- node 1 根据iptables,通过SNAT 将原地址改为node1 ip, 通过DNAT 将目的地址改为pod ip
- node 1 将pod响应报文通过SNAT 返回给客户端
(此时pod所见的source ip
为node 1的IP)
这就很烦了,怎么都获取不到正确的用户ip。好在NodePort模式还提供了{"spec":{"externalTrafficPolicy":"Local"}}
参数
加上以后效果是这样的:
toplogy:
client
^ / \
/ / \
/ v X
node 1 node 2
^ |
| |
| v
endpoint
- 客户端请求
node1:nodeport
- node 1 根据iptables, 通过DNAT将目的地址改为pod ip
- node 1 将pod响应报文通过SNAT返回给客户端
(此时pod所见的source ip
为client ip)
注:发往node2的报文会被丢弃,因为报文不会再做SNAT,来将client ip替换为node2 ip了。
LoadBalancer
默认也会做SNAT,替换客户端IP。
However, if you’re running on Google Kubernetes Engine/GCE, setting the same
service.spec.externalTrafficPolicy
field toLocal
forces nodes without Service endpoints to remove themselves from the list of nodes eligible for loadbalanced traffic by deliberately failing health checks.
Visually:
client
|
lb VIP
/ ^
v /
health check ---> node 1 node 2 <--- health check
200 <--- ^ | ---> 500
| V
endpoint
总结
要让 pod 能正常获取客户端ip大致有如下几种方式:
1. 可以使用 NodePort
+ {"spec":{"externalTrafficPolicy":"Local"}}
的配置来实现。
2. 还有个解决思路就是利用 INGERSS。INGRESS 本质上是监听物理机端口,然后直接将客户端请求转发至service
。可以在INGRESS 请求转发阶段将客户端IP 带到请求头中。
3. pod直接使用 HOST 网络模式。
第三种方式最便捷,但容易造成端口冲突。安全问题也有待考量,因此不推荐。
第二种方式最灵活,即使pod分布在不同node上也可以通过统一入口访问,官方INGRESS是由nginx实现的,这样一来花样就多了(甚至可以做流控,认证功能)。推荐使用。
第一种方式折中吧,因为还没试过当service
的多个endpoint
分布在不同节点上的情况。
更多推荐
所有评论(0)