cni网络插件之flannel
https://www.cni.dev/
https://github.com/containernetworking/plugins
https://www.rfc-editor.org/rfc/rfc7348
静态分配pod ip https://github.com/k8snetworkplumbingwg/whereabouts
flannel 涉及到的目录
/var/lib/cni/networks/cbr0 保存了pod 地址分配信息
/run/flannel/subnet.env 保存了节点子网分配信息
/opt/cni/bin/ 保存了可执行命令
/etc/cni/net.d/10-flannel.conflist 保存了cni配置的信息
flannel是什么
- flannel 是一个为k8s设计的简单易用的三层网络解决方案
- falnnel 不控制container 如何与host 进行通讯,只控制host与host之间如何通讯
- flannel 聚焦于网络通讯,网络策略有calico 负责
- flannel 以服务的形式运行在每一台主机上,负责从大的网络中租赁子网给每一台主机
- flannel 可以使用k8s api 或直接使用etcd来存储网络配置、子网分配及辅助数据。通过监听etcd的变化来调整路由,github 建议使用k8s api 来连接etcd
- 容器间数据包被转发通过vxlan、host-gw 及多种云网络
- flannel 一旦获得租赁的子网会在
/run/flannel/subnet.env
生成环境变量文件。每次flannel 重启都会试图访问/run/flannel/subnet.env
中FLANNEL_SUBNET的值,从而防止在租约到期前更新了网络信息 - 可以运行多个flanneld 通过
flanneld -subnet-file /vxlan.env -etcd-prefix=/vxlan/network
flannel配置文件
[info]
如果
--kube-subnet-mgr true
则flannel 从/etc/kube-flannel/net-conf.json
读取启动配置
如果--kube-subnet-mgr false
则flannel 从etcd
读取启动配置。其中key 为/coreos.com/network/config
,可以使用--etcd-prefix
来修改该key-ip-masq
setup IP masquerade rule for traffic destined outside of overlay network
配置文件事例
# cat /etc/kube-flannel/net-conf.json
{
"Network": "10.244.0.0/16", # 必须的key
"SubnetLen": "/24",
"SubnetMin": "10.244.21.0/24",
"SubnetMax": "10.244.22.0/24",
"Backend": {
"Type": "udp",
"Port": 7890
}
}
Backends
flannel 支持多种类型的配置,这个设置一旦设定,在集群运行状态不应该做修改
-
VXLAN
-
host-gw 通常不能使用在云环境,要求host 运行在相同的二层网络
-
UDP suggested for debugging
-
AWS, GCE, and AliVPC 处于试验阶段,存在风险
-
ipip
-
ipsec
vxlan 使用linxu内核的vxlan 技术进行封包
"Backend":{
"Type": "vxlan",
# vxlan的标识符 linux 使用 1, windows 使用大于或等于4096的值
"VNI": 1,
# 当通讯的主机在同一子网中时基于host-gw 的方式通讯,vxlan 仅用于不同网段的主机通讯
"DirectRouting": false
}
host-gw
"Backend":{
"Type": "host-gw"
}
upd
"Backend":{
"Type": "udp",
# udp 的端口 Linux 使用 8472 windows 使用4789
"Port": 8472
}
ali-vpc
"Backend":{
"Type": "ali-vpc",
# 可以使用环境变量 ACCESS_KEY_ID
"AccessKeyID": "",
# 可以使用环境变量 ACCESS_KEY_SECRET
"AccessKeySecret": ""
}
tencent-vpc
"Backend":{
"Type": "tencent-vpc",
# 可以使用环境变量 ACCESS_KEY_ID
"AccessKeyID": "",
# 可以使用环境变量 ACCESS_KEY_SECRET
"AccessKeySecret": ""
}
ipip
使用内核的ipip 来封装包
ipip 是一种最简单的隧道
他的开销最低,单只能封装基于IPV4的单播数据,因此不支持 OSPF
RIP
等基于组播的协议
"Backend": {
"Type": "ipip",
# 当通讯的主机在同一子网中时基于host-gw 的方式通讯,ipip 仅用于不同网段的主机通讯
"DirectRouting": false
}
ipsec
使用内核的ipsec 进行封包
使用IKEv2进程,通过预共享秘钥的来实现秘钥的交换,保证秘钥在周期性改变
"Backend": {
"Type": "ipsec",
# 预共享秘钥,最少96个字符,可以使用这个命令生成 dd if=/dev/urandom count=48 bs=1 status=none | xxd -p -c 48 xxd通过yum install vim-common 安装
"PSK": ""
# 当通讯的主机在同一子网中时基于host-gw 的方式通讯,ipip 仅用于不同网段的主机通讯
"DirectRouting": false,
# 使用udp 封包,默认false
"UDPEncap": false,
# 秘钥交换的算法
"ESPProposal": "aes128gcm16-sha256-prfsha256-ecp256"
}
启动命令
flannel
--publish-ip="10.4.7.21"
用于通讯的ip
--etcd-endpoints=https://10.4.7.12:2379,https://10.4.7.21:2379
指定etcd,使用都好隔开
--etcd-prefix=/coreos.com/network
指定 etdctl 中key
--etcd-keyfile=""
与etcd 通讯的key
--etcd-certfile=""
与etcd 通讯的crt
--etcd-cafile=""
与etcd 通讯的ca
--kube-subnet-mgr
指定使用k8sapi 而不是独立的etcd
--iface=""
指定通讯的网卡名字 eth0
--subnet-file=/run/flannel/subnet.env
指定变量文件包括subnet 和 MTU。MTU 有flannel 自动设定不能修改
--net-config-path=/etc/kube-flannel/net-conf.json
指定启动配置文件
--ip-masq=false
发往pod 集群外的网络进行nat,这里假设iptables POSTROUTING 的默认策略为ACCEPT
--healthz-port=0
指定健康检查的端口,0 表示禁用
任何指令都可以通过环境变量的形式传递规则如下:
使用FLANNELD_
代替指令开头的--
其他-
转换成_
所有小写字母转大写
举例:--etcd-endpoints=http://10.0.0.2:2379
is equivalent to FLANNELD_ETCD_ENDPOINTS=http://10.0.0.2:2379
安装部署
[info]
- 在启动kube-apiserver是需要添加
--allow-privileged=true
。否则在pod 中无法使用sercurityContext.privileged: true- 在启动kubelet 是需要指定
--allocate-node-cidrs=true
--cluster-cidr="172.7.0.0/16"
。否则会提示crashLoopBackOff
,容器日志提示Error registering network: faild to acquire less: node "node-01" pod cidr not assigned
部署
https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/k8s-manifests/kube-flannel-legacy.yml
https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/k8s-manifests/kube-flannel-rbac.yml
网络策略canl
wget https://docs.projectcalico.org/manifests/canal.yaml --no-check-certificate
vxlan 下数据包的抓取
[root@master ~]# ip r
default via 10.4.7.254 dev eth0 proto static metric 100
10.4.7.0/24 dev eth0 proto kernel scope link src 10.4.7.12 metric 100
172.7.0.0/24 dev cni0 proto kernel scope link src 172.7.0.1
172.7.0.7 dev calic5dfa14a2a1 scope link
172.7.0.8 dev cali67af1dd0d0b scope link
172.7.0.21 dev cali725cb08e809 scope link
172.7.1.0/24 via 172.7.1.0 dev flannel.1 onlink
[root@master ~]# tcpdump -i flannel.1 icmp -nn
22:21:46.943557 IP 172.7.0.22 > 172.7.1.88: ICMP echo request, id 17, seq 0, length 64
22:21:46.944043 IP 172.7.1.88 > 172.7.0.22: ICMP echo reply, id 17, seq 0, length 64
[root@master ~]# tcpdump -i eth0 -nnn |sed -n '/overlay/{N;p}'
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
22:41:16.081998 IP 10.4.7.12.48367 > 10.4.7.11.8472: OTV, flags [I] (0x08), overlay 0, instance 1
IP 172.7.0.22 > 172.7.1.88: ICMP echo request, id 15, seq 0, length 64
22:41:16.082615 IP 10.4.7.11.53477 > 10.4.7.12.8472: OTV, flags [I] (0x08), overlay 0, instance 1
IP 172.7.1.88 > 172.7.0.22: ICMP echo reply, id 15, seq 0, length 64
22:41:18.217711 IP 10.4.7.12.47091 > 10.4.7.11.8472: OTV, flags [I] (0x08), overlay 0, instance 1
和docker集成
[info]
Docker 1.16及以后,将不再使用docker daemon命令,而直接使用dockerd命令了
需要先启动docker
source /run/flannel/subnet.env
docker daemon --bip=${FLANNEL_SUBNET} --mtu=${FLANNEL_MTU} &
EnvironmentFile=/run/flannel/subnet.env # 文件不存在是会报错
ExecStart=/usr/bin/dockerd \
-H fd:// --containerd=/run/containerd/containerd.sock \
--bip ${FLANNEL_SUBNET} \
--mtu=${FLANNEL_MTU}
source /run/flannel/subnet.env
docker network create --attachable=true --subnet=${FLANNEL_SUBNET} -o "com.docker.network.driver.mtu"=${FLANNEL_MTU} flannel
FQA
启动报错信息
[root@hdss7-11 ~]# FLANNEL_SUBNET="10.24.3.0/24"
[root@hdss7-11 ~]# FLANNEL_MTU=1450
[root@hdss7-11 ~]# dockerd --bip=${FLANNEL_SUBNET} --mtu=${FLANNEL_MTU}
WARN[2021-12-09T10:48:16.618553963+08:00] The "graph" config file option is deprecated. Please use "data-root" instead.
INFO[2021-12-09T10:48:16.618703045+08:00] Starting up
INFO[2021-12-09T10:48:16.623793979+08:00] parsed scheme: "unix" module=grpc
INFO[2021-12-09T10:48:16.623832873+08:00] scheme "unix" not registered, fallback to default scheme module=grpc
INFO[2021-12-09T10:48:16.623861447+08:00] ccResolverWrapper: sending update to cc: {[{unix:///run/containerd/containerd.sock <nil> 0 <nil>}] <nil> <nil>} module=grpc
INFO[2021-12-09T10:48:16.623871897+08:00] ClientConn switching balancer to "pick_first" module=grpc
INFO[2021-12-09T10:48:16.627321514+08:00] parsed scheme: "unix" module=grpc
INFO[2021-12-09T10:48:16.627370226+08:00] scheme "unix" not registered, fallback to default scheme module=grpc
INFO[2021-12-09T10:48:16.627398410+08:00] ccResolverWrapper: sending update to cc: {[{unix:///run/containerd/containerd.sock <nil> 0 <nil>}] <nil> <nil>} module=grpc
INFO[2021-12-09T10:48:16.627412396+08:00] ClientConn switching balancer to "pick_first" module=grpc
INFO[2021-12-09T10:48:16.640777303+08:00] Loading containers: start.
INFO[2021-12-09T10:48:16.746126687+08:00] stopping event stream following graceful shutdown error="<nil>" module=libcontainerd namespace=moby
failed to start daemon: Error initializing network controller: Error creating default "bridge" network: failed to allocate gateway (10.24.3.0): Address already in use
解决办法
Docker can only start on the default bridge IP range · Issue #22638 · moby/moby · GitHub
修改成FLANNEL_SUBNET="10.24.3.1/24"
您可以使用以下两个命令之一检查节点的 podCidr
- `kubectl get nodes -o jsonpath='{.items[*].spec.podCIDR}'``
- ``kubectl get nodes -o template --template={{.spec.podCIDR}}`
如果没有可以手动修改
kubectl patch node <NODE_NAME> -p '{"spec":{"podCIDR":"<SUBNET>"}}
容器报错
cni0 already has an ip address different from 172.24.6.1/24
解决办法
这个节点之前加入过集群,flannel 网路配置不一致导致
ip link cni0 down
ip link flannel.1 down
ip link delete cni0
ip link delete flannel.1
rm -rf /var/lib/cni/flannel/*
rm -rf /var/lib/cni/networks/cni0/*
rm -fr /etc/cni/