flannel 实战与源码分析(三)

2024-05-10 18:08
文章标签 分析 实战 源码 flannel

本文主要是介绍flannel 实战与源码分析(三),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

之前一直介绍flannel的使用,现在正是进入代码讲解,看看flannel是如何实现的,先看启动


func main() {flag.Set("logtostderr", "true")// 解析参数flag.Parse()if flag.NArg() > 0 || opts.help {fmt.Fprintf(os.Stderr, "Usage: %s [OPTION]...\n", os.Args[0])flag.PrintDefaults()os.Exit(0)}if opts.version {fmt.Fprintln(os.Stderr, version.Version)os.Exit(0)}flagutil.SetFlagsFromEnv(flag.CommandLine, "FLANNELD")// 确定使用的端口extIface, err := LookupExtIface(opts.iface)if err != nil {log.Error("Failed to find interface to use: ", err)os.Exit(1)}sm, err := newSubnetManager()if err != nil {log.Error("Failed to create SubnetManager: ", err)os.Exit(1)}// 注册 SIGINT and SIGTERM信号监听log.Info("Installing signal handlers")sigs := make(chan os.Signal, 1)signal.Notify(sigs, os.Interrupt, syscall.SIGTERM)ctx, cancel := context.WithCancel(context.Background())go shutdown(sigs, cancel)// 获取网络配置如backend等config, err := getConfig(ctx, sm)if err == errCanceled {exit()}// 创建backend manager bm := backend.NewManager(ctx, sm, extIface)be, err := bm.GetBackend(config.BackendType)if err != nil {log.Errorf("Error fetching backend: %s", err)exit()}bn, err := be.RegisterNetwork(ctx, config)if err != nil {log.Errorf("Error registering network: %s", err)exit()}// 启动ipmasqif opts.ipMasq {err = network.SetupIPMasq(config.Network)if err != nil {log.Errorf("Failed to set up IP Masquerade: %v", err)}defer func() {if err := network.TeardownIPMasq(config.Network); err != nil {log.Errorf("Failed to tear down IP Masquerade: %v", err)}}()}if err := WriteSubnetFile(opts.subnetFile, config.Network, opts.ipMasq, bn); err != nil {log.Warningf("Failed to write subnet file: %s", err)} else {log.Infof("Wrote subnet file to %s", opts.subnetFile)}// 启动 backend network阻塞直到服务启动go bn.Run(ctx)log.Infof("Finished starting backend.")daemon.SdNotify(false, "READY=1")// 重新租约_ = MonitorLease(ctx, sm, bn)exit()
}

上面的代码是服务的入口,先解析参数,在之前的应用的时候就有使用参数

flag.StringVar(&opts.etcdEndpoints, "etcd-endpoints", "http://127.0.0.1:4001,http://127.0.0.1:2379", "a comma-delimited list of etcd endpoints")flag.StringVar(&opts.etcdPrefix, "etcd-prefix", "/coreos.com/network", "etcd prefix")flag.StringVar(&opts.iface, "iface", "", "interface to use (IP or name) for inter-host communication")flag.StringVar(&opts.subnetFile, "subnet-file", "/run/flannel/subnet.env", "filename where env variables (subnet, MTU, ... ) will be written to")flag.IntVar(&opts.subnetLeaseRenewMargin, "subnet-lease-renew-margin", 60, "Subnet lease renewal margin, in minutes.")flag.BoolVar(&opts.ipMasq, "ip-masq", false, "setup IP masquerade rule for traffic destined outside of overlay network")

这些截取的参数有事比较重要,大概说一下
etcd-endpoints:连接etcd地址
etcd-prefix :在etcd里面路径前缀
iface:主机间流量互通的网卡
subnet-file:生成docker网络信息的路径
subnet-lease-renew-margin:这个是自网段的租约时间
ip-masq:是否启动ipmasq,就是SANT
当解析完参数后LookupExtIface检查网卡是否存在,并且返回外部接口信息

&backend.ExternalInterface{Iface:     iface,IfaceAddr: ifaceAddr,ExtAddr:   extAddr,}

