Flannel 有以下几种工作模式
推荐的模式:
实验性质的模式:
本章节也会简单介绍 flannel host-gw 模式下对 bridge 和 host-local 两种插件的使用。
获取 yaml
https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
修改 backends 并 apply
net-conf.json: |
{
"Network": "10.244.0.0/16",
"Backend": {
"Type": "host-gw"
}
}
指定网卡
- --iface=ens10
安装完成后,cni 配置如下
/etc/cni/net.d/10-flannel.conflist
{
"name": "cbr0",
"cniVersion": "0.3.1",
"plugins": [
{
"type": "flannel",
"delegate": {
"hairpinMode": true,
"isDefaultGateway": true
}
},
{
"type": "portmap",
"capabilities": {
"portMappings": true
}
}
]
}
下面是以 host-gw 为示例分析,host-gw 中 pod 通信是由所在主机的 路由到另一节点上的。
在 Flannel 启动时
&backend.ExternalInterface{
Iface: iface, // ens10
IfaceAddr: ifaceAddr, //192.168.100.111
IfaceV6Addr: ifaceV6Addr,
ExtAddr: extAddr, //192.168.100.111
ExtV6Addr: extV6Addr,
}
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
FLANNEL-POSTRTG all -- 0.0.0.0/0 0.0.0.0/0 /* flanneld masq */
......
Chain FLANNEL-POSTRTG (1 references)
target prot opt source destination
RETURN all -- 0.0.0.0/0 0.0.0.0/0 mark match 0x4000/0x4000 /* flanneld masq */
RETURN all -- 10.244.0.0/16 10.244.0.0/16 /* flanneld masq */
MASQUERADE all -- 10.244.0.0/16 !224.0.0.0/4 /* flanneld masq */ random-fully
RETURN all -- !10.244.0.0/16 10.244.0.0/24 /* flanneld masq */
MASQUERADE all -- !10.244.0.0/16 10.244.0.0/16 /* flanneld masq */ random-fully
status:
conditions:
- lastHeartbeatTime: "2023-01-08T14:21:45Z"
lastTransitionTime: "2023-01-08T14:21:45Z"
message: Flannel is running on this node
reason: FlannelIsUp
status: "False"
type: NetworkUnavailable
在 Flannel 启动后
11. 起 goroutine 去跑对应的 backend network;
// Start "Running" the backend network. This will block until the context is done so run in another goroutine.
log.Info("Running backend.")
wg.Add(1)
go func() {
bn.Run(ctx)
wg.Done()
}()
log.Info("Watching for new subnet leases")
evts := make(chan []subnet.Event)
wg.Add(1)
go func() {
subnet.WatchLeases(ctx, n.SM, n.SubnetLease, evts)
wg.Done()
}()
for {
evtBatch, ok := <-evts
if !ok {
log.Infof("evts chan closed")
return
}
n.handleSubnetEvents(evtBatch) // 配置本节点路由信息
}
attrs.PublicIP = ip.FromIP(be.extIface.ExtAddr)
n.GetRoute = func(lease *subnet.Lease) *netlink.Route {
return &netlink.Route{
Dst: lease.Subnet.ToIPNet(), // 新增节点的 子网
Gw: lease.Attrs.PublicIP.ToIP(), // 新增节点的 extIface IP
LinkIndex: n.LinkIndex, // 本节点的 接口索引
}
}
func (n *RouteNetwork) routeCheck(ctx context.Context) {
for {
select {
case <-ctx.Done():
return
case <-time.After(routeCheckRetries * time.Second):
n.checkSubnetExistInV4Routes()
n.checkSubnetExistInV6Routes()
}
}
}
由此可见,flannel 负责从 K8s 集群中分配一个本节点的地址段,然后根据所有集群节点维护本节点配置
Flannel 中 pod 的网卡创建是由 bridge cni 来进行的;
Flannel 的 IPAM 则是由 host-local 来实现的。IPAM 见步骤 8
以 containerd 作为 cri 实现为例
{0d29f8838ec3a206d6cc4658dcebd08697cf4d52e03dc2ca27176b0c4a148a02 /var/run/netns/cni-908d2d0f-add3-29d3-0eaf-0141764e0852 eth0 K8S_POD_UID=036c90b4-3e4b-4790-8554-505892d70433;IgnoreUnknown=1;K8S_POD_NAMESPACE=default;K8S_POD_NAME=pod24;K8S_POD_INFRA_CONTAINER_ID=0d29f8838ec3a206d6cc4658dcebd08697cf4d52e03dc2ca27176b0c4a148a02 /opt/cni/bin [123 34 99 110 105 86 101 114 115 105 111 110 34 58 34 48 46 51 46 49 34 44 34 100 101 108 101 103 97 116 101 34 58 123 34 104 97 105 114 112 105 110 77 111 100 101 34 58 116 114 117 101 44 34 105 115 68 101 102 97 117 108 116 71 97 116 101 119 97 121 34 58 116 114 117 101 125 44 34 110 97 109 101 34 58 34 99 98 114 48 34 44 34 116 121 112 101 34 58 34 102 108 97 110 110 101 108 34 125]}
其中 u8 列表是 {“cniVersion”:“0.3.1”,“delegate”:{“hairpinMode”:true,“isDefaultGateway”:true},“name”:“cbr0”,“type”:“flannel”},即从 /etc/cni/net.d/10-flannel.conflist 读取的信息。
&{{0.3.1 cbr0 flannel map[] {} {[] [] []} map[] <nil>} map[] /run/flannel/subnet.env /var/lib/cni/flannel map[hairpinMode:true isDefaultGateway:true] map[]}
其中 netConf.Delegate 为 map[hairpinMode:true isDefaultGateway:true]
FLANNEL_NETWORK=10.244.0.0/16
FLANNEL_SUBNET=10.244.1.1/24
FLANNEL_MTU=1500
FLANNEL_IPMASQ=true
func doCmdAdd(args *skel.CmdArgs, n *NetConf, fenv *subnetEnv) error
type: host-local
ranges: {"subnet": "10.244.1.1/24"}
routes: {"dst": "10.244.0.0/16"}
delegateAdd(args.ContainerID, n.DataDir, n.Delegate)
// n.Delegate 4 中 netConf.Delegate n.DataDir 默认为 /var/lib/cni/flannel/{container_id}
将 netconf (n.Delegate)存到 /var/lib/cni/flannel/{container_id} 中 给 cmdDel 删除使用,示例如下
$ cat /var/lib/cni/flannel/75fc1ae6fef3fe8d9368fbb3cc6f07ec23a6d87abf2cb3814f6053d6952a9ba9
{"cniVersion":"0.3.1","hairpinMode":true,"ipMasq":false,"ipam":{"ranges":[[{"subnet":"10.244.1.0/24"}]],"routes":[{"dst":"10.244.0.0/16"}],"type":"host-local"},"isDefaultGateway":true,"isGateway":true,"mtu":1500,"name":"cbr0","type":"bridge"}
调 netConf 中实际二进制 bridge 干活
result, err := invoke.DelegateAdd(context.TODO(), netconf["type"].(string), netconfBytes, nil)
bridge 二进制代码在 https://github.com/containernetworking/plugins 中,dummy,ipvlan,macvlan,vlan 等plgin 都在这里。
和调取 flannel 二进制一样调取 bridge 的 cmdAdd
同样根据参数解析 netConf
在 NS 里创建 veth-pair
ips: [{"IP":"10.244.1.13","Gateway":"10.244.1.1"}]
dns: {}
routes: [{"dst":"10.244.0.0/16"}]
DAD 功能会避免 IPv6 地址重复分配,比如 ipv6 从 DHCP 获取的,则必须要关闭