通读Flannel代码以及如何编写backend进行网络开发

Flannel代码组织

代码privatepublic结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
├── backend
│   ├── alivpc
│   ├── alloc
│   ├── awsvpc
│   ├── common.go
│   ├── extension
│   ├── gce
│   ├── hostgw
│   ├── hostgw_ocean
│   ├── kscvpc
│   ├── kscvpc_ocean
│   ├── manager.go
│   ├── udp
│   └── vxlan
├── bill-of-materials.json
├── bill-of-materials.override.json
├── CONTRIBUTING.md
├── DCO
├── dist
│   ├── bill-of-materials.sh
│   ├── extension-hostgw
│   ├── extension-vxlan
│   ├── fake-node.yaml
│   ├── functional-test.sh
│   ├── iptables-amd64
│   ├── iptables-arm
│   ├── iptables-arm64
│   ├── iptables-ppc64le
│   ├── iptables-s390x
│   ├── license-check.sh
│   ├── mk-docker-opts.sh
│   ├── mk-docker-opts_tests.sh
│   └── sample_subnet.env
├── Dockerfile.amd64
├── Dockerfile.arm
├── Dockerfile.arm64
├── Dockerfile.ppc64le
├── Dockerfile.s390x
├── Documentation
│   ├── alicloud-vpc-backend.md
│   ├── aws-vpc-backend.md
│   ├── backends.md
│   ├── building.md
│   ├── configuration.md
│   ├── extension.md
│   ├── gce-backend.md
│   ├── img
│   ├── integrations.md
│   ├── k8s-manifests
│   ├── kube-flannel-aliyun.yml
│   ├── kube-flannel.yml
│   ├── Kubernetes.md
│   ├── minikube.yml
│   ├── production-users.md
│   ├── reporting_bugs.md
│   ├── reservations.md
│   ├── running.md
│   └── troubleshooting.md
├── glide.lock
├── glide.yaml
├── LICENSE
├── license-check.sh
├── logos
│   ├── flannel-glyph-color.png
│   ├── flannel-glyph-color.svg
│   ├── flannel-glyph-white.png
│   ├── flannel-glyph-white.svg
│   ├── flannel-horizontal-bw.png
│   ├── flannel-horizontal-bw.svg
│   ├── flannel-horizontal-color.png
│   ├── flannel-horizontal-color.svg
│   ├── flannel-horizontal-white.png
│   └── flannel-horizontal-white.svg
├── main.go
├── MAINTAINERS
├── Makefile
├── network
│   ├── iptables.go
│   └── iptables_test.go
├── NOTICE
├── packet-01.png
├── pkg
│   └── ip
├── README.md
├── subnet
│   ├── config.go
│   ├── config_test.go
│   ├── etcdv2
│   ├── kube
│   ├── subnet.go
│   └── watch.go
├── tools
│   └── token.go
├── vendor
│   ├── cloud.google.com
│   ├── github.com
│   ├── golang.org
│   ├── google.golang.org
│   ├── gopkg.in
│   └── k8s.io
└── version
└── version.go

比较重要的就是backendnetwork pkg subnet tools等目录,其中main.go为入口

main.go

backend实现

backendinterface定义

1
2
3
4
type Backend interface {
// Called when the backend should create or begin managing a new network
RegisterNetwork(ctx context.Context, wg *sync.WaitGroup, config *subnet.Config) (Network, error)
}

只需要实现RegisterNetwork方法,但是它返回的是一个Network interface,所以还需要实现Network接口
其中host-gw的实现

host-gw

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// backend需要实现的RegisterNetwork
n := &network{
extIface: be.extIface,
sm: be.sm,
}

attrs := subnet.LeaseAttrs{
PublicIP: ip.FromIP(be.extIface.ExtAddr),
BackendType: "host-gw",
}
l, err := be.sm.AcquireLease(ctx, &attrs)
switch err {
case nil:
n.lease = l

case context.Canceled, context.DeadlineExceeded:
return nil, err

....

主要就是申请了一个lease(租约),并赋值给实现的NetWork
申请lease主要的调用链

1
AcquireLease-->tryAcquireLease

tryAcquireLease更多是为了找到一个适合的subnet(这些信息保存在etcdv2)里,然后组成network实例
然后就是核心逻辑networkRun方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
func (n *network) Run(ctx context.Context) {
wg := sync.WaitGroup{}

log.Info("Watching for new subnet leases")
evts := make(chan []subnet.Event)
wg.Add(1)
go func() {
subnet.WatchLeases(ctx, n.sm, n.lease, evts)
wg.Done()
}()

// Store a list of routes, initialized to capacity of 10.
n.rl = make([]netlink.Route, 0, 10)
wg.Add(1)

// Start a goroutine which periodically checks that the right routes are created
go func() {
n.routeCheck(ctx)
wg.Done()
}()

defer wg.Wait()

for {
select {
case evtBatch := <-evts:
n.handleSubnetEvents(evtBatch)

case <-ctx.Done():
return
}
}
}

WatchLeases通过监听etcd里的subnet变化,返回event切片,然后写入evts管道
handleSubnetEvents消费evts管道里的消息,根据evt.Type执行不同的操作也就是
addToRouteListremoveFromRouteList来增删子网路由
这些路由都是在宿主机上的

host-gw-ocean

自研的backend,主要是把路由写到交换机上
它的流程与host-gw相同
但是他的核心逻辑addRouteRegisterNetwork方法里,主要的功能是http调用交换机接口,把子网信息和网关写到交换机上,由交换机广播出去
但是delRouteRun里,这里估计调用不了defer ,因为Run里面有个for循环不断监听子网变化evt
为什么没写在handleSubnetEvents,我理解应该是因为其他机器子网的添加,不需要维护交换机,由所在node上的flannel进城维护子网即可