flannel 实战与源码分析(五)

来源:互联网 发布:linux开机启动mysql 编辑:程序博客网 时间:2024/06/05 01:01

上一篇介绍的vxlan模式,本篇还想介绍一个host-gw模式,顾名思义,就是主机网关模式。这个和calico的路由模式中主机网关是一样的,只不过没有BGP罢了。
先介绍一下怎么使用,然后分析了源码。先设置一下网络模式

etcdctl set  /flannel/network/config  '{"Network": "192.168.0.0/16","SubnetLen": 24,"SubnetMin": "192.168.1.0","SubnetMax": "192.168.100.0","Backend": {"Type": "host-gw"}}'

这样就设置好了,重启flannel和docker就行了。简单!
测试一下

19: eth0@if20: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue     link/ether 02:42:c0:a8:45:02 brd ff:ff:ff:ff:ff:ff    inet 192.168.69.2/24 scope global eth0       valid_lft forever preferred_lft forever    inet6 fe80::42:c0ff:fea8:4502/64 scope link        valid_lft forever preferred_lft forever/ # / # ping 192.168.49.2PING 192.168.49.2 (192.168.49.2): 56 data bytes64 bytes from 192.168.49.2: seq=0 ttl=62 time=1.179 ms64 bytes from 192.168.49.2: seq=1 ttl=62 time=0.675 ms64 bytes from 192.168.49.2: seq=2 ttl=62 time=6.091 ms

网络是联通的,下面分析一下网络路由

ip routedefault via 10.39.0.1 dev eth0  proto static  metric 100 10.39.0.0/24 dev eth0  proto kernel  scope link  src 10.39.0.53  metric 100 192.168.0.0/16 dev flannel.1 192.168.49.0/24 via 10.39.0.45 dev eth0 192.168.69.0/24 dev docker0  proto kernel  scope link  src 192.168.69.1 

这里面通过192.168.49.0/24 via 10.39.0.45 dev eth0 将流量通过eth0发送出去
在另一台机器商量也有对应的

ip routedefault via 10.39.0.1 dev eth0  proto static  metric 100 10.39.0.0/24 dev eth0  proto kernel  scope link  src 10.39.0.45  metric 100 192.168.0.0/16 dev flannel.1 192.168.49.0/24 dev docker0  scope link 192.168.69.0/24 via 10.39.0.53 dev eth0 

通过路由互通,这个和calico很相似
下面通过抓包查看
这里写图片描述
从eth0抓取的包可以看出,这就是路由转发,没有overlay封包。源mac为宿主机mac,目的mac为目的宿主机的mac地址,源IP为宿主机IP,目的IP为目标容器的IP,什么情况?目的IP为啥不是容器的IP呢?你可能忘记docker自带的SANT了

-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERAD

这主要是为了屏蔽docker自己的IP,将容器内部出去的流量通过SNAT修改为宿主机的IP,避免暴露容器。那么这个就不符合kubernetes对容器网络的定义,这里我一直强调的是概念的理解。那么你可以把这个规则删除就可以了这样,网络就可以,看看现在抓包结果
这里写图片描述
这样容器就能看到对方容器的IP了。分析完原理,我们再进入代码讲解,它的代码比较简单,关于网段租赁的代码之前有讲解再次不再赘述,主要看看路由是怎么下发的吧

func (n *network) handleSubnetEvents(batch []subnet.Event) {    for _, evt := range batch {        switch evt.Type {        case subnet.EventAdded:            log.Infof("Subnet added: %v via %v", evt.Lease.Subnet, evt.Lease.Attrs.PublicIP)            if evt.Lease.Attrs.BackendType != "host-gw" {                log.Warningf("Ignoring non-host-gw subnet: type=%v", evt.Lease.Attrs.BackendType)                continue            }            route := netlink.Route{                Dst:       evt.Lease.Subnet.ToIPNet(),                Gw:        evt.Lease.Attrs.PublicIP.ToIP(),                LinkIndex: n.linkIndex,            }            // Check if route exists before attempting to add it            routeList, err := netlink.RouteListFiltered(netlink.FAMILY_V4, &netlink.Route{                Dst: route.Dst,            }, netlink.RT_FILTER_DST)            if err != nil {                log.Warningf("Unable to list routes: %v", err)            }            //   Check match on Dst for match on Gw            if len(routeList) > 0 && !routeList[0].Gw.Equal(route.Gw) {                // Same Dst different Gw. Remove it, correct route will be added below.                log.Warningf("Replacing existing route to %v via %v with %v via %v.", evt.Lease.Subnet, routeList[0].Gw, evt.Lease.Subnet, evt.Lease.Attrs.PublicIP)                if err := netlink.RouteDel(&route); err != nil {                    log.Errorf("Error deleting route to %v: %v", evt.Lease.Subnet, err)                    continue                }            }            if len(routeList) > 0 && routeList[0].Gw.Equal(route.Gw) {                // Same Dst and same Gw, keep it and do not attempt to add it.                log.Infof("Route to %v via %v already exists, skipping.", evt.Lease.Subnet, evt.Lease.Attrs.PublicIP)            } else if err := netlink.RouteAdd(&route); err != nil {                log.Errorf("Error adding route to %v via %v: %v", evt.Lease.Subnet, evt.Lease.Attrs.PublicIP, err)                continue            }            n.addToRouteList(route)        case subnet.EventRemoved:            log.Info("Subnet removed: ", evt.Lease.Subnet)            if evt.Lease.Attrs.BackendType != "host-gw" {                log.Warningf("Ignoring non-host-gw subnet: type=%v", evt.Lease.Attrs.BackendType)                continue            }            route := netlink.Route{                Dst:       evt.Lease.Subnet.ToIPNet(),                Gw:        evt.Lease.Attrs.PublicIP.ToIP(),                LinkIndex: n.linkIndex,            }            if err := netlink.RouteDel(&route); err != nil {                log.Errorf("Error deleting route to %v: %v", evt.Lease.Subnet, err)                continue            }            n.removeFromRouteList(route)        default:            log.Error("Internal error: unknown event type: ", int(evt.Type))        }    }}

先介绍一下添加网络事件EventAdded,先是创建一个路由对象,查找本地路由比对:
如果目的地址一样但网关不一样,删了重建
如果已经有重复的则不做任何操作
如果没有这条路由则通过RouteAdd添加到本地路由表中并通过addToRouteList写到本地缓存中
删除的逻辑就粗暴了直接删除本地路由表和本地缓存。这样路由管理就完成了。

0 0