CNI之Flannel网络原理

news/2025/1/11 17:54:02/

简介

flannel是 coreos 开源的 Kubernetes CNI 实现。它使用 etcd 或者 Kubernetes API 存储整个集群的网络配置。每个 kubernetes节点上运行 flanneld 组件,它从 etcd 或者 Kubernetes API 获取集群的网络地址空间,并在空间内获取一个 subnet ,该节点上的容器 IP都从这个 subnet 中分配,从而保证不同节点上的 IP不会冲突。flannel通过不同的 backend 来实现跨主机的容器网络通信,目前支持 udp , vxlan , host-gw 等一系列 backend实现。

源码地址:https://github.com/flannel-io/flannel 

SubnetManager

子网管理器,以下简称sm
在main方法中会初始化sm: sm, err := newSubnetManager(ctx)
这里kube子网管理为例:

func NewSubnetManager(ctx context.Context, apiUrl, kubeconfig, prefix, netConfPath string, setNodeNetworkUnavailable, useMultiClusterCidr bool) (subnet.Manager, error) {var cfg *rest.Configvar err error// Try to build kubernetes config from a master url or a kubeconfig filepath. If neither masterUrl// or kubeconfigPath are passed in we fall back to inClusterConfig. If inClusterConfig fails,// we fallback to the default config.cfg, err = clientcmd.BuildConfigFromFlags(apiUrl, kubeconfig)if err != nil {return nil, fmt.Errorf("fail to create kubernetes config: %v", err)}c, err := clientset.NewForConfig(cfg)if err != nil {return nil, fmt.Errorf("unable to initialize client: %v", err)}// The kube subnet mgr needs to know the k8s node name that it's running on so it can annotate it.// If we're running as a pod then the POD_NAME and POD_NAMESPACE will be populated and can be used to find the node// name. Otherwise, the environment variable NODE_NAME can be passed in.nodeName := os.Getenv("NODE_NAME")if nodeName == "" {podName := os.Getenv("POD_NAME")podNamespace := os.Getenv("POD_NAMESPACE")if podName == "" || podNamespace == "" {return nil, fmt.Errorf("env variables POD_NAME and POD_NAMESPACE must be set")}pod, err := c.CoreV1().Pods(podNamespace).Get(ctx, podName, metav1.GetOptions{})if err != nil {return nil, fmt.Errorf("error retrieving pod spec for '%s/%s': %v", podNamespace, podName, err)}nodeName = pod.Spec.NodeNameif nodeName == "" {return nil, fmt.Errorf("node name not present in pod spec '%s/%s'", podNamespace, podName)}}netConf, err := os.ReadFile(netConfPath)if err != nil {return nil, fmt.Errorf("failed to read net conf: %v", err)}sc, err := subnet.ParseConfig(string(netConf))if err != nil {return nil, fmt.Errorf("error parsing subnet config: %s", err)}if useMultiClusterCidr {err = readFlannelNetworksFromClusterCIDRList(ctx, c, sc)if err != nil {return nil, fmt.Errorf("error reading flannel networks from k8s api: %s", err)}}sm, err := newKubeSubnetManager(ctx, c, sc, nodeName, prefix, useMultiClusterCidr)if err != nil {return nil, fmt.Errorf("error creating network manager: %s", err)}sm.setNodeNetworkUnavailable = setNodeNetworkUnavailableif sm.disableNodeInformer {log.Infof("Node controller skips sync")} else {go sm.Run(context.Background())log.Infof("Waiting %s for node controller to sync", nodeControllerSyncTimeout)err = wait.Poll(time.Second, nodeControllerSyncTimeout, func() (bool, error) {return sm.nodeController.HasSynced(), nil})if err != nil {return nil, fmt.Errorf("error waiting for nodeController to sync state: %v", err)}log.Infof("Node controller sync successful")}return sm, nil
}

上面的逻辑大致如下:

  • 通过配置得到的kubeconfig获取到pod访问客户端

  • 通过节点环境变量获取到节点名称,如果没有则通过pod详情获取到节点名称

  • 通过client-go库方法机制对集群中node进行监听,因为flannel是根据node来划分网段的

  • 根据监听到的node的事件,放入到sm的events channel中

BackendManager

在main方法中,进行了以下操作:

bm := backend.NewManager(ctx, sm, extIface)
be, err := bm.GetBackend(config.BackendType)
if err != nil {log.Errorf("Error fetching backend: %s", err)cancel()wg.Wait()os.Exit(1)
}bn, err := be.RegisterNetwork(ctx, &wg, config)

通过上面会得到这样一个接口实例:

type Network interface {Lease() *subnet.LeaseMTU() intRun(ctx context.Context)
}

目前支持的backend类型有allpc,awsvpc,gce,hostgw,udp和vxlan。

以vxlan为例:

func (nw *network) Run(ctx context.Context) {wg := sync.WaitGroup{}log.V(0).Info("watching for new subnet leases")events := make(chan []subnet.Event)wg.Add(1)go func() {subnet.WatchLeases(ctx, nw.subnetMgr, nw.SubnetLease, events)log.V(1).Info("WatchLeases exited")wg.Done()}()defer wg.Wait()for {evtBatch, ok := <-eventsif !ok {log.Infof("evts chan closed")return}nw.handleSubnetEvents(evtBatch)}
}

