跨VPC或者跨云供应商搭建K8S集群正确姿势-番外篇

本文灵感主要是来自于张馆长的文章《跨VPC或者跨云供应商搭建K8S集群正确姿势》,因此取名《跨VPC或者跨云供应商搭建K8S集群正确姿势-番外篇》

上周发了几篇关于Kubernetes集群搭建相关的文章,里面有一个部分谈到了Kubernetes集群CNI插件(也就是容器网络接口)的部署,很多读者看到了这个部分之后有问到“如何跨VPC或者跨云供应商打通集群之间的网络访问”,我当时搭建集群和写文章的时候也没有注意这点,只是根据以往的经验单纯地把几台机器搞在一起再加上部署好CNI就想当然的以为Kubernetes集群算是“全网通”了。经过读者的提醒和自己的实践,发现忽略了一个严重的问题,也是大多数人在个人搭建Kubernetes集群常常会碰到的问题,也是就今天需要谈论的问题—“如何跨VPC或者跨云供应商搭建Kubernetes集群,保证集群网络互通”。

为了解决这个问题需要从几个方面思考:

  • 单一VPC和跨VPC/云供应商的网络方面的区别
  • 单一VPC和跨VPC/云供应商的网络环境下Kubernetes集群的区别
  • 跨VPC/云供应商的Kubernetes集群搭建时需要注意的点
  • 采用何种CNI来保证跨VPC/云供应商的Kubernetes集群的网络互通

本文会基于以上几点问题来展开,最后会根据我们思考的点给大家演示下具体的实战,可能有些点说的不太清楚,希望大家可以狠狠的批评!

1. Kubernetes集群搭建相关问题思考

1.1 单一VPC和跨VPC/云供应商的网络方面的区别

首先了解下什么是VPC?跨VPC或者跨云供应商搭建K8S集群正确姿势-番外篇_第1张图片
这里直接搬出百度百科的解释,直白地说,首先从服务的角度来看,VPC指的是一种云(Cloud),这与它的字面意思相符。你或许听过公有云(Public Cloud),私有云(Private Cloud),混合云(Hybrid Cloud)。不过,VPC不属于这三种云中任一种。这是一种运行在公有云上,将一部分公有云资源为某个用户隔离出来,给这个用户私有使用的资源的集合。VPC是这么一种云,它由公有云管理,运行在公共资源上,但是保证每个用户之间的资源是隔离,用户在使用的时候不受其他用户的影响,感觉像是在使用自己的私有云一样。它在概念上有点类似于VPN(Virtual Private Network),不过VPN只是在网络资源上的隔离,VPC更像是VPN的超集,VPC是对各种资源上对各个用户的隔离。

而我们这次主要讲不同VPC网络上面的隔离,用一个图来演示下不同VPC之间的关系。
跨VPC或者跨云供应商搭建K8S集群正确姿势-番外篇_第2张图片
从上面这张图可以看出,每个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进行通信。

1.2 单一VPC和跨VPC/云供应商的网络环境下Kubernetes集群的区别

上个问题我们理解到不同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

  • 场景一:Node要加入集群
    跨VPC或者跨云供应商搭建K8S集群正确姿势-番外篇_第3张图片
    如图所示,Node加入集群需要通过访问Master节点的ApiServer服务加入,既然要通过访问服务加入,也就是需要Node、Master互通才能做到访问,当然也可以通过Node访问Master节点的公网IP来访问,前提是Kubernetes集群初始化的时候暴露出公网地址。
  • 场景二:Master调度Pod到Node,需要获取Pod具体情况
    跨VPC或者跨云供应商搭建K8S集群正确姿势-番外篇_第4张图片
    图里面可以看出,每个节点都有自己的INTERNAL-IP,而当Master节点调度Pod到Node上的时候,Master节点通过describe和logs等命令获取数据时也是需要Master节点和Node节点互通的,Master和Node节点能否互通是通过查看INTERNAL-IP是否是同一网段的,而INTERNAL-IP是通过Kubectl查询节点上面的物理网卡(例如eth0,enoxxx)的地址,而物理网卡的地址往往都是子网的地址,所以在跨VPC/云供应商的网络环境必然是不可能处于同一网段的。
  • 场景三:Master需要收集Node节点数据
    同理场景二,当Master节点需要获取Node节点的数据的时候,需要通过访问Node节点暴露出的端口来获取数据,此时也是需要Master能够与Node节点互通的。

1.3 跨VPC/云供应商的Kubernetes集群搭建时需要注意的点

这个问题是我本次基于跨VPC或者跨云供应商搭建Kubernetes集群时所想到的,也是一个个人搭建Kubernetes集群时注意到的点。

  • 虽然是跨VPC,但是需要保证每个节点都有自己独立的公网IP。
  • 由于使用的是Kubeadm Config的方式来初始化Kubernetes集群,所以需要保证Kubeadm将ApiServer服务暴露在公网,其他具体的Kubeadm Config配置会在之后的实战时具体讲解。
  • 由于Node节点加入集群的时候被登记的INTERNAL-IP是节点内网IP,这样Master节点在和Node节点通信的时候会直接访问Node的内网IP,所以需要做Iptables的NAT转发。

