externaltrafficpolicy作用阐述

把集群外部的服务引入到集群内部来,在集群内部直接使用。没有任何类型代理被创建,这只有 kubernetes 1.7 或更高版本的 kube-dns 才支持【当我们的集群服务需要访问k8s之外的集群时,可以选择这种类型,然后把外部服务的IP及端口写入到k8s服务中来,k8s的代理将会帮助我们访问到外部的集群服务】

什么是external-traffic-policy

在k8s的Service对象(申明一条访问通道)中,有一个“externalTrafficPolicy”字段可以设置。有2个值可以设置:Cluster或者Local。

1)Cluster表示:流量可以转发到其他节点上的Pod。

2)Local表示:流量只发给本机的Pod。

这2种模式有什么区别

存在这2种模式的原因就是,当前节点的Kube-proxy在转发报文的时候,会不会保留原始访问者的IP。

选择(1)Cluster

注:这个是默认模式,Kube-proxy不管容器实例在哪,公平转发。

Kube-proxy转发时会替换掉报文的源IP。即:容器收的报文,源IP地址,已经被替换为上一个转发节点的了。

原因是Kube-proxy在做转发的时候,会做一次SNAT (source network address translation),所以源IP变成了节点1的IP地址。

ps:snat确保回去的报文可以原路返回,不然回去的路径不一样,客户会认为非法报文的。(我发给张三的,怎么李四给我回应?丢弃!)

这种模式好处是负载均衡会比较好,因为无论容器实例怎么分布在多个节点上,它都会转发过去。当然,由于多了一次转发,性能会损失一丢丢。

选择(2)Local

这种情况下,只转发给本机的容器,绝不跨节点转发。

Kube-proxy转发时会保留源IP。即:容器收到的报文,看到源IP地址还是用户的。

缺点是负载均衡可能不是很好,因为一旦容器实例分布在多个节点上,它只转发给本机,不跨节点转发流量。当然,少了一次转发,性能会相对好一丢丢。

注1:这种模式下的Service类型只能为外部流量,即:LoadBalancer 或者 NodePort 两种,否则会报错。

注2: 如果客户端经过代理访问pod, 例如走clb, 这时候获取到的客户端ip就已经变成了clb的地址, 如果需要真实ip, 可以查看nginx篇remote_addr的一些认识

同时,由于本机不会跨节点转发报文,所以要想所有节点上的容器有负载均衡,就需要上一级的Loadbalancer来做了。

不过流量还是会不太均衡,如上图,Loadbalancer看到的是2个后端(把节点的IP),每个Node上面几个Pod对Loadbalancer来说是不知道的。

想要解决负载不均衡的问题:可以给Pod容器设置反亲和,让这些容器平均的分布在各个节点上(不要聚在一起)。

1
2
3
4
5
6
7
8
9
10
11
12
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: k8s-app
operator: In
values:
- my-app
topologyKey: kubernetes.io/hostname

像下面这样,负载均衡情况就会好很多~

两种模式该怎么选

要想性能(时延)好,当然应该选 Local 模式喽,毕竟流量转发少一次SNAT嘛。

不过注意,选了这个就得考虑好怎么处理好负载均衡问题。

如果你是从外部LB接收流量的,那么使用:Local模式 + Pod反亲和,一般是足够的

在几种service模式下, 获取真实客户端ip情况

Kube-proxy 通过访问proxyMode endpoint查看模式

1
2
$ curl localhost:10249/proxyMode
iptables

具有 Type = ClusterIP 服务的客户端IP

1
如果在 iptables 模式下运行 kube-proxy,则从集群内发送到 ClusterIP 的数据包永远不会来自 DNAT(目的地址转换,作用是将一组本地内部的地址映射到一组全球地址) ,这是Kubernetes 1.2 以来的默认设置。

无论何种访问方式,获取到的 remote_addr 地址,永远都是客户端所在容器的IP 10.244.5.27

通过 Type=NodePort 获取客户端IP

1
从 Kubernetes 1.5 开始, 默认情况下,发送到 Type = NodePort 的服务数据包是来自 DNAT。

通过上面的方法能够看到,我们从不同节点去访问 NodePort ,得到的也并不是真正的客户端IP, 而是集群ip

通过 Type = LoadBalancer 获取客户端IP

略...