Iface是制定的外网端口,如果publicip没有制定,IfaceAddr等于ExtAddr。这个容器出去的外部端口就设定成功了。
然后通过newSubnetManager去创建子网管理器,如果没有设置kubernetes子网管理的话,默认使用的就是通过etcd做子网管理,

func newSubnetManager() (subnet.Manager, error) {if opts.kubeSubnetMgr {return kube.NewSubnetManager()}cfg := &etcdv2.EtcdConfig{Endpoints: strings.Split(opts.etcdEndpoints, ","),Keyfile:   opts.etcdKeyfile,Certfile:  opts.etcdCertfile,CAFile:    opts.etcdCAFile,Prefix:    opts.etcdPrefix,Username:  opts.etcdUsername,Password:  opts.etcdPassword,}return etcdv2.NewLocalManager(cfg)
}

连接上etcd。创建网sm以后,注册SIGINT and SIGTERM这个主要是优雅的停止服务使用。getConfig里面调用的是getNetworkConfig

func (esr *etcdSubnetRegistry) getNetworkConfig(ctx context.Context) (string, error) {key := path.Join(esr.etcdCfg.Prefix, "config")resp, err := esr.client().Get(ctx, key, &etcd.GetOptions{Quorum: true})if err != nil {return "", err}return resp.Node.Value, nil
}

这个也是就是第一篇的实战的时候设置的config。从config里面获取backend是udp还是vxlan或者是别的。通过be, err := bm.GetBackend(config.BackendType)创建相应的backend。

    befunc, ok := constructors[betype]if !ok {return nil, fmt.Errorf("unknown backend type: %v", betype)}be, err := befunc(bm.sm, bm.extIface)

这样就获取到制定的backend,下面就是开始注册网络RegisterNetwork了,
每个backend都有自己的RegisterNetwork
这里写图片描述
下面以vxlan为例

func (be *VXLANBackend) RegisterNetwork(ctx context.Context, config *subnet.Config) (backend.Network, error) {// Parse our configurationcfg := struct {VNI  intPort intGBP  bool}{VNI: defaultVNI,}if len(config.Backend) > 0 {if err := json.Unmarshal(config.Backend, &cfg); err != nil {return nil, fmt.Errorf("error decoding VXLAN backend config: %v", err)}}devAttrs := vxlanDeviceAttrs{vni:       uint32(cfg.VNI),name:      fmt.Sprintf("flannel.%v", cfg.VNI),vtepIndex: be.extIface.Iface.Index,vtepAddr:  be.extIface.IfaceAddr,vtepPort:  cfg.Port,gbp:       cfg.GBP,}dev, err := newVXLANDevice(&devAttrs)if err != nil {return nil, err}subnetAttrs, err := newSubnetAttrs(be.extIface.ExtAddr, dev.MACAddr())if err != nil {return nil, err}lease, err := be.subnetMgr.AcquireLease(ctx, subnetAttrs)switch err {case nil:case context.Canceled, context.DeadlineExceeded:return nil, errdefault:return nil, fmt.Errorf("failed to acquire lease: %v", err)}// vxlan's subnet is that of the whole overlay network (e.g. /16)// and not that of the individual host (e.g. /24)vxlanNet := ip.IP4Net{IP:        lease.Subnet.IP,PrefixLen: config.Network.PrefixLen,}if err = dev.Configure(vxlanNet); err != nil {return nil, err}return newNetwork(be.subnetMgr, be.extIface, dev, vxlanNet, lease)
}

配置vxlan的vtep设备,AcquireLease分配人一个子网租约,就是分配一个网段。再回到main里面,如果设置ipmaq就是添加一个NAT的IPtable是规则,接着就是就是写docker的网络配置文件WriteSubnetFile,最后启动go bn.Run(ctx),它会阻塞,在另一个协程中运行,MonitorLease就是默认每隔60分钟续约一下。main解析完成,服务启动。

这篇关于flannel 实战与源码分析(三)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/977169

相关文章

MyBatis-Plus 与 Spring Boot 集成原理实战示例