1.4 采用何种CNI来保证跨VPC/云供应商的Kubernetes集群的网络互通

经过询问各位大佬的建议和自己的实际操作,发现主要有以下几种方式:

  • Flannel VXLAN的模式

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模式就被我们放弃了。跨VPC或者跨云供应商搭建K8S集群正确姿势-番外篇_第5张图片而UDP是Flannel最开始采用的方案,但是由于IP包多次在内核态和用户态之间做切换,因此效率最慢,作为Kubernetes集群的网络平台显然会拖累整个集群的响应能力,因此也被放弃了,那么只剩最后的VXLAN模式,也是目前官方主推的模式,我们来简单理解下VXLAN模式的原理:
跨VPC或者跨云供应商搭建K8S集群正确姿势-番外篇_第6张图片
一句话概括,当两层网络抵达不了的时候,通过虚拟设备的封包解包模拟出一层网络,造成“第三层网络”,在网络上实现互通。

  • Calico IPIP的模式
    Calico主要有两种模式:BGP和IPIP模式,和Flannel CNI类似,Calico BGP类似于Flannel host-gw模式,是一种基于路由的模式,没有封包和解包过程,完全基于两端宿主机的路由表进行转发,因此效率很高,但是必须要求两层互通,而且也会因为Iptables膨胀导致性能降低,因为宿主机上每个容器需要在本机添加一条路由规则,而不同宿主机之间需要广播自己的网段路由规则。而IPIP和Flannel VXLAN原理一样,就是基于隧道的模式来建立的,但是好一点的是Calico的封装协议IPIP的header更小,所以性能比Fannel VXLAN要好一点点。
  • Canal
    这个Canal不是阿里出的MySQL Binlog同步工具,而是华为出的基于Calico和Flannel开发的工具,不过这个工具的文档较少,所以没有具体研究。

2. Kubernetes集群搭建实战

上面讲了很多“不清不楚”的原理,下面可以开始正式的实战了,本次采用三个云服务器作为节点,三个节点均处于不同的VPC网络下面,每个节点都有自己的公网IP,张馆长的博客写明了在搭建好集群之后所有配置,但是没有写明初始化集群的时候如何配置,我在初始化集群的时候发现加入集群之后总是导致新的Flannel Pod无法启动,原因是因为无法和集群的ApiServer通信,因此在初始化的时候需要更改写Config的参数。

2.1 Kubeadm Config初始化集群

首先来看下我的Kubeadm Config配置
跨VPC或者跨云供应商搭建K8S集群正确姿势-番外篇_第7张图片
主要需要注意的点是三个部分,从上往下看

  • controlPlaneEndpoint
    这个配置需要填写公网IP以及对应的开放给公网的端口,如图中的xxxx:6443,如果没有写上这个的话,会默认访问clusterip:443,为了更方便对外网访问以及调试,可以做修改。
  • apiServer
    控制apiServer的暴露地址,修改为公网IP是为了能够让Node节点从公网进行访问。
  • networking.podSubnet
    划分子网的CIDR,这个是根据我们选择的CNI插件来填写的,默认Flannel的是10.244.0.0/16,默认Calico的是192.168.0.0/16,这个配置可以根据需求自由填写。

2.2 Flannel CNI部署及修改

Flannel CNI插件默认开启的模式就是VXLAN模式,可以参考官方配置文件跨VPC或者跨云供应商搭建K8S集群正确姿势-番外篇_第8张图片
可以看到Backend使用的是vxlan模式。

Flannel主要修改在于部署好Flannel CNI插件之后对于每个节点的Annotations上的public-ip参数进行修改,默认的都是使用内网IP,在使用Flannel VXLAN进行通信的时候也是访问不同,因此需要进行修改。

2.3 Iptables相关修改

参考张馆长的文章,Master通过logs和describe命令调用Node上的某一Pod的时候,往往会出现timeout的情况,这是由于Master和Node之间不能直接通信,而Master调用Node是根据Node的网卡地址的IP,这个IP是内网IP,因此需要做Iptables的NAT转发,如图
跨VPC或者跨云供应商搭建K8S集群正确姿势-番外篇_第9张图片

2.4 Metrics Server相关修改

在部署metrics server的时候会遇到不能获取Node节点数据的情况,原因还是因为Master节点访问不通Node节点,而Master访问的方式是通过Hostname:xxx的方式,而正常解析域名的时候会把Hostname解析成Node的内网IP,这样会访问不通,所以需要增加hostAliases来自定义hosts,让Master解析域名的时候解析到Node节点的公网IP上才能对Node节点上的数据进行收集。
跨VPC或者跨云供应商搭建K8S集群正确姿势-番外篇_第10张图片

3. 后续

以上就是对于跨VPC或者跨云供应商搭建K8S集群的思考,虽然成功的实现了集群之间的互通,但是方式上显得不那么“友好”,后续会继续研究相关方案,希望大佬们能够提供宝贵的意见。

你可能感兴趣的:(跨VPC或者跨云供应商搭建K8S集群正确姿势-番外篇)