关于 kubernetes 的 flannel 网络组件研究

https://github.com/flannel-io/flannel/tree/master/Documentation
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

# flannel 的网络方案是基于L3网实现虚L2网 "Virtual eXtensible Local Area Network",仅关心流量如何在 Node 间流转
# 它为每个节点分配一个子网,每个节点创建POD时再从它的 subnet 中进行IP分配,并使这些IP(集群全局唯一)在Node间路由 ...
# 使得容器间在不借助NAT、端口映射的情况下互通(每个节点的 subnet 都是从更大的集群范围的IP地址池中划分的)
# 每个节点中运行的 flanneld 负责从集群的IP地址池中申请并分配 subnet 给各自节点(IP池及分配信息存于etcd)
# 使用 etcd 存放网络配置、已分配的 subnet、Host的IP等信息(flannel通过APIServer或直接与etcd通讯)
# flannel 数据包在主机间的转发功能由其后端 backend 实现,目前支持 VxLAN、host-gw、UDP、AWS VPC、GCE 路由等 ...
# flannel 实时监听 etcd 中数据变化。同时在节点中创建名为 flannel0 的桥(这是VXLAN类型的接口)...
# Tunnel协议的一个重要的特性就是软件扩展性,这是SDN软件定义网络 Software-defined Network 的基石之一 

# 名为flannel的CNI插件是开源网络方案 flannel 的调用器,这是flannel网络方案适配CNI架构的产物
# 为了便于区分通常称CNI插件中的flannel为 flanenl CNI
# 节点中的 flanneld 返回该节点使用的网络、subnet、MTU等信息并保存到本地文件中,默认为 /run/flannel/subnet.env
# 处于flannel网络下的 bridge 设备会与其生成的 flannel0 接口互联,而 flannel0 的数据会被封包 (udp、vxlan) 或直接转发 (host-gw)
# 处于flannel网络下的 flannel 还会配置相应的Node间路由并生成ARP、FDB表 ...

# --------------------------------------------------------- Flanneld Arguments

# 命令行选项也能通过环境变量指定,例如 --etcd-endpoints=xxx 等效于 FLANNELD_ETCD_ENDPOINTS=xxx
--ip-masq
--public-ip=""
--etcd-endpoints=http://127.0.0.1:4001
--etcd-prefix=/coreos.com/network
--etcd-keyfile=""
--etcd-certfile=""
--etcd-cafile=""
--subnet-file="/run/flannel/subnet.env"
-v=0

# --------------------------------------------------------- describe

kubernetes 集群中基于 flannel 的通讯流程 (节点间通过overlay网络保证不同节点的container互通)

1. 容器直接用目标POD_IP进行访问,并通过容器内部网络名称空间的eth0网卡发出(POD内的网关是其所在bridge的IP)
2. 报文通过veth pair被发送到POD所在宿主节点中的虚拟桥设备 docker0或cni0,报文通过其发出 ...
4. 此时在该Node中通过查路由表 (由Flannel生成) 访问外部POD_IP的报文根据其转发到名为 flannel0 的虚拟网卡
5. 这是P2P的虚拟网卡,然后此报文就被转发到运行在其他节点的flanneld监听的的UDP/8285或UDP/8472端口 (UDP/Vxlan) ...
5. flanneld通过etcd存储、维护各节点间的路由信息,把原来的报文用UDP再封装一层后通过 --iface 参数设置的接口发出
6. 报文通过主机之间的网络找到目标主机 (由于是overlay模式,因此对底层网络没啥要求)
7. 报文继续向上到传输层,交给默认监听在UDP/8285的flanneld处理(基于UDP的VXLAN数据被解包后发给flannel0虚拟网卡)
8. 此时目标Node查找其路由表后发现对应的POD_IP的报文要交给 docker0 桥
9. docker0 根据连接自己的容器的IP信息把报文发送过去 (veth pair)

flannel 启动流程 …
https://github.com/flannel-io/flannel/blob/master/Documentation/running.md

flanneld --subnet-file /run/flannel/subnet.env --etcd-endpoints=http://x.x.x.x:2379 --etcd-prefix=/coreos.com/network/config ...

# flanneld 启动过程 (要在docker daemon之前启动):
#     1. 从apiserver或etcd中获取network配置信息,并且会 watch etcd中记录的新成员并相应地调整路由 ...
#     2. 划分其所在Node的子网 subnet 并在etcd进行注册 ...
#     3. 配置其对应的后端 backend ,根据不同的后端设置对的处理规则 ...
#     4. 将从etcd申请的属于本节点的子网信息写入 /run/flannel/subnet.env (含有其支持的子网地址和MTU)

# Flanneld在etcd集群中的初始网络配置信息如下
# 对于所有加入flannel的节点和container来讲,flannel给它们呈现的是一个flat的/16大三层网络,每个节点获取里面1个/24的网段
{
  "Network": "172.22.0.0/16",
  "SubnetLen": 24,
  "Backend": {
    "Type": "vxlan"
   }
 }

