本文灵感主要是来自于张馆长的文章《跨VPC或者跨云供应商搭建K8S集群正确姿势》,因此取名《跨VPC或者跨云供应商搭建K8S集群正确姿势-番外篇》
上周发了几篇关于Kubernetes集群搭建相关的文章,里面有一个部分谈到了Kubernetes集群CNI插件(也就是容器网络接口)的部署,很多读者看到了这个部分之后有问到“如何跨VPC或者跨云供应商打通集群之间的网络访问”,我当时搭建集群和写文章的时候也没有注意这点,只是根据以往的经验单纯地把几台机器搞在一起再加上部署好CNI就想当然的以为Kubernetes集群算是“全网通”了。经过读者的提醒和自己的实践,发现忽略了一个严重的问题,也是大多数人在个人搭建Kubernetes集群常常会碰到的问题,也是就今天需要谈论的问题—“如何跨VPC或者跨云供应商搭建Kubernetes集群,保证集群网络互通”。
为了解决这个问题需要从几个方面思考:
本文会基于以上几点问题来展开,最后会根据我们思考的点给大家演示下具体的实战,可能有些点说的不太清楚,希望大家可以狠狠的批评!
首先了解下什么是VPC?
这里直接搬出百度百科的解释,直白地说,首先从服务的角度来看,VPC指的是一种云(Cloud),这与它的字面意思相符。你或许听过公有云(Public Cloud),私有云(Private Cloud),混合云(Hybrid Cloud)。不过,VPC不属于这三种云中任一种。这是一种运行在公有云上,将一部分公有云资源为某个用户隔离出来,给这个用户私有使用的资源的集合。VPC是这么一种云,它由公有云管理,运行在公共资源上,但是保证每个用户之间的资源是隔离,用户在使用的时候不受其他用户的影响,感觉像是在使用自己的私有云一样。它在概念上有点类似于VPN(Virtual Private Network),不过VPN只是在网络资源上的隔离,VPC更像是VPN的超集,VPC是对各种资源上对各个用户的隔离。
而我们这次主要讲不同VPC网络上面的隔离,用一个图来演示下不同VPC之间的关系。
从上面这张图可以看出,每个VPC都有自己独立的IPv4 CIDR和IP地址,在单个VPC中的每个Node节点又会根据网址划分规则获取自己的VPC内网地址,由于Node A1和Node A2是同处一个网段,可以相互通信(原理上是源节点根据发送ARP请求到广播域让目标节点获得ARP请求把MAC地址单播到源节点,获取到MAC地址之后,封装XX等协议包经由物理传输进行通行通信)。而在不同VPC之间,由于网段的不同,比如Node A1(10.4.0.1)和Node B1(10.3.0.1),不能直接通过内网地址通信,需要通信的话一是通过两个Node的公网IP来访问,二是通过VPC的封装转发来通信,大家想要仔细了解可以参考Docker的网络原理。
上面说了这么多都是为了让大家理解VPC具体在网络方面做了什么隔离,那么大家现在应该可以明白单一VPC和跨VPC/云供应商之间的网络区别是什么,在单一VPC集群里,各个节点都是在同一网段下,可以直接进行通信,不需要配置额外的转发,而在跨VPC/云供应商的环境中,各个Node节点是不能够直接通过内网IP进行通信的,不过可以通过公网IP进行通信。
上个问题我们理解到不同VPC之间的Node节点是不能直接访问的,那么这点对于我们在搭建Kubernetes集群的时候有什么影响呢?
假设我们现在有1台Master节点、1台Node节点,要搭建双节点的集群,我们从几个特定的场景看看单一VPC和跨VPC/云供应商的网络环境有什么区别。
当在单一VPC中的时候,Master为10.0.0.1,Node为10.0.0.2,当在跨VPC/云供应商的时候,Master为10.0.0.1,Node为10.0.0.2
这个问题是我本次基于跨VPC或者跨云供应商搭建Kubernetes集群时所想到的,也是一个个人搭建Kubernetes集群时注意到的点。
经过询问各位大佬的建议和自己的实际操作,发现主要有以下几种方式:
Flannel网络通信原理可以看看这篇文章:
https://blog.51cto.com/liuzhengwei521/2427495
https://blog.51cto.com/14143894/2462379
Flannel主要有三种模式,UDP、VXLAN、host-gw,而由于host-gw的原理是将每个flannel的子网的下一跳,设置成该子网对应的宿主机的IP地址,也就是在于IP包在封装成帧发送出去的时候,会使用路由表的“下一跳”来设置目的MAC地址,这就要求必须通过二层网络到达目的宿主机,所以host-gw模式必须要求集群宿主机之间是二层连通的,host-gw模式就被我们放弃了。而UDP是Flannel最开始采用的方案,但是由于IP包多次在内核态和用户态之间做切换,因此效率最慢,作为Kubernetes集群的网络平台显然会拖累整个集群的响应能力,因此也被放弃了,那么只剩最后的VXLAN模式,也是目前官方主推的模式,我们来简单理解下VXLAN模式的原理:
一句话概括,当两层网络抵达不了的时候,通过虚拟设备的封包解包模拟出一层网络,造成“第三层网络”,在网络上实现互通。
上面讲了很多“不清不楚”的原理,下面可以开始正式的实战了,本次采用三个云服务器作为节点,三个节点均处于不同的VPC网络下面,每个节点都有自己的公网IP,张馆长的博客写明了在搭建好集群之后所有配置,但是没有写明初始化集群的时候如何配置,我在初始化集群的时候发现加入集群之后总是导致新的Flannel Pod无法启动,原因是因为无法和集群的ApiServer通信,因此在初始化的时候需要更改写Config的参数。
首先来看下我的Kubeadm Config配置
主要需要注意的点是三个部分,从上往下看
Flannel CNI插件默认开启的模式就是VXLAN模式,可以参考官方配置文件
可以看到Backend使用的是vxlan模式。
Flannel主要修改在于部署好Flannel CNI插件之后对于每个节点的Annotations上的public-ip参数进行修改,默认的都是使用内网IP,在使用Flannel VXLAN进行通信的时候也是访问不同,因此需要进行修改。
参考张馆长的文章,Master通过logs和describe命令调用Node上的某一Pod的时候,往往会出现timeout的情况,这是由于Master和Node之间不能直接通信,而Master调用Node是根据Node的网卡地址的IP,这个IP是内网IP,因此需要做Iptables的NAT转发,如图
在部署metrics server的时候会遇到不能获取Node节点数据的情况,原因还是因为Master节点访问不通Node节点,而Master访问的方式是通过Hostname:xxx的方式,而正常解析域名的时候会把Hostname解析成Node的内网IP,这样会访问不通,所以需要增加hostAliases来自定义hosts,让Master解析域名的时候解析到Node节点的公网IP上才能对Node节点上的数据进行收集。
以上就是对于跨VPC或者跨云供应商搭建K8S集群的思考,虽然成功的实现了集群之间的互通,但是方式上显得不那么“友好”,后续会继续研究相关方案,希望大佬们能够提供宝贵的意见。