一、容器与容器之间的通信

同一个pod中的容器,共用同一个网络命名空间,直接使用localhost或127.0.0.1加上端口访问就好了。可以看到这两个容器的ip地址,路由表,以及暴露的端口号等都是一样的,因为他们使用的是同一个网络命名空间,同一个网络栈。

【注意】:他们只是共用网络命名空间(network namespace),但是进程命名空间(PID namespace)、用户命名空间(user namespace)等其他的命名空间是相互隔离的。

二、POD与POD之间的通信

1、同一个Node上的pod之间的通信

dbe17f5bc7ab2deb0d5c2424afd90ac9.png

每个pod都有唯一一个ip(属于docker0网桥上的网段),每个pod的网络基础设施容器都是通过veth设备对直接连在docker0网桥上的:

本机docker0网桥的地址的数据包都会通过容器内的eth0(veth设备)直接转给Kernel,路由的范围是link(与本设备直接连接),因为veth设备都是成对存在的,另一端连在docker0网桥上,所以会由Kernel直接转发给docker0网桥上的另一个veth设备。

宿主机将数据包通过docker0发给Kernel,最终docker0网桥会将数据包转发给目的pod。

2、不同Node上的pod之间的通信

要支持不同Node节点上的pod通信需要满足的要求:

1)整个kubernetes集群中对每个POD分配一个唯一的IP:在部署Kubernetes时,对每个Node节点的docker0网桥的网段重新划分,用户设定一个大的网段(eg:10.20.0.0/16),存在etcd中,每个节点的flanneld会去etcd中查找这个值,然后,flanneld随机生成一个属于大网段的,且不冲突的子网(eg: 10.20.37.0/24; 10.20.92.0/24; 10.20.0.53/24)并将该值写回etcd中,这样就保证了每个pod的IP都会在10.20.0.0/16这个网段内;

2)Node节点之间需要架设一个overlay网络(一般通过flannel实现),保证pod可以互相访问。

三、Pod与Service之间的通信

为了支持水平扩展和高可用,实际使用中并不会直接使用POD的IP来访问POD中的服务,而是定义service来访问一组POD中的服务。service是对一组POD的抽象,会根据访问策略(负载均衡)来访问这组POD。

Kubernetes会在创建service时随机分配一个ClusterIP,这是一个虚IP(VIP),不能与docker0网桥的网段冲突,比如:10.10.0.0/16这个网段(在 kube-apiserver的--service-cluster-ip-range=10.10.0.0/16配置项中指定)。

访问POD中服务是只需要访问这个VIP就好了,而service会将请求经过负载均衡之后转发到后端POD中,这些工作都是运行在每个Node节点的kube-proxy进程管理的,它的核心功能是:将对某个Service的访问经过负载均衡(Round Robin算法)之后转发到某一个后端POD:

1、Service的类型

1、ClusterIP:默认类型,自动分配一个仅cluster内部可以访问的虚拟IP;

2、NodePort:在ClusterIP基础上为Service在每台机器上绑定一个端口,这样就可以通过:NodePort来访问改服务;

3、LoadBalancer:在NodePort的基础上,借助cloud provider创建一个外部的负载均衡器,并将请求转发到:NodePort

无论是ClusterIP+TargetPort的方式,还是NodeIP+NodePort的方式访问服务,都会被节点的iptables规则重定向到kube-proxy监听Service的服务代理端口,kube-proxy接受到Service请求之后,会使用Round-Robin负载均衡算法按照Service维护的Endpoint对象中选择一个endpoint(其实就是POD)。

2、ClusterIP类型的service需要的iptables规则

任何数据包进入宿主机后,首先进入PREROUTING链:

-A PREROUTING -m comment --comment "kubernetes service portals" -j KUBE-SERVICES-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER

kube-proxy进程在启动时或者监听到Service和Endpoint发生变化之后,会为每个endpoint修改本机Iptables的NAT表中的4条规则链:

