Pod网络
# Pod特点
- 有自己的IP地址
- 有自己的hostname
- 有自己的端口
Pod实际上可以理解为就是k8s云平台中的虚拟机,而这个pod内部封装的是由docker引擎所创建的容器,也可以理解为pod就是一个虚拟化分组,pod内部可以存储一个或者多个容器。
所谓Pod网络,就是能够保证K8s集群中的所有Pods(包括同一节点上的,也包括不同节点上的Pods),逻辑上看起来都在同一个平面网络内,能够相互做IP寻址和通信的网络,下图是Pod网络的简化概念模型:
是否可以通过外网直接访问pod的ip:port ??? 不可以,pod只是一个进程,没有与之对应的物理实体。要在现实的网络中进行通信,必须要有与之对应的物理实体。也就是说pod要想和外部进行通信,必须借助于物理网卡。
# Pod内部通信
- 上图节点上展示了Pod网络所依赖的3个网络设备,eth0是节点主机上的网卡,这个是支持该节点流量出入的设备,也是支持集群节点间IP寻址和互通的设备。docker0是一个虚拟网桥,可以简单理解为一个虚拟交换机,它是支持该节点上的Pod之间进行IP寻址和互通的设备。veth0则是Pod1的虚拟网卡,是支持该Pod内容器互通和对外访问的虚拟设备。docker0网桥和veth0网卡,都是linux支持和创建的虚拟网络设备。
- 上图Pod1内部住了3个容器,它们都共享一个虚拟网卡veth0。内部的这些容器可以通过localhost相互访问,但是它们不能在同一端口上同时开启服务,否则会有端口冲突,这就是共享网络栈的意思。Pod1中还有一个比较特殊的叫pause的容器,这个容器运行的唯一目的是为Pod建立共享的veth0网络接口。
- 如果你SSH到K8s集群中一个有Pod运行的节点上去,然后运行
docker ps
,可以看到通过pause命令运行的容器。
即pod内部容器是通过共享一个虚拟网卡相互通信的,可以直接通过localhost相互访问,而这个虚拟网卡是通过一个特殊的容器pause创建的。
# 相同节点的Pod通信
- docker0是一个虚拟网桥,可以简单理解为一个虚拟交换机,它是支持该节点上的Pod之间进行IP寻址和互通的设备。
- Pod的IP是由docker0网桥分配的,例如上图docker0网桥的IP是172.17.0.1,它给第一个Pod1分配IP为172.17.0.2。如果该节点上再启一个Pod2,那么相应的分配IP为172.17.0.3,如果再启动Pod可依次类推。因为这些Pods都连在同一个网桥上,在同一个网段内,它们可以进行IP寻址和互通。
即相同节点的pod通信是通过当前节点的虚拟网桥相互通信的
# 不同节点的Pod通信
实际上不同节点间的Pod网络互通,有很多技术实现方案,底层的技术细节也很复杂。为了简化描述,我把这些方案大体分为两类,一类是路由方案,另外一类是覆盖(Overlay)网络方案。
# 1. 路由方案
- 通过路由设备为K8s集群的Pod网络单独划分网段,并配置路由器支持Pod网络的转发。例如上图中,对于目标为172.17.1.0/24这个范围内的包,转发到10.100.0.3这个主机上,同样,对于目标为172.17.0.0/24这个范围内的包,转发到10.100.0.2这个主机上。当主机的eth0接口接收到来自Pod网络的包,就会向内部网桥转发,这样不同节点间的Pod就可以相互IP寻址和通信。这种方案依赖于底层的网络设备,但是不引入额外性能开销。
# 2. 覆盖网络方案(k8s)
如果底层的网络是你无法控制的,比如说公有云网络,或者企业的运维团队不支持路由方案,可以采用覆盖(Overlay)网络方案,如下图所示:
所谓覆盖网络,就是在现有网络之上再建立一个虚拟网络,实现技术有很多,例如flannel/weavenet等等,这些方案大都采用隧道封包技术。
简单理解,Pod网络的数据包,在出节点之前,会先被封装成节点网络的数据包,当数据包到达目标节点,包内的Pod网络数据包会被解封出来,再转发给节点内部的Pod网络。这种方案对底层网络没有特别依赖,但是封包解包会引入额外性能开销。
Kubernetes-基于Flannel的网络原理
- flannel组建一个大二层扁平网络,pod的ip分配由flannel统一分配,通讯过程也是走flannel的网桥。
- 每个node上面都会创建一个flannel0虚拟网卡,用于跨node之间通讯。所以容器直接可以直接使用pod id进行通讯。
- 跨节点通讯时,发送端数据会从docker0路由到flannel0虚拟网卡,接收端数据会从flannel0路由到docker0。
# 外部访问pod
外网要和内部的pod进行通信,必须在物理机上开辟一个端口,通过物理机的端口对数据包(请求)进行转发,把请求转发给pod。实现pod内部服务外网访问。
- 将物理机的端口 和 内部pod(进程)做映射,访问物理机ip 和 端口,可以转发到对应的pod(内部进程的互连) 可以使用iptabels的配置规则实现数据包转发