《MyBatis-Plus与SpringBoot集成原理实战示例》MyBatis-Plus通过自动配置与核心组件集成SpringBoot实现零配置,提供分页、逻辑删除等插件化功能,增强MyBa... 目录 一、MyBATis-Plus 简介 二、集成方式(Spring Boot)1. 引入依赖 三、核心机制

MySQL 数据库表操作完全指南:创建、读取、更新与删除实战

《MySQL数据库表操作完全指南:创建、读取、更新与删除实战》本文系统讲解MySQL表的增删查改(CURD)操作,涵盖创建、更新、查询、删除及插入查询结果,也是贯穿各类项目开发全流程的基础数据交互原... 目录mysql系列前言一、Create(创建)并插入数据1.1 单行数据 + 全列插入1.2 多行数据

MySQL 数据库表与查询操作实战案例

《MySQL数据库表与查询操作实战案例》本文将通过实际案例,详细介绍MySQL中数据库表的设计、数据插入以及常用的查询操作,帮助初学者快速上手,感兴趣的朋友跟随小编一起看看吧... 目录mysql 数据库表操作与查询实战案例项目一:产品相关数据库设计与创建一、数据库及表结构设计二、数据库与表的创建项目二:员

从基础到高阶详解Python多态实战应用指南

《从基础到高阶详解Python多态实战应用指南》这篇文章主要从基础到高阶为大家详细介绍Python中多态的相关应用与技巧,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、多态的本质:python的“鸭子类型”哲学二、多态的三大实战场景场景1:数据处理管道——统一处理不同数据格式

Android 缓存日志Logcat导出与分析最佳实践

《Android缓存日志Logcat导出与分析最佳实践》本文全面介绍AndroidLogcat缓存日志的导出与分析方法,涵盖按进程、缓冲区类型及日志级别过滤,自动化工具使用,常见问题解决方案和最佳实... 目录android 缓存日志(Logcat)导出与分析全攻略为什么要导出缓存日志?按需过滤导出1. 按

Java慢查询排查与性能调优完整实战指南

《Java慢查询排查与性能调优完整实战指南》Java调优是一个广泛的话题,它涵盖了代码优化、内存管理、并发处理等多个方面,:本文主要介绍Java慢查询排查与性能调优的相关资料,文中通过代码介绍的非... 目录1. 事故全景:从告警到定位1.1 事故时间线1.2 关键指标异常1.3 排查工具链2. 深度剖析:

Linux中的HTTPS协议原理分析

《Linux中的HTTPS协议原理分析》文章解释了HTTPS的必要性:HTTP明文传输易被篡改和劫持,HTTPS通过非对称加密协商对称密钥、CA证书认证和混合加密机制,有效防范中间人攻击,保障通信安全... 目录一、什么是加密和解密?二、为什么需要加密?三、常见的加密方式3.1 对称加密3.2非对称加密四、

MySQL中读写分离方案对比分析与选型建议

《MySQL中读写分离方案对比分析与选型建议》MySQL读写分离是提升数据库可用性和性能的常见手段,本文将围绕现实生产环境中常见的几种读写分离模式进行系统对比,希望对大家有所帮助... 目录一、问题背景介绍二、多种解决方案对比2.1 原生mysql主从复制2.2 Proxy层中间件:ProxySQL2.3

Python实现Word转PDF全攻略(从入门到实战)

《Python实现Word转PDF全攻略(从入门到实战)》在数字化办公场景中,Word文档的跨平台兼容性始终是个难题,而PDF格式凭借所见即所得的特性,已成为文档分发和归档的标准格式,下面小编就来和大... 目录一、为什么需要python处理Word转PDF?二、主流转换方案对比三、五套实战方案详解方案1:

SpringBoot实现RSA+AES自动接口解密的实战指南

《SpringBoot实现RSA+AES自动接口解密的实战指南》在当今数据泄露频发的网络环境中,接口安全已成为开发者不可忽视的核心议题,RSA+AES混合加密方案因其安全性高、性能优越而被广泛采用,本... 目录一、项目依赖与环境准备1.1 Maven依赖配置1.2 密钥生成与配置二、加密工具类实现2.1