# Use Port For flannel backend
udp   # flannel 使用 UDP/8285 发送封装的 packets
vxlan # kernel  使用 UDP/8472 发送封装的 packets

# --------------------------------------------------------- flannel => etcd => /coreos.com/network/config

# 在etcd中修改flannel的默认配置 ...
etcdctl put /coreos.com/network/config \
{
    "Network": "172.22.0.0/16",     # 设置容器IP池,docker0 默认是 172.17.0.0/16 ( 指定Flannel地址池 )
    "SubnetLen": 24,                # 
    "SubnetMin": "172.22.0.0",      # 用于分配的起始网段,可不写(用于特殊预留)
    "SubnetMax": "172.22.255.0",    # 用于分配的终止网段,可不写
    "Backend": {                    # Flannel 的后端类型设置 ...
        "Type": "vxlan"             # 默认 udp 方式,此处设为 vxlan 方式,目前支持 VxLAN、host-gw、UDP、AWS VPC、GCE 路由等 ...
    }
}

# 每个flannel节点都能通过 apiserver/etcd 感知到集群中其它节点的存在 ...
# etcdctl ls /coreos.com/network --recursive (v2 api)
/coreos.com/network/config                          # flanneld 的配置信息 ...
/coreos.com/network/subnets                         # 该路径下存放的是为集群中所有Node分配的IP段
/coreos.com/network/subnets/172.22.9.0-24           # 每个地址都是1个Node节点能分配给其自身运行的Pod地址范围
/coreos.com/network/subnets/172.22.21.0-24          # 
/coreos.com/network/subnets/172.22.90.0-24          # 

# 查看具体某个节点的 flannel 网络配置信息
etcdctl get /coreos.com/network/subnets/172.22.9.0-24 | python -m json.tool
{
    "PublicIP": "192.168.166.102",                  # 172.22.9.0-24 网段对外的IP地址,即 Node IP
    "BackendType": "vxlan",                         # 
    "BackendData": {                                # 
        "VtepMAC": "1a:9a:e1:c1:be:3f"              # 
    }
}

# --------------------------------------------------------- Docker integration

# 部署 docker daemon 后需修改启动参数来让其使用 flannel 实现的IP分配 (subnet) 及网络通讯 ...
# 因为 flannel 将获取的子网和MTU值写到了 subnet.env 文件,因此 docker daemon 启动时可直接读取它们的值 ...

# cat /run/flannel/subnet.env
FLANNEL_NETWORK=172.22.0.0/16
FLANNEL_SUBNET=172.22.255.0/24      # docker读取其来生成在整个集群范围内唯一的 bridge 网段,从而保证 Pod IP 唯一
FLANNEL_MTU=1450                    # MTU 也是要进行修改的 ...
FLANNEL_IPMASQ=false

# Example For start docker daemon
source /run/flannel/subnet.env
docker daemon --bip=${FLANNEL_SUBNET} --mtu=${FLANNEL_MTU} &

# --------------------------------------------------------- /run/docker_opts.env

# 可使用 flannel 提供的脚本将 subnet.env 转写成 docker daemon 的启动参数,它默认被生成在 /run/docker_opts.env 中
# systemd用户可使用 EnvironmentFile 指令来引入 /run/flannel/subnet.env 中的环境变量 ...

/opt/flannel/mk-docker-opts.sh -c
cat /run/docker_opts.env
# DOCKER_OPTS="--bip=172.22.9.1/24 --ip-masq=false --mtu=1450"

# 修改docker的服务启动文件
vim /lib/systemd/system/docker.service
# ......
# EnvironmentFile=/run/docker_opts.env
# ExecStart=/usr/bin/dockerd $DOCKER_OPTS -H fd://
# ......
systemctl daemon-reload && systemctl enable docker --now


# 如果想保留使用默认的 docker0 网络而非创建的新网桥,可执行以下操作:
source /run/flannel/subnet.env
docker network create \
    --attachable=true --subnet=${FLANNEL_SUBNET} -o "com.docker.network.driver.mtu"=${FLANNEL_MTU} flannel

# ---------------------------------------------------------

flanneld启动后会在Node中创建名为 flannel.1 的vxlan设备并将节点对应的子网赋给 docker0,同时实时维护Node中的路由信息 ...

# 3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN 
#     link/ether 02:42:e0:e9:e9:52 brd ff:ff:ff:ff:ff:ff
#     inet 172.22.9.1/24 scope global docker0
#        valid_lft forever preferred_lft forever
# 4: flannel.1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN 
#     link/ether 1a:9a:e1:c1:be:3f brd ff:ff:ff:ff:ff:ff
#     inet 172.22.9.0/32 scope global flannel.1
#        valid_lft forever preferred_lft forever
#     inet6 fe80::189a:e1ff:fec1:be3f/64 scope link 
#        valid_lft forever preferred_lft forever

