k8s网络插件-flannel
一、Bridge网络介绍
1.网络模型图
2.Bridge网络的构建过程,对上图的各个网络名称做解释说明
(1)安装Docker时,创建一个名为docke0的虚拟网桥,虚拟网桥使用“10.0.0.0-10.255.255.255 “、”172.16.0.0-172.31.255.255″和“192.168.0.0——192.168.255.255”这三个私有网络的地址范围。
通过 ifconfig命令可以查看docker0网桥的信息:
通过 docker network inspect bridge 可以查看网桥的子网网络范围和网关:
(2)运行容器时,会在宿主机上创建虚拟网卡vethpair设备,vethpair设备是成对出现的,从而组成一个数据通道,数据从一个设备进入,就会从另一个设备出来。将vethpair设备的一端放在新创建的容器中,命名为eth0;另一端放在宿主机的docker0中,以veth为前缀的名字命名。通过brctlshow 命令查看放在docker0中的veth pair设备
ifconfig
brctl show
3.外部访问
bridge的docker0是虚拟出来的网桥,因此无法被外部的网络访问。因此需要在运行容器时通过-p和-P参数将容器的端口映射到宿主机上相应的端口。实际上Docker是采用NAT的方式,将容器内部的服务监听端口与宿主机的某一个端口port 进行绑定,使得宿主机外部可以将网络报文发送至容器。
1)通过-P参数,将容器的端口映射到宿主机的随机端口:
docker run -P {images}
2)通过-p参数,将容器的端口映射到宿主机的制定端口:
docker run -p {hostPort}:{containerPort} {images}
二、kubernetes常见的网络通信方式
1、pod内部容器间的通信:同一个pod内的多个容器间的通信
2、pod和pod之间的通信:从一个pod Ip到另一个pod Ip
3、pod与service通信:pod ip到serviceip
(1)pod内部容器之间通信
pod内部的容器是共享网络名称空间的,所以容器直接可以使用localhost访问其他容器;k8s在启动容器的时候会先启动一个Pause容器,这个容器就是实现这个功能的。
pause:
每个Pod里运行着一个特殊的被称之为Pause的容器,其他容器则为业务容器,这些业务容器共享Pause容器的网络栈和Volume存储卷,因此他们之间通信和数据交换更为高效,在设计时我们可以充分利用这一特性将一组密切相关的服务进程放入同一个Pod中。
(2)pod与pod之间的通信
此种类型又分为两种情况:
两个pod在同一台节点上:此时是利用docker默认的网桥bridge方式互连容器的。
两个pod在不同节点上:这种情况k8s官方推荐的是使用flannel网络,pod的ip分配由flannel统一分配,通讯过程也是走flannel的网桥方式。
(3)pod与service服务之间的通信
通过暴露主机IP和端口的形式进行通讯
要解决上面的几种通信问题,需要靠CNI网络插件实现
要解决上面四种通信的问题,需要靠CNI插件接口:
kubernetes中的网络插件
Kubernetes中常见的网络插件有哪些?
1.flannel:能提供ip地址,但不支持网络策略
2.calico:既提供ip地址,又支持网络策略
3.canal:flannel和calico结合,通过flannel提供ip地址,calico提供网络策略
什么叫做网络策略?
网络策略:可以达到多租户网络隔离,可以控制入网和出网流量,入网和出网ip访问的一种策略
三、flannel网络方案
1、flannel介绍
Flannel是CoreOS团队针对Kubernetes设计的一个网络服务,它的功能是让集群中的不同节点创建的Docker容器都具有全集群唯一的虚拟IP地址,Flannel的设计目的就是为集群中的所有节点重新规划IP地址,从而使得不同节点上的容器能够获得“同属一个内网”且”不重复的”IP地址,并让属于不同节点上的容器能够直接通过内网IP通信,Flannel实质上是一种“覆盖网络(overlaynetwork)”,也就是将TCP数据包装在另一种网络包里面进行路由转发和通信,目前已经支持udp、vxlan、host-gw、aws-vpc、gce路由等数据转发方式。
2、flannel支持的路由转发方式
1、vxlan(源数据包封装在另一种网络包里面进行路由转发和通信)
包含以下两种模式
- vxlan:叠加网络模式,利用内核级别的VXLAN来封装host之间传送的包;
- Directrouting:直接路由模式,当主机位于同一子网时,启用直接路由(类似host-gw),通过宿主机的物理网卡通信;
2、host-gw:直接路由模式,要求所有pod在同一个网段中,host-gw性能好,依赖少,并且易于设置。Flannel通过在各个节点上的Agent进程,将容器网络的路由信息刷到主机的路由表上,这样一来所有的主机都有整个容器网络的路由数据了。
3、UDP:不可用于生产环境,仅在内核或网络无法使用VXLAN或 host-gw时,用 UDP 进行调试。最早支持的一种方式,由于性能最差,目前已经弃用
VXLAN
# kubeadm部署指定Pod网段
kubeadm init --pod-network-cidr=10.244.0.0/16
# 二进制部署指定
cat /opt/kubernetes/cfg/kube-controller-manager.conf --allocate-node-cidrs=true \ --cluster-cidr=10.244.0.0/16 \ # kube-flannel.yml net-conf.json: | { "Network": "10.244.0.0/16", "Backend": { "Type": "vxlan" } }
flannel网络原理图
原理图解释说明
1.网卡和组件说明
安装flannel时会创建一个名为flannel0的网桥,这个网桥的一端连接docker0的网桥,另一端连接一个名为flanneld的服务进程。
Flanneld守护进程:它需要连etcd,利用etcd来管理可分配的IP资源,同时监控etcd中每个Pod的实际地址,将docker0发给它的数据包装起来,利用物理网络的连接将数据包投递到目标flanneld上,从而完成pod到pod之间的通信
2.ping包走向
(1)数据从源容器中发出后,经由所在主机的docker0虚拟网卡转发到flannel0虚拟网卡,flanneld服务监听在网卡的另外一端。
(2)源主机的flanneld服务将原本的数据内容封装成一个数据包,然后根据自己的路由表投递给目的节点的flanneld服务,数据到达以后被解包,然后直接进入目的节点的flannel0虚拟网卡,然后被转发到目的主机的docker0虚拟网卡,最后就像本机容器通信一样由docker0路由到达目标容器。
注:
flannel通过Etcd分配了每个节点可用的IP地址段后,可以保证每个结点上容器分配的地址不冲突。
四、flannel的原理
flannel旨在解决不同节点上的容器网络互联问题,大致原理是为每个 host 分配一个子网,容器从此子网中分配IP,这些 IP可以在 host间路由,容器间无需 NAT 转发就可以跨主机通信,为了在各个主机间共享信息,flannel 用 etcd(如果是k8s集群会直接调用k8s api)存放网络配置、已分配的子网、主机ip等信息。
通过具体例子解释容器跨节点通信时数据包走向
假设容器1是nginx,容器2是tomcat
(1)在发送端的node1节点上,数据请求从nginx容器(10.0.46.2:2379)发出后,首先经由所在主机的docker0虚拟网卡(10.0.46.1)转发到flannel0虚拟网卡(10.0.46.0)。
(2)接着flannel服务将原本的数据内容UDP封装后根据自己的路由表投递给目的节点的flanneld服务。在此包中,包含有router-ip(宿主机源ip:192.168.8.227 ;宿主机目的ip:192.168.8.228),还有容器ip(source:10.0.46.2:2379dest:10.0.90.2:8080)等数据信息。
(3)然后在接收端node2节点上,数据到达以后被解包,直接进入目的节点的flannel0虚拟网卡中(10.0.90.0),且被转发到目的主机的docker0虚拟网卡(10.0.90.1),最后就像本机容器通信一样由docker0路由到达目标 tomcat 容器(10.0.90.2:8080)。
五、flannel部署及参数配置
1.部署
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
kubectl get pods -n kube-system -o wide 显示如下:
kubectl get configmap -n kube-system 显示如下:
这个kube-flannel-cfg用来设置上面看到的flannel是怎么运行的,它可以把相关的变量注入到flannel的pod中。
kubectl get configmap kube-flannel-cfg -n kube-system -o yaml可显示configmap的yaml文件内容,具体内容在备注列出
net-conf.json: | { "Network": "10.244.0.0/16", "Backend": { "Type": "vxlan" } } 上面可以看到使用的后端网络模型是vxlan,为pod分配的网段是10.244.0.0/16
2.把flannel后端的通信类型修改成Directrouting
重新修改flannel的yaml文件
cd/root/manifests/
mkdir flannel
cd flannel
修改kube-flannel.yml文件
kube-flannel.yaml这个文件里在net-conf.json字段增加了”Directrouting”: true,表示是使用直接路由模式,如果没有这个字段就表示使用的是vxlan这种叠加网络模式通信。
kubectl delete -f kube-flannel.yml
等到上面关于flannel的pod都删除之后再重新执行:
kubectl apply -f kube-flannel.yml
kubectl get pods -n kube-system 显示如下,说明重新生成了flannel这个pod,这时后端通信类型使用的就是directrouting了
验证是否是通过Directrouting(直接路由模式)通信
cd /root/manifests
kubectl apply -f deploy-myapp.yaml
cat deploy-myapp.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: myapp-deploy namespace: default spec: replicas: 3 selector: matchLabels: app: myapp release: canary template: metadata: labels: app: myapp release: canary spec: containers: - name: myapp image: ikubernetes/myapp:v1 ports: - name: http containerPort: 80
kubectl get pods -o wide 显示如下,说明pod创建成功:
窗口1:
kubectl exec -itmyapp-deploy-69b47bc96d-7s7zs -- /bin/sh
窗口2:
kubectl exec -itmyapp-deploy-69b47bc96d-lm4m4 -- /bin/sh
ping10.244.0.6
窗口3:抓包
tcpdump -i ens160 -nnhost 172.21.0.100 显示如下:
上面可以看到两个pod之间的通信是通过ens160,而不是overlay(覆盖网络),这样就提高了网络传输性能;如果两个节点是跨网段的,那么就会降级到vxlan(叠加网络)模式,否则就可以使用直接路由模式。
3.把flannel的后端通信方式改成host-gw
修改kube-flannel.yml文件的如下部分
net-conf.json: | { "Network":"10.244.0.0/16", "Backend":{ "Type":"host-gw" } }
注:上面修改flannel的网络模式,一般在刚开始安装flannel的时候修改,不要在线上直接修改
4.flannel中vxlan和host-gw的区别
vxlan模式下的的vxlan是一种覆盖网络;host-gw是直接路由模式,将主机作为网关,依赖于纯三层的ip转发。
不同网络模型的性能分析
1.vxlan的Directrouting模式和host-gw模式性能一样,都是通过宿主机的物理网络进行通信,效率高于vxlan的vxlan模式,但是不能实现跨网段通信; 2.如果要跨网段通信vxlan的Directrouting模式会自动降级到vxlan的vxlan这种叠加网络模式
5.Flannel网络优点:
1)集群中的不同Node主机创建的Docker容器都具有全集群唯一的虚拟IP地址。
2)etcd保证了所有node上flanned所看到的配置是一致的,同时每个node上的flanned监听etcd上的数据变化,实时感知集群中node的变化
6.Flannel网络缺点:
不支持pod之间的网络隔离,不支持网路策略
六、卸载flannel网络
#第一步,在master节点删除flannel
kubectl delete -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
#第二步,在node节点清理flannel网络留下的文件
ifconfig cni0 down ip link delete cni0 ifconfig flannel.1 down ip link delete flannel.1 rm -rf /var/lib/cni/ rm -f /etc/cni/net.d/* 注:执行完上面的操作,重启kubelet
#第三步,应用calico相关的yaml文件
七、有待梳理
源地址:https://mp.weixin.qq.com/s/J0rV2gPzb-lx3ldJa2U4Tg
为了能够在二层网络上打通“隧道”,VXLAN 会在宿主机上设置一个特殊的网络设备作为“隧道”的两端。这个设备就叫 VTEP,即:VXLAN Tunnel End Point(虚拟隧道端点)。下图flannel.1的设备就是VXLAN所需的VTEP设备。示意图如下
1. 容器路由:容器根据路由表从eth0发出
# ip route
default via 10.244.0.1 dev eth0
10.244.0.0/24 dev eth0 scope link src 10.244.0.45
10.244.0.0/16 via 10.244.0.1 dev eth0
2. 主机路由:数据包进入到宿主机虚拟网卡cni0,根据路由表转发到flannel.1虚拟网卡,也就是来到了隧道的入口。
# ip route
default via 192.168.31.1 dev ens33 proto static metric 100
10.244.0.0/24 dev cni0 proto kernel scope link src 10.244.0.1
10.244.1.0/24 via 10.244.1.0 dev flannel.1 onlink
10.244.2.0/24 via 10.244.2.0 dev flannel.1 onlink
最后一条规则意思是,凡是发往10.244.2.0/24网段的数据包,都需要经过flannel.1设备发出,并且网关地址是10.244.2.0,即Node2 VTEP设备flannel.1。
3. VXLAN封装:而这些VTEP设备之间组成一个二层网络,但是二层网络必须要知道目的MAC地址,那这个MAC地址从哪获取到呢?其实在flanneld进程启动后,就会自动添加其他节点ARP记录,可以通过ip命令查看,如下所示:
# ip neigh show dev flannel.1
10.244.1.0 lladdr ca:2a:a4:59:b6:55 PERMANENT
10.244.2.0 lladdr d2:d0:1b:a7:a9:cd PERMANENT
可以看到10.244.2.0对应MAC地址是d2:d0:1b:a7:a9:cd。
4. 二次封包:知道了目的MAC地址,Linux内核就可以进行二层封包了。但是,对于宿主机网络来说这个二层帧并不能在宿主机二层网络里传输。所以接下来,Linux内核还要把这个数据帧进一步封装成为宿主机网络的一个普通数据帧,好让它载着内部数据帧,通过宿主机的eth0网卡进行传输。
5. 封装到UDP包发出去:在封装成宿主机网络可传输的数据帧时,还缺少目标宿主机MAC地址,也就是说这个UDP包该发给哪台宿主机呢?
flanneld进程也维护着一个叫做FDB的转发数据库,所以使用这个目的IP与MAC地址进行封装。
6. 数据包到达目的宿主机:是宿主机与宿主机之间通信了,数据包从Node1的eth0网卡发出去,Node2接收到数据包,解封装发现是VXLAN数据包,把它交给flannel.1设备。flannel.1设备则会进一步拆包,取出原始IP包(源容器IP和目标容器IP),通过cni0网桥二层转发给容器。