先来说明一下flannel有两种工作方式。
- 二进制安装,flannel是独立工作的,使用etcd存储网段。
- 以pod运行,flannel集成到k8s集群里面,直接从集群获取网段数据。二进制方式应该也可以直接连接k8s集群,只是没有试成功过。
第一种:
docker通过指定flannel在节点生成的网段配置,确定docker网桥的地址,然后以docker自己的方式给容器分配ip.
第二种:
这种方式flannel也会在节点生成网段配置,但是docker却不能使用,因为需要重启docker, flannel总是在docker启动以后才开始运行,有很多不确定性。
所以需要使用cni的网络。
cni网络是Kubernetes的网络模型, 这种方式下,nodes里会包含ip信息。
如我这里查看k8s-node01的信息。
kubectl get nodes/k8s-node1 -o yaml
其中的spec段就包含ip信息。
spec:
podCIDR: 10.5.2.0/24
podCIDRs:
- 10.5.2.0/24
这样对于查找节点的容器网段也方便。
CNI(Container Network Interface): 是一种容器网络接口规范。与Docker的CNM(Container Network Model)的具体区别也说不清。
cni运行方式就是在创建容器的时候,先创建容器使用的网络命名空间,然后调用cni插件为命名空间做网络配置,最后启动容器内的进程。
kubelet通过cni配置找到对应的cni插件,由插件配置容器网络。
cni插件获取对应服务提供的信息,然后配置网络。如: flannel插件会通过flannel服务获取容器应该配置什么地址。
flannel的方式我觉得就是在主机上生成包含网络配置的文件/var/run/flannel/subnet.env,然后插件去读取。
配置
除了指定的其他都与二进制安装中的一样。
1、kube-controller-manager添加参数
添加--allocate-node-cidrs
与--cluster-cidr
如:
--allocate-node-cidrs
--cluster-cidr=10.5.0.0/16
--allocate-node-cidrs
: 允许给pod分配地址。
--cluster-cidr
: 分配给集群中的可用pod范围。 之后的flannel就是使用的这个范围。
2、下载flannel的yaml文件
git主页:
https://github.com/coreos/flannel/tree/d893bcbfe6b04791054aea6c7569dea4080cc289
下载地址:
https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
或者:
https://github.com/coreos/flannel/blob/master/Documentation/kube-flannel.yml
3、各节点准备cni插件
插件从这里下载:
https://github.com/containernetworking/plugins/releases
包含了这些插件:
[root@k8s-node1 cni]# ls bin
bandwidth bridge dhcp firewall flannel host-device host-local ipvlan loopback macvlan portmap ptp sbr static tuning vlan
[root@k8s-node1 cni]#
里面没有calico插件,calico插件是在安装calico的时候自动添加的。
我们这里使用flannel,已经包含了。
[root@k8s-node1 k8s]# ls
bin cni conf logs ssl
[root@k8s-node1 k8s]# ls bin
kubelet kube-proxy
[root@k8s-node1 k8s]# ls cni
bandwidth bridge dhcp firewall flannel host-device host-local ipvlan loopback macvlan portmap ptp sbr static tuning vlan
4、各节点准备cni配置
上面下载的flannel yaml文件里已经包含了cni配置。这个不用动,只是需要知道有这个配置。
{
"name": "cbr0",
"cniVersion": "0.3.1",
"plugins": [
{
"type": "flannel",
"delegate": {
"hairpinMode": true,
"isDefaultGateway": true
}
},
{
"type": "portmap",
"capabilities": {
"portMappings": true
}
}
]
}
5、修改kubelet启动参数
有三个参数需要指定:
--network-plugin # 调用的网络插件。如: --network-plugin=cni。
--cni-bin-dir # cni插件目录
--cni-conf-dir # cni配置目录,kubelet通过这个配置确定使用什么cni插件。然后在--cni-bin-dir目录里查找需要的插件。
其中--cni-conf-dir
默认是/etc/cni/net.d
目录,flannel.yaml包含的cni配置也是写到这个地方,所以默认就可以。kubelet会去这个目录查找配置文件,来确定使用什么cni插件。
这个目录如果原来有其它插件的配置,最好清理一下,最简单的就是yaml文件里面放个清理目录的初始化容器。
注意,如果要手动创建cni配置文件,文件的扩展名需要是conflist
,自动生成的也是这个扩展名。
--cni-bin-dir
默认位置是/opt/cni/bin/
,这里为了方便传到所有机器,修改一下路径,放到kubelet的所在的目录里。
最简单的也是把cni插件做成镜像,放到yaml的初始化容器里,最后做个例子。
注意:如果以后会用到calico
就不要修改这个参数了,因为calico
会自动在默认目录里生成calico
的cni插件,如果改了的话还要再改回来。
最终添加的参数:
--network-plugin=cni
--cni-bin-dir=/opt/k8s/cni
重启kubelet以后,因为节点暂时还没有cni配置文件,kubelet会报类似这种错误。
==> kubelet.k8s-node1.root.log.WARNING.20200307-172910.22981 <==
W0307 17:31:00.940854 22981 cni.go:237] Unable to update cni config: no networks found in /etc/cni/net.d
E0307 17:31:01.509817 22981 kubelet.go:2187] Container runtime network not ready: NetworkReady=false reason:NetworkPluginNotReady message:docker: network plugin is not ready: cni config uninitialized
==> kubelet.WARNING <==
W0307 17:31:00.940854 22981 cni.go:237] Unable to update cni config: no networks found in /etc/cni/net.d
E0307 17:31:01.509817 22981 kubelet.go:2187] Container runtime network not ready: NetworkReady=false reason:NetworkPluginNotReady message:docker: network plugin is not ready: cni config uninitialized
查看节点是notready状态。
[root@k8s-master ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-node1 NotReady <none> 5h19m v1.16.7
k8s-node2 NotReady <none> 4h28m v1.16.7
不过这个没关系,这只是因为cni网络出错导致的,kubelet其他功能没有问题。
而且flannel.yaml里面有污点容忍的配置,可以正常应用到节点。
6、安装flannel
flannel.yaml 应用以后会在节点产生两个文件
/etc/cni/net.d/10-flannel.conflist
cni配置文件,这个是yaml文件里的初始化容器放到主机上的。
/var/run/flannel/subnet.env
flannel跟集群交互获取到节点可以使用的网段放到这个文件里,这个文件也是flannel
插件需要用到的,flannel
插件默认也是会去这个路径找这个文件,来确定分配给容器的ip。插件也会检查cni网桥是否存在,没有就创建,并设置对应的ip。
flannel.yaml文件里的镜像是海外的,可能会下载失败,可以改成registry.cn-beijing.aliyuncs.com/yangxingxing/flannel
,我下载下来然后传到阿里云的。如:
image: registry.cn-beijing.aliyuncs.com/yangxingxing/flannel:v0.11.0-amd64
文件中还有一个地方:
{
"Network": "10.244.0.0/16",
"Backend": {
"Type": "vxlan"
}
}
网络模式可以看情况修改, 集群pod地址范围也是会输出在/var/run/flannel/subnet.env
文件里,如果文件里的配置会用到,可以改一下。 我这里暂时先不改, 看看效果再说。
应用文件
kubectl apply -f flannel.yml
稍等一下,kubelet日志:
==> kubelet.k8s-node1.root.log.INFO.20200307-180116.30451 <==
I0307 18:02:12.148070 30451 cni.go:206] Using CNI configuration file /etc/cni/net.d/10-flannel.conflist
I0307 18:02:12.667479 30451 kubelet.go:2184] Container runtime status: Runtime Conditions: RuntimeReady=true reason: message:, NetworkReady=true reason: message:
节点状态:
[root@k8s-master ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-node1 Ready <none> 5h54m v1.16.7
k8s-node2 Ready <none> 5h3m v1.16.7
看一下/var/run/flannel/subnet.env
文件:
[root@k8s-node1 logs]# cat /var/run/flannel/subnet.env
FLANNEL_NETWORK=10.244.0.0/16
FLANNEL_SUBNET=10.5.0.1/24
FLANNEL_MTU=1500
FLANNEL_IPMASQ=true
就是这样子,FLANNEL_SUBNET网段就是从集群获取的,因为上面controller-manager
的参数指定的是10.5.0.0/16
,分到当前节点是10.5.0.*/24
, 再起一个节点可能就是10.5.1.*/24
。
FLANNEL_NETWORK 这个网段会添加iptables的规则,如:
POSTROUTING
:
2 0 0 RETURN all -- * * 10.244.0.0/16 10.244.0.0/16
3 0 0 MASQUERADE all -- * * 10.244.0.0/16 !224.0.0.0/4
4 0 0 RETURN all -- * * !10.244.0.0/16 10.5.0.0/24
5 0 0 MASQUERADE all -- * * !10.244.0.0/16 10.244.0.0/16
FORWARD
:
num pkts bytes target prot opt in out source destination
1 0 0 ACCEPT all -- * * 10.244.0.0/16 0.0.0.0/0
2 0 0 ACCEPT all -- * * 0.0.0.0/0 10.244.0.0/16
需要在flannel.yaml文件里改一下,如:
{
"Network": "10.5.0.0/16",
"Backend": {
"Type": "host-gw"
}
}
然后删除flannel在重建就可以了。
7、最后
节点多了一个网卡:
7: cni0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
link/ether 22:2d:99:b2:dc:46 brd ff:ff:ff:ff:ff:ff
inet 10.5.0.1/24 brd 10.5.0.255 scope global cni0
valid_lft forever preferred_lft forever
inet6 fe80::202d:99ff:feb2:dc46/64 scope link
valid_lft forever preferred_lft forever
如果没有,就创建一下pod或deployment之类的,让他在节点上跑一下。
原因可能是kubelet只有在创建容器的时候才会调用cni插件。
cni0
与docker0
一样都是bridge
类型的网卡。
插件为容器配置网络环境,veth peer应该也是它挂到这个网卡的。
而非cni的模式是由docker来完成的。
看这个:
[root@k8s-master ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
test1-788f856d48-5hzkq 1/1 Running 0 58s 10.5.0.6 k8s-node1 <none> <none>
test1-788f856d48-f42fx 1/1 Running 0 37s 10.5.0.8 k8s-node1 <none> <none>
test1-788f856d48-tfkpw 1/1 Running 0 37s 10.5.0.7 k8s-node1 <none> <none>
test1-788f856d48-vvvn7 1/1 Running 0 37s 10.5.1.3 k8s-node2 <none> <none>
test1-788f856d48-wfvdg 1/1 Running 0 37s 10.5.1.2 k8s-node2 <none> <none>
test2-78597966d7-jtjbm 1/1 Running 0 123m 172.17.0.5 k8s-node2 <none> <none>
test2-78597966d7-k2h5n 1/1 Running 0 154m 172.17.0.4 k8s-node2 <none> <none>
test2-78597966d7-n6zrc 1/1 Running 0 154m 172.17.0.2 k8s-node2 <none> <none>
test2-78597966d7-r4hmd 1/1 Running 0 123m 172.17.0.6 k8s-node2 <none> <none>
test2-78597966d7-zx6gv 1/1 Running 0 154m 172.17.0.3 k8s-node2 <none> <none>
test2是之前创建的, 都在node2是因为node1做实验停了段时间。
[root@k8s-node2 logs]# brctl show
bridge name bridge id STP enabled interfaces
cni0 8000.6af0a81db5e0 no veth8fe78c44
vethd9ea07f0
docker0 8000.02421e8c8c03 no veth0dfed0a
veth134a1c3
veth268742c
veth3cfdc7b
veth606a09b
[root@k8s-node2 logs]#
test2还是挂载docker0上的, 在本节点运行也正常,只是不能跨节点,这个跟cni插件没关系。只是因为flannel配置的网段原因。
总之flannel
cni插件与flannel这是两个不同的东西,只是cni需要flannel提供一些信息。 而flannel的主业就是解决跨节点问题。就算flannel没了,cni插件还是正常配置容器网络。
把cni插件集成到yml
后边加的,跟上面的文件版本不一样。
1、作镜像
因为不想破坏flannel自己的镜像。所以就找个小镜像,把flannel的cni插件放进去。
反正就只是一个承载cni插件的镜像,所以Dockerfile非常简单, 这里选择了busybox做基础镜像,因为够小。只需要插件中的flannel
和portmap
。
我直接把插件的压缩包放里面了,因为简单测试了一下发现好几个插件都需要。
需要各种插件初始化容器的网络环境。
[root@docker1 dockerfile]# ls
cni.tgz Dockerfile
[root@docker1 dockerfile]# cat Dockerfile
FROM busybox
COPY cni.tgz /cni/
最终生成的镜像, tag是cni插件的版本号。
harbor.atest.pub/k8s/flannel-cni:v0.9.0
2、修改flannel.yaml文件
就两个地方,一个是添加volume。 一个是添加初始化容器。
1、
2、