在基于 VXLAN 后端的节点中执行 ip route show 命令 ...
# default via 192.168.166.2 dev ens33 proto static metric 100 
# 172.22.9.0/24 dev docker0 proto kernel scope link src 172.22.9.1   
# 172.22.0.0/16 dev flannel.1
# 192.168.166.0/24 dev ens33 proto kernel scope link src 192.168.166.102 metric 100

# 流程:
# [ POD1 -> docker0 -<route table>-> flannel1(vxlan) ]  <==NETWORK==>  [ (vxlan)flannel1 -> docker0 -<route table>-> POD2 ]
#                                               ↓                             ↑
#                                      (encapsulation)  --------------  (decapsulation)

关于flannel的CNI插件相关Json配置段
https://www.cni.dev/plugins/current/meta/flannel/

# 节点中 flannel daemon 的 flannel CNI 的任务如下:
# 1. 执行ADD命令时flanenl插件从 /run/flannel/subnet.env 读取flanneld配置,然后根据参数和该配置生成新的CNI配置文件保存在本地,文件名包含容器ID来区分
# 2. 新的CNI配置文件中会使用其他CNI组件并注入相关配置信息,之后 flannel CNI根据这个新的CNI配置文件执行ADD命令
# 3. 执行DEL命令时flanenl插件从本地根据容器ID找到之前创建的CNI配置文件,根据该配置文件执行DEL命令 ...
# 4. 也就是说flannel插件此时是flannel网络模型的委托者,falnnel网络模型委托它去调用其他CNI组件来实现网络配置。通常调用的是CNI内置的 bridge、host-local

# -------------------------------------------------------------------------------------------------

# flannel的CNI插件旨在与flanneld一起使用,该CNI插件用于容器的网络设置,当启动flanneld时将生成 /run/flannel/subnet.env 文件:
FLANNEL_NETWORK=10.1.0.0/16
FLANNEL_SUBNET=10.1.17.1/24
FLANNEL_MTU=1472
FLANNEL_IPMASQ=true

# 上述配置反应了节点中flannel的网络属性,由flannel CNI通过该文件读取其信息来调用其他CNI插件 (例如使用其传参并调用CNI的 bridge 插件)
# 当给定以下CNI网络配置文件的内容及上述 /run/flannel/subnet.env 内容时
# Given the following network configuration file and the contents of /run/flannel/subnet.env above
{
	"name": "mynet",
	"type": "flannel"
}
#
# flannel的CNI插件将生成另一个网络配置文件,the flannel plugin will generate another network configuration file
# 然后flannel的CNI插件再去调用 bridge 插件并将生成的这个Json配置传递给它:
{
	"name": "mynet",
	"type": "bridge",           # flannel插件调用了bridge插件 ...
	"mtu": 1472,
	"ipMasq": false,
	"isGateway": true,
	"ipam": {
		"type": "host-local",
		"subnet": "10.1.17.0/24"
	}
}

# 从上述可看出默认情况下flannel的CNI插件会委派 bridge 插件执行
# 若需将其他的配置信息传递给 bridge 插件时可通过在 delegate 字段设置进行传递:
{
	"name": "mynet",
	"type": "flannel",
	"delegate": {
		"bridge": "mynet0",     # 创建的 bridge 设备将命名为 mynet0
		"mtu": 1400             # 设置 MTU
	}
}

# --------------------------------------------------- flannel CNI - Network configuration reference

name        # 网络名称
type        # flannel 
subnetFile  # flanneld 写入的子网文件的完整路径,默认为 /run/flannel/subnet.env
dataDir     # 该插件用于存储生成的网络配置文件的目录的路径,默认为 /var/lib/cni/flannel
delegate    # 指定委托插件的配置选项
ipam        # 指定时,用作构造ipam委托插件配置的部分的基础

# flannel插件将始终在 delegate 插件的配置段中设置以下字段:
name        # 其名称
ipam        # 若存在,则默认的 type为host-local、subnet为$FLANNEL_SUBNET、并且还有个routes元素 ...

# flannel plugin will set the following fields in the delegated plugin configuration if they are not present:
ipMasq      # the inverse of $FLANNEL_IPMASQ
mtu         # $FLANNEL_MTU

# 另外 bridge插件的 isGateway 属性默认值为 true

theory

# POD数据包流向:
# POD数据包从cni0进入,从flanel0出去,然后在借助于宿主机的物理网卡发出报文 ...

# 当 kubernetes 集群中的 Node 数量很多时,每个Node中都将存在超多路由条目,因此会造成性能问题

# 当flennel处于 host-gw 工作模式时由于是直接通过路由进行转发,因此其性能与calico相当
# 但该模式的缺陷是集群节点之间不能跨网段通讯 ...

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值