【kubernetes/k8s源码分析】CNI flannel源码分析

源码路径: https://github.com/containernetworking/plugins

版本: v.0.10.0

flannel cni路径: plugins/plugins/meta/flannel/flannel.go

 

subnet.env文件

# cat /run/flannel/subnet.env 
FLANNEL_NETWORK=172.30.0.0/16
FLANNEL_SUBNET=172.30.45.1/24
FLANNEL_MTU=1500
FLANNEL_IPMASQ=false

 

cni 配置文件

# cat /etc/cni/net.d/10-flannel.conf 
{"name":"cbr0","type":"flannel","delegate": {"bridge": "docker0", "isDefaultGateway": true, "ipMasq": false}}

 

NetConf结构体

    subnetFile文件默认为:/run/flannel/subnet.env

    dataDIr默认为:/var/lib/cni/flannel

type NetConf struct {
	types.NetConf

	SubnetFile string                 `json:"subnetFile"`
	DataDir    string                 `json:"dataDir"`
	Delegate   map[string]interface{} `json:"delegate"`
}

 

1. cmdAdd函数

  

  1.1 loadFlannelNetConf函数

    将传入的参数解析到NetConf结构体,这里设置了默认的subnetFile,与dataDir

	n, err := loadFlannelNetConf(args.StdinData)
	if err != nil {
		return err
	}

  1.2 loadFlannelSubnetEnv函数

    从/run/flannel/subnet.env读取配置,包括:

  • FLANNEL_NETWORK=172.30.0.0/16
  • FLANNEL_SUBNET=172.30.46.1/24
  • FLANNEL_MTU=1500
  • FLANNEL_IPMASQ=false
	fenv, err := loadFlannelSubnetEnv(n.SubnetFile)
	if err != nil {
		return err
	}

  1.3 subnet.env验证参数合法性

	if n.Delegate == nil {
		n.Delegate = make(map[string]interface{})
	} else {
		if hasKey(n.Delegate, "type") && !isString(n.Delegate["type"]) {
			return fmt.Errorf("'delegate' dictionary, if present, must have (string) 'type' field")
		}
		if hasKey(n.Delegate, "name") {
			return fmt.Errorf("'delegate' dictionary must not have 'name' field, it'll be set by flannel")
		}
		if hasKey(n.Delegate, "ipam") {
			return fmt.Errorf("'delegate' dictionary must not have 'ipam' field, it'll be set by flannel")
		}
	}

  1.4 doCmdAdd函数

    对于未设置的参数初始化,如果未设置ipam则使用默认host-local

func doCmdAdd(args *skel.CmdArgs, n *NetConf, fenv *subnetEnv) error {
	n.Delegate["name"] = n.Name

	if !hasKey(n.Delegate, "type") {
		n.Delegate["type"] = "bridge"
	}

	if !hasKey(n.Delegate, "ipMasq") {
		// if flannel is not doing ipmasq, we should
		ipmasq := !*fenv.ipmasq
		n.Delegate["ipMasq"] = ipmasq
	}

	if !hasKey(n.Delegate, "mtu") {
		mtu := fenv.mtu
		n.Delegate["mtu"] = mtu
	}

	if n.Delegate["type"].(string) == "bridge" {
		if !hasKey(n.Delegate, "isGateway") {
			n.Delegate["isGateway"] = true
		}
	}
	if n.CNIVersion != "" {
		n.Delegate["cniVersion"] = n.CNIVersion
	}

	n.Delegate["ipam"] = map[string]interface{}{
		"type":   "host-local",
		"subnet": fenv.sn.String(),
		"routes": []types.Route{
			{
				Dst: *fenv.nw,
			},
		},
	}

	return delegateAdd(args.ContainerID, n.DataDir, n.Delegate)
}

2. delegateAdd函数

  saveScratchNetConf函数创建/var/lib/cni/flannel目录

  调用DelegateAdd函数

func delegateAdd(cid, dataDir string, netconf map[string]interface{}) error {
	netconfBytes, err := json.Marshal(netconf)
	if err != nil {
		return fmt.Errorf("error serializing delegate netconf: %v", err)
	}

	// save the rendered netconf for cmdDel
	if err = saveScratchNetConf(cid, dataDir, netconfBytes); err != nil {
		return err
	}

	result, err := invoke.DelegateAdd(netconf["type"].(string), netconfBytes, nil)
	if err != nil {
		return err
	}

	return result.Print()
}

3. 根據設置的bridge,調用bridge cni

參照https://blog.csdn.net/zhonglinzhang/article/details/82733201

  3.1 setupBridge函数

  • 通过netlink.LinkAdd(br)创建网桥,相当于ip link add br-test type bridge
  •  然后通过 netlink.LinkSetUp(br)启动网桥,相当于ip link set dev br-test up

  3.2 setupVeth函数

  •  调用netlink.LinkAdd(veth)创建veth,这个是一个管道,Linux的网卡对,在容器对应的namespace下创建好虚拟网络接口,相当于ip link add test-veth0 type veth peer name test-veth1
  •  调用netlink.LinkSetUp(contVeth)启动容器端网卡,相当于ip link set dev test-veth0 up
  • 调用netlink.LinkSetNsFd(hostVeth, int(hostNS.Fd()))将host端加入namespace中,相当于ip link set $link netns $ns
  •  调用netlink.LinkSetMaster(hostVeth, br)绑到bridge,相当于ip link set dev test-veth0 master br-test
     

 

与calico不同点:

calico 绑到eth0

flannel 绑到docker0 bridge上,在调用bridage cni创建一大堆网络相关

你可能感兴趣的:(kubernetes,CNI,网络)