上面代码逻辑大致如下:

    • 调用SubnetManager.WatchLeases()监听整个集群网络的变更事件

    • 根据不同事件刷新路由表,arp表和fdb表等。

网络设备

与flannel相关的几个虚拟网络上设备:

  • flannel.1:这是一个vxlan设备。也就是耳熟能详的vteh设备,负责网络数据包的封包和解封。

  • cni0:是一个linux bridge,用于连接同一个宿主机上的pod。

  • vethf12090da@if3:容器内eth0网卡的对端设备,从名字上看,在容器内eth0网卡的编号应为3。

流程原理

VxLAN的设计思想是:

在现有的三层网络之上,“覆盖”一层虚拟的、由内核VxLAN模块负责维护的二层网络,使得连接在这个VxLAN二层网络上的“主机”(虚拟机或容器都可以),可以像在同一个局域网(LAN)里那样自由通信。 

为了能够在二层网络上打通“隧道”,VxLAN会在宿主机上设置一个特殊的网络设备作为“隧道”的两端,叫VTEP

VTEP原理如下:

  • flannel.1设备,就是VxLAN的VTEP,即有IP地址,也有MAC地址

  • 容器服务的IP包,会先出现在docker0网桥,再路由到本机的flannel.1设备进行处理,

  • 为了能够将“原始IP包”封装并发送到正常的主机,源VTEP设备收到原始IP包后,在上面加上一个目的MAC地址(也就是VTEP设备的MAC地址),封装成数据桢,发送给目的VTEP设备 ,封装过程只是加了一个二层头,不会改变“原始IP包”的内容,

  • Linux会再加上一个VxLAN头,VxLAN头里有一个重要的标志叫VNI,它是VTEP识别某个数据桢是不是应该归自己处理的重要标识。在Flannel中,VNI的默认值是1,这也是为什么宿主机的VTEP设备都叫flannel.1的原因

一个flannel.1设备只知道另一端flannel.1设备的MAC地址,却不知道对应的宿主机地址是什么。在linux内核里面,网络设备进行转发的依据,来自FDB的转发数据库

https://juejin.cn/post/6994825163757846565
http://just4coding.com/2021/11/03/flannel/


http://www.ppmy.cn/news/494960.html

相关文章

佳能打印机HP打印机爱普生打印机提示卡纸了确找不到卡纸

1&#xff0c;首先查看报错信息提示是卡纸了&#xff0c;那大多数原因都是卡纸了&#xff0c;只是你没找到在哪里。 2&#xff0c;先排查进纸口&#xff0c;打开储纸盒&#xff0c;用手电筒照明看下进纸口是否有卡纸&#xff0c;如果有慢慢取出。 3&#xff0c;排查打印机后盖…

电脑丢失msvcp140.dll的解决方法分享

如果你在使用电脑时遇到了“找不到msvcp140.dll”的错误提示&#xff0c;别着急&#xff01;这并不是什么严重的问题&#xff0c;电脑丢失msvcp140.dll的解决方法分享&#xff0c;只要你按照以下方法进行处理&#xff0c;很快就能够顺利地解决它。 一.什么是msvcp140.dll msvc…

佳能9100cdn故障_佳能打印机错误代码

佳能代码 佳能复印机故障代码总结及故障代码解决方案大全 号码显示 主要原因 说明 解决方法 更换零件 E000 热敏电阻( TH1 、 TH2 ) 接触不良&#xff0c; 断路 接通电源后&#xff0c; 在规定时间内 ( TH1 、 TH2 ) 检测的 按 SW 开关或关机 10 分种( NP6016 、 NP3020 ) 热敏…

打印机无响应的解决办法,不错哦

“开始”&#xff0d;&#xff0d; “运行”&#xff0d;&#xff0d; 在里面输入“net stop spooler”&#xff0c;点“确定”。再点“开始” 继续在“运行”里输入“spool”&#xff0c;点“确定” 进入到PRINTERS文件夹 删除里面的所有文件&#xff08;注意不是删除PRINT…

共享打印机无响应解决方案

场景解释 实验室打印机网口坏了&#xff0c;所以只能将打印机接到一台主机上&#xff0c;设置共享之后其他主机共享使用这台主机的打印机。共享打印机的具体设置方法可以百度。除此之外大多数人会发现设置好了之后当时可以使用&#xff0c;但是过一段时间以后就无法使用了&…

AbstractQueuedSynchronizer源码

介绍 基于队列的抽象同步器&#xff0c;它是jdk中所有显示的线程同步工具的基础&#xff0c;像ReentrantLock/DelayQueue/CountdownLatch等等&#xff0c;都是借助AQS实现的。 public abstract class AbstractQueuedSynchronizerextends AbstractOwnableSynchronizerimplemen…

基于Java学生公寓管理中心系统设计实现(源码+lw+部署文档+讲解等)

博主介绍&#xff1a; ✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战 ✌ &#x1f345; 文末获取源码联系 &#x1f345; &#x1f447;&#x1f3fb; 精…

macOS中比较好用的压缩软件:FastZip

在macOS的访达中右键点击1个或多个文件或目录时&#xff0c;右键菜单里有"压缩XXX"的选项&#xff0c;点击之后会以系统自带的&#xff1a;"归档实用工具"对选择的文件和目录进行压缩。这看起来并没有什么问题&#xff0c;而且的确挺方便。但是当你通过其他…