SsJackX 2019-06-28
1、下载模板wget https://docs.projectcalico.org/v3.1/getting-started/kubernetes/installation/hosted/kubeadm/1.7/calico.yaml
可以得到一份calico官方提供的v3.1版本calico的部署模板(基于kubeadm)。当然里面都是社区的镜像,我们可以替换成本地镜像.建议到网易云的景象中心下载,很多其他的国内镜像仓库都不做维护了。
2、启/禁用 ip-ip
目前官方提供的模板里,默认打开了ip-ip功能,该功能会在node上创建一个设备:tunl0,容器的网络数据会经过该设备被封装一个ip头再转发。这里,calico.yaml中通过修改calico-node的环境变量:CALICO_IPV4POOL_IPIP来实现ipip功能的开关:默认是Always,表示开启;Off表示关闭ipip; cross-subnet表示开启并支持跨子网,目前用不到这种类型。sed -i "s#Always#Off#g" calico.yaml
3、部署:
注意:部署前,要配置一个参数,让calico-node组件能够识别node的IP,node上可能有多块网卡,官方提供的yaml文件中,ip识别策略(IPDETECTMETHOD)没有配置,即默认为first-found,这会导致一个网络异常的ip作为nodeIP被注册,从而影响node-to-node mesh。我们可以修改成can-reach的策略,尝试连接某一个Ready的node的IP,以此选择出正确的IP。
为了方便,下面的脚本里,我以任意一个node的ip地址为reach 地址
connective_ip=`kubectl get node -o wide |grep Ready |head -n1 |awk '{print $6}'` sed -i -rn 'p;/name: IP/,/autodetect/H;/autodetect/{g;s/^\n//;p}' calico.yaml sed -i '1,/name: IP/{s/name: IP/name: IP_AUTODETECTION_METHOD/}' calico.yaml sed -i '1,/\"autodetect\"/{s/\"autodetect\"/can-reach=__ONE_CONNECTIVE_ENDPOINT__/}' calico.yaml sed -i "s#__ONE_CONNECTIVE_ENDPOINT__#$connective_ip#g" calico.yaml
执行:kubectl apply -f calico.yaml
4、calico使用过程中的一些其他点
wget https://docs.projectcalico.org/v3.1/getting-started/kubernetes/installation/hosted/kubernetes-datastore/calico-networking/1.7/calico.yaml wget https://docs.projectcalico.org/v3.1/getting-started/kubernetes/installation/hosted/rbac-kdd.yaml kubectl apply -f rbac-kdd.yaml kubectl apply -f calico.yaml
此处下载的calico.yaml 仍可以参照上文的部署方式进行ipip、ip pool等的定制化。
通过bgp方式部署好calico后,我们在集群中创建几个pod:
root@k8s-calico1:~# pods NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE huang1 huangtest-69d9fddd97-cbzbm 1/1 Running 0 20m 192.168.211.1 k8s-calico4 huang1 huangtest-69d9fddd97-pbvvw 1/1 Running 0 3m 192.168.210.194 k8s-calico3 huang2 hhh-6897d64fcd-4zph4 1/1 Running 0 1d 192.168.97.2 k8s-calico2
我们在k8s-calico2这个node上来看。执行ip r, 在这个node的路由中,需要我们关注的有:
192.168.97.2 dev calic285cddbb40 scope link blackhole 192.168.97.0/26 proto bird 192.168.210.192/26 via 10.173.32.26 dev eth0 proto bird 192.168.211.0/26 via 10.173.32.25 dev eth0 proto bird
192.168.97.2 dev calic285cddbb40 scope link
这条路由将通向容器ip的请求导向veth:calic285cddbb40 ,进而让请求直达容器内的网卡。blackhole 192.168.97.0/26 proto bird
表示发往192.168.97.0/26
网段的报文都会被丢弃且不会回复源端。配置这条路由的原因是:这台机器上的calico网络可分配的cidr是192.168.97.0/26
,容器里访问同网段的其他IP时,配置该路由以避免报文被发到外部。
最后两条,分别记录了:要访问calico网络中的某个网段,需要以对应的node IP为网关,通过eth0发包。也就是说通过这两条路由,可以将部分网段(目的IP)的包经由eth0发送到正确的地方。
我们可以这么理解:pod hhh-6897d64fcd-4zph4
中ping huangtest-69d9fddd97-pbvvw
时,流量是这么走的:
0、数据包封装完成,srcip:192.168.97.2 , destip:192.168.210.194
1、容器中只有eth0网卡,容器里ip r 看到的是default **** dev eth0
,所以流量通过容器的eth0发送。
2、容器网卡的配置是通过vethpair做的,也就是说,容器里网卡发的包,在宿主机上都会被calic285cddbb40
设备发出。
3、通过第2步,网络报文就在宿主机的网络中,受宿主机路由影响,192.168.210.192/26 via 10.173.32.26 dev eth0 proto bird
这条路由会将数据从eth0转发,并发给路由中记录的网关:10.173.32.26(这个ip,就是pod huangtest-69d9fddd97-pbvvw
所在的node:k8s-calico3 的ip)
4、10.173.32.26是node:k8s-calico3上eth0的ip,收到包后,在机器自身的路由表中寻找合理的路由,当然这个地方也会有路由:192.168.210.194 dev calif6874dae1d2 scope link
,于是包顺利被对端接收
我们通过ip-ip模式部署calico,然后将原有的pod全部删掉重建,如下:
root@k8s-calico1:~# pods NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE huang1 huangtest-69d9fddd97-2b8hr 1/1 Running 0 1m 192.168.97.1 k8s-calico2 huang1 huangtest-69d9fddd97-npwzw 1/1 Running 0 1m 192.168.210.65 k8s-calico4 huang2 hhh-6897d64fcd-kqsj4 1/1 Running 0 10s 192.168.210.129 k8s-calico3
我们再去看看k8s-calico2这个node 上的路由,同样的需要我们关注的路由有下面的几条:
root@k8s-calico2:~# ip r |grep bird 192.168.97.1 dev cali3683f65394b scope link blackhole 192.168.97.0/26 proto bird 192.168.110.64/26 via 10.173.32.24 dev tunl0 proto bird onlink 192.168.210.64/26 via 10.173.32.25 dev tunl0 proto bird onlink 192.168.210.128/26 via 10.173.32.26 dev tunl0 proto bird onlink
前两条不再赘述,我们看到最后三条路由,其实他们描述的逻辑与BGP的那两条没有差别,只不过网卡换成了tunl0.
我们以一个例子来解释清楚:pod huangtest-69d9fddd97-2b8hr
ping hhh-6897d64fcd-kqsj4
0、封装报文,SRCIP:192.168.97.1 DESTIP:192.168.210.129
1、容器中只有eth0网卡,容器里ip r 看到的是default **** dev eth0
,所以流量通过容器的eth0发送。
2、容器网卡的配置是通过vethpair做的,也就是说,容器里网卡发的包,在宿主机上都会被calic285cddbb40
设备发出。
3、通过第2步,网络报文就在宿主机的网络中,受宿主机路由影响,192.168.210.128/26 via 10.173.32.26 dev tunl0 proto bird onlink
识别到匹配的对端IP,将报文从tunl0发出到10.173.32.26。这里,tunl0会对报文进行封装,在原有的ip报文之上封装了一个ip头部,新的头部中,srcip是宿主机自身的ip:10.173.32.23, destip是对端的ip地址:10.173.32.26。
我们可以通过tcpdump抓包看到这个步骤:
封装前:
封装后(注意到输出内容结尾有ipip-proto-4
):
4、由于宿主机上只有一个eth的物理机网卡,所以流量终究还是从eth0向外发出到10.173.32.26。10.173.32.26这个节点的eth0网卡,收到了报文后,发现带有ipip协议的标记(第3步中tcpdump抓包看到的ipip-proto-4
),将ipip头部解开,于是处理到了真实的报文。
5、宿主机上192.168.210.129 dev cali5ce61eb6bc2 scope link
这个路由将包发给vethpair,从而被容器内的eth0接收。
6、icmp响应包的走向与上述的走向逻辑上相同。