Kubernetes网络
提供多种选项帮助实现网络连接,k8s本身不关心如何实现它,但需满足三个基本要求:
无需NAT(network address translation),所有容器可相互访问,无论在哪个节点上
所有节点可与所有容器通信
容器看自己的IP应与其他容器看到的一致
Docker网络
三种容器网络模型:bridge、none、host
Docker创建并附加虚拟以太网设备(也称veth),并为每个容器分配网络命名空间
网络命名空间Network namespace是linux中的一项功能,逻辑上是网络栈的副本,拥有自己的路由表、arp(address resolution protocal 地址解析协议)表、网络设备
veth成对出现,一个在网络命名空间中,一个在网桥上,当流量进入主机网络,它被路由到网桥,数据包被发送到对应veth,并进入容器内的命名空间
容器间通信
k8s中的pod都有自己真实的IP地址,pod中的容器共享网络命名空间,视彼此为localhost
默认情况,由network container实现,该容器充当pod中每个容器流量转发的桥梁
Pod间通信
无论Pod在哪个节点上,其他Pod都应该可以通过PodIP进行访问
同一节点内Pod间通信
默认情况,同一节点内Pod间通信会经过网桥
示例:有两个Pod,都有自己的网络命名空间,数据包通过Pod1命名空间传递到相应的veth pair vethXXXX,然后进入网桥,网桥广播目标IP地址以帮助数据包找到路径,vethYYYY进行响应,数据包到达Pod2
跨节点Pod间通信
k8s通过容器网络接口(container network interface,CNI)实现通信
实现方式如L2、L3、Overlay
Overlay数据包封装,在数据包离开数据源之前封装,在目的端解封,导致overlay会增加网络延迟和复杂性
Pod与服务间通信
k8s始终是动态变化的,Pod一直在创建和删除
k8s通过标签选择器选择一组Pod,通常通过服务来访问而不是直接访问某个Pod
Endpoint对象也会随着服务的创建而产生,记录了服务后端的PodIP
k8s使用kube-proxy通过iptables来完成流量从一个Pod到服务后端的Pod
外部与服务通信
k8s支持外部流程访问,两个API对象实现该目标:
Service:外部网络负载均衡或者NodePort(L4)
Ingress:HTTP(s)负载均衡(L7)
示例:
两个服务,服务A有3个Pod,a、b、c,服务B有一个Pod d
流程从LoadBalancer进入,数据包被发送到其中一个节点(多数LoadBalancer不知道Pod或容器存在,只知道有后端节点),如果节点通过健康检查就可以加入到负载均衡后端
若要访问服务B,LoadBalancer就会将数据包发送到另一个节点上
数据流示例:
1 LoadBalancer选择一个节点转发数据包,GCE中,通过源IP和端口、目的IP和端口,以及协议的散列选择实例,AWS中,基于round-robin轮询算法
2 路由目标被更改为Pod d(DNAT),将数据包转发到另一个节点,类似于跨节点的Pod间通信
3 通过Service到Pod的通信,数据包到达Pod d并得到响应
4 Pod到Service通信也由iptables管理
5 数据包将被转发到原始节点
6 源和目的将un-DNAT回负载均衡(Loadbalancer)和客户端,数据包原路返回
k8s 1.7中,Service中有外部流量策略(externalTraffic-Policy)的新属性,设置为local,流量进入节点后,k8s在改节点上路由
Ingress
Pod和Service都有自己的IP,但通常不是提供给外部互联网的接口
虽然配置了含节点IP的服务,但是节点IP中的端口不能在服务间重复,确定用哪种服务管理哪个端口很麻烦,节点启启停停,不适合为外部服务提供静态节点IP
Ingress定义了一组允许入站连接访问k8s集群服务的规则,在七层将流量引入机器,每个节点都分配服务端口进行流量转发,允许使用URL路径路由到不同服务
如下图,定义规则发布到API服务器,流量进入时,Ingress控制器匹配Ingress规则并进行路由,Ingress通过不同的URL将外部流量路由到不同k8s端点
网络策略
NetworkPolicy,Pod的软件防火墙,默认下,Pod可以互相通信
网络策略应用于Pod的隔离,通过命名空间选择器和Pod选择器,定义谁可以访问哪个端口,这些策略在命名空间中是叠加的
默认拒绝所有,标签不匹配的Pod都将被拒绝