Flannel

Flannel是CoreOS团队针对Kubernetes设计的一个网络规划服务,简单来说,它的功能是让集群中的 不同节点主机创建的Docker容器都具有全集群唯一的虚拟IP地址。

Flannel聚焦于网络,而非网络策略。

工作原理

Flannel在每个主机上运行一个小的单一二进制代理,称为flanneld,并负责从更大的预配置地址空间中 为每个主机分配子网租约。 Flannel直接使用Kubernetes API或etcd来存储网络配置,分配的子网和 任何辅助数据(例如主机的公共IP)。 使用多种后端机制之一转发数据包,包括VXLAN和各种云集成。

在默认的Docker配置中,每个Node的Docker服务会分别负责所在节点容器的IP分配。Node内部的容器 之间可以相互访问,但是跨主机(Node)网络相互间是不能通信。Flannel设计目的就是为集群中所有节点 重新规划IP地址的使用规则,从而使得不同节点上的容器能够获得”同属一个内网”且”不重复的”IP地址, 并让属于不同节点上的容器能够直接通过内网IP通信。

Flannel 使用etcd存储配置数据和子网分配信息。flannel 启动之后,后台进程首先检索配置和正在 使用的子网列表,然后选择一个可用的子网,然后尝试去注册它。etcd也存储这个每个主机对应的ip。 flannel 使用etcd的watch机制监视/coreos.com/network/subnets下面所有元素的变化信息,并且根据 它来维护一个路由表。为了提高性能,flannel优化了Universal TAP/TUN设备,对TUN和UDP之间的ip 分片做了代理。

报文传输路径

数据从源容器中发出后,经由所在主机的docker0虚拟网卡转发到flannel.1虚拟网卡。

Flannel通过Etcd服务维护了一张节点间的路由表,该张表里保存了各个节点主机的子网网段信息。

源主机的flanneld服务将原本的数据内容UDP封装后根据自己的路由表投递给目的节点的flanneld服务, 数据到达以后被解包,然后进入目的节点的flannel.1虚拟网卡,再然后被转发到目的主机的docker0虚拟网卡, 最后就像本机容器通信一样的由docker0路由到目标容器。

在最外层报文,是有A主机到B主机, 然后再将报文解封装到目标的虚拟机中。

编译及安装

sudo yum install kernel-headers golang gcc glibc-static

下载代码 :

编译 :

CGO_ENABLED=1 make dist/flanneld

后端支持

推荐使用内核VXLAN封装数据包。还支持host-gw/UDP等等。

使用host-gw通过远程计算机IP创建到子网的IP路由。 host-gw需要运行flannel的主机之间具有 直接的layer2连接。因此在云上不能使用。

host-gw具有良好的性能,几乎没有依赖关系,并且易于设置。

运行

首先启动etcd, 然后进行基本设置

$ etcd &

$ systemctl start etcd

然后在etcd中添加flannel配置

$ etcdctl set /coreos.com/network/config '{ "Network": "10.5.0.0/16", "Backend": {"Type": "vxlan"}}'

启动flanneld

[zhang@localhost flannel]$ sudo ./dist/flanneld [sudo] password for zhang: I0918 01:50:49.978004 7651 main.go:518] Determining IP address of default interface I0918 01:50:49.980126 7651 main.go:531] Using interface with name enp0s3 and address 10.0.2.15 I0918 01:50:49.980163 7651 main.go:548] Defaulting external address to interface address (10.0.2.15) I0918 01:50:49.980453 7651 main.go:246] Created subnet manager: Etcd Local Manager with Previous Subnet: 10.5.58.0/24 I0918 01:50:49.980471 7651 main.go:249] Installing signal handlers I0918 01:50:49.983762 7651 main.go:390] Found network config - Backend type: vxlan I0918 01:50:49.983834 7651 vxlan.go:121] VXLAN config: VNI=1 Port=0 GBP=false Learning=false DirectRouting=false I0918 01:50:49.988488 7651 local_manager.go:147] Found lease (10.5.58.0/24) for current IP (10.0.2.15), reusing I0918 01:50:49.992472 7651 main.go:313] Changing default FORWARD chain policy to ACCEPT I0918 01:50:49.992804 7651 main.go:321] Wrote subnet file to /run/flannel/subnet.env I0918 01:50:49.992829 7651 main.go:325] Running backend. I0918 01:50:50.002762 7651 vxlan_network.go:60] watching for new subnet leases I0918 01:50:50.003475 7651 main.go:433] Waiting for 22h59m59.985730351s to renew lease

进程启动成功后, 将创建VXLAN tunnel设备, 我这里设备名称为flannel.1, 可以查看配置

$ cat /run/flannel/subnet.env

FLANNEL_NETWORK=10.5.0.0/16 FLANNEL_SUBNET=10.5.58.1/24 FLANNEL_MTU=1450 FLANNEL_IPMASQ=false

可以通过”ip -d addr”查看flannel.1网卡信息, 选项”-d”表示输出详细信息

[root@zhang1 ckd]#  ip -d addr show flannel.1
4: flannel.1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN group default
        link/ether 2e:89:bf:b4:cd:aa brd ff:ff:ff:ff:ff:ff promiscuity 0
        vxlan id 1 local 192.168.101.180 dev enp0s8 srcport 0 0 dstport 8472 nolearning ageing 300 noudpcsum noudp6zerocsumtx noudp6zerocsumrx numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
        inet 10.244.0.0/32 brd 10.244.0.0 scope global flannel.1
           valid_lft forever preferred_lft forever
        inet6 fe80::2c89:bfff:feb4:cdaa/64 scope link
           valid_lft forever preferred_lft forever

从以上输出可以看到,flannel.1的local IP为192.168.101.180,目的端口为8472。MTU值为 1450, 比通常网卡的mtu 1500要小。 vxlan网络IP为10.244.0.0/32。

通过k8s安装

flannel也可以运行在容器中,它的网络模式为host模式,即hostNetwork为true.

flannel自己的控制器如果作为pod来部署的话是一个demonset,一个节点上只运行一个pod副本,相当于模拟运行了系统级的守护进程。 并且这个pod副本和宿主机共享网络名称空间。

创建命令为

kubectl apply -f kube-flannel.yml

kube-flannel.yml在代码库中有提供,地址为: https://github.com/coreos/flannel.git仓库下Documentation/kube-flannel.yml

kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

诊断

kubectl get po –namespace kube-system -l app=flannel

kubectl logs –namespace kube-system <POD_ID> -c kube-flannel

问题,没有默认路由错误

输出以下错误

[zhang@localhost flannel]$ sudo ./dist/flanneld
I0920 21:47:11.200976    2224 main.go:518] Determining IP address of default interface
E0920 21:47:11.201471    2224 main.go:204] Failed to find any valid interface to use: failed to get default interface: Unable to find default route

解决方法:增加默认路由, 我这里有NAT网卡可以出去,因此通过dhcp分配ip及默认路由即可。

$ sudo dhclient enp0s3

参考资料

https://github.com/coreos/flannel/blob/master/Documentation/running.md

https://github.com/coreos/flannel/blob/master/Documentation/kubernetes.md

VxLAN https://tools.ietf.org/html/rfc7348