首页 > 代码库 > flannel源码分析(一) 概述

flannel源码分析(一) 概述

随着docker社区的不断壮大, CoreOS、Kubernetes、Hashicorp等项目蓬勃发展。 flannel作为一款专为容器打造的开源网络组件, 也吸引了工程师的关注。flannel简单易用, 只需要同属CoreOS家族的etcd作为一致性存储, 便可配置multi-host的网络连接。

 
下图为flanned的网络原理图, 源自https://github.com/coreos/flannel 。
 
 
技术分享

 

 
可以看到flannel为每台host划分了subnet, 这样就保证多台主机上的多个容器都能拥有独立的ip来互相通信。
 
本文参考flannel-0.6.2来分析flannel的具体实现。
 
 

技术分享

 

 
可以看到flannel源码主要包含以下目录:
backend: ip packet转发的具体实现, 包含udp, vxlan, hostgw, gce... , 默认是udp。
network:  确定backend类型, 写本地env文件。
subnet:    与etcd交互, 确定subnet。
这些目录里的source code, 后续都有详细介绍。
 
现在我们就从main.go开始看一下, flannel的启动过程。 
 
 1 func main() { 2     // glog will log to tmp files by default. override so all entries 3     // can flow into journald (if running under systemd) 4     flag.Set("logtostderr", "true") 5     // now parse command line args 6     flag.Parse() 7     if flag.NArg() > 0 || opts.help { 8         fmt.Fprintf(os.Stderr, "Usage: %s [OPTION]...\n", os.Args[0]) 9         flag.PrintDefaults()10         os.Exit(0)11     }12     if opts.version {13         fmt.Fprintln(os.Stderr, version.Version)14         os.Exit(0)15     }16 17     flagutil.SetFlagsFromEnv(flag.CommandLine, "FLANNELD")18     19     // 创建SubnetManager用于划分子网20     sm, err := newSubnetManager()21     if err != nil {22         log.Error("Failed to create SubnetManager: ", err)23         os.Exit(1)24     }25     // Register for SIGINT and SIGTERM26     log.Info("Installing signal handlers")27     sigs := make(chan os.Signal, 1)28     signal.Notify(sigs, os.Interrupt, syscall.SIGTERM)29     // 设置可以cancle的context30     ctx, cancel := context.WithCancel(context.Background())31     var runFunc func(ctx context.Context)32     if opts.listen != "" {33         if opts.remote != "" {34             log.Error("--listen and --remote are mutually exclusive")35             os.Exit(1)36         }37         log.Info("running as server")38         runFunc = func(ctx context.Context) {39             remote.RunServer(ctx, sm, opts.listen, opts.remoteCAFile, opts.remoteCertfile, opts.remoteKeyfile)40         }41     } else {42         nm, err := network.NewNetworkManager(ctx, sm)43         if err != nil {44             log.Error("Failed to create NetworkManager: ", err)45             os.Exit(1)46         }47         runFunc = func(ctx context.Context) {48             nm.Run(ctx)49         }50     }51     wg := sync.WaitGroup{}52     wg.Add(1)53     go func() {54         runFunc(ctx)    // 在一个新的goroutine中运行NetworkManager的Run函数55         wg.Done()56     }()57     <-sigs58     // unregister to get default OS nuke behaviour in case we don‘t exit cleanly59     signal.Stop(sigs)60     log.Info("Exiting...")61     62     // 收到信号后,掉用cancle函数, 取消所有相关的子context63     cancel()64     wg.Wait()65 }

 

由上述的代码可以看出, 根据参数listen和remote可以设置flannel为server模式或client模式, server模式对外提供服务, 并不能加入到flannel的网络。 client模式下NetworkManager的Run函数是程序执行的入口, 设置flannel的subnet。

下一篇将分析NetworkManager对应的源码。

 

关于go context的用法, 请参考以下两篇博文。

https://segmentfault.com/a/1190000006744213

http://blog.csdn.net/xiaohu50/article/details/49100433

 

 

flannel源码分析(一) 概述