-A KUBE-SEP-6XCC4VJACKOMSYVV -s 10.20.92.11/32 -m comment --comment "hyjx--hyjx-group3/mysql-demo:mysqld-demo" -j KUBE-MARK-MASQ-A KUBE-SEP-6XCC4VJACKOMSYVV -p tcp -m comment --comment "hyjx--hyjx-group3/mysql-demo:mysqld-demo" -m tcp -j DNAT --to-destination 10.20.92.11:3306

-A KUBE-SERVICES -d 10.10.147.26/32 -p tcp -m comment --comment "hyjx--hyjx-group3/mysql-demo:mysqld-demo cluster IP" -m tcp --dport 13306 -j KUBE-SVC-DM5EMDBLORDRGWLL-A KUBE-SVC-DM5EMDBLORDRGWLL -m comment --comment "hyjx--hyjx-group3/mysql-demo:mysqld-demo" -j KUBE-SEP-6XCC4VJACKOMSYVV

3、NodePort类型的Service需要的iptables规则

-A KUBE-NODEPORTS -p tcp -m comment --comment "hyjx--hyjx-group3/mysql-demo2:mysqld-demo2" -m tcp --dport 30016 -j KUBE-MARK-MASQ-A KUBE-NODEPORTS -p tcp -m comment --comment "hyjx--hyjx-group3/mysql-demo2:mysqld-demo2" -m tcp --dport 30016 -j KUBE-SVC-NVNGTMQMPFTQA6YS-A KUBE-SEP-7MWHP37XXE3W6QI4 -s 10.20.92.11/32 -m comment --comment "hyjx--hyjx-group3/mysql-demo2:mysqld-demo2" -j KUBE-MARK-MASQ-A KUBE-SEP-7MWHP37XXE3W6QI4 -p tcp -m comment --comment "hyjx--hyjx-group3/mysql-demo2:mysqld-demo2" -m tcp -j DNAT --to-destination 10.20.92.11:3306

-A KUBE-SERVICES -d 10.10.95.1/32 -p tcp -m comment --comment "hyjx--hyjx-group3/mysql-demo2:mysqld-demo2 cluster IP" -m tcp --dport 23306 -j KUBE-SVC-NVNGTMQMPFTQA6YS-A KUBE-SVC-NVNGTMQMPFTQA6YS -m comment --comment "hyjx--hyjx-group3/mysql-demo2:mysqld-demo2" -j KUBE-SEP-7MWHP37XXE3W6QI4

NodePort类型的Service比ClusterIP类型就多了两条规则KUBE-NODEPORTS,剩下的4条规则是用来处理使用ClusterIP的方式访问服务的请求,因为NodePort类型的服务,同样可以使用ClusterIP的方式访问。

1)、第一条规则,实现了IP Masquerade功能 ;

2)、第二条规则,如果是使用NodeIP+NodePort的方式,目的端口为30016,处理方法和直接使用ClusterIP类型的服务访问一样。

4、更近一步,直接使用服务的名字访问

使用服务的VIP的方式还是不太友好,因为只有创建好Service之后,系统才会随机分配一个VIP,运行在容器中的应用无法提前知道这个VIP,动态修改镜像是不现实的。最终的解决方案是直接使用服务的名称来访问服务。而,服务的名称到服务的VIP的解析是由kube-dns来完成的。

kubelet在启动容器的时候,会修改容器的/etc/resolv.conf,设置容器的DNS服务器为kube-dns(k8s-master节点IP),每个服务都有唯一一个域名。

在容器中无法ping通服务mysql-demo的VIP,但是使用服务的名称,kube-dns可以正确地返回服务对应的VIP

四、k8s集群外部到k8s集群内部的访问

设置service的类型为NodePort,并为服务指定一个不冲突的端口(30000-32767)就行了,访问时直接使用任意一个Node节点的IP加上这个NodePort

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