充当连接容器到网桥的虚拟介质叫做Veth Pair。这个东西一头连接在容器的eth0上,一头连接在网桥上,而且连接在网桥上的这一端没有网络协议栈功能可以理解为就是一个普通交换机的端口,只有一个MAC地址;而连接在容器eth0上的一端则具有网站的网络协议栈功能。
完成上述功能就是通过Libnetwork来实现的:
Libnetwork是CNM原生实现的,它为Docker daemon和网络驱动之间提供了接口,网络控制器负责将驱动和一个网络对接,每个驱动程序负责管理它拥有的网络以及为网络提供各种负责,比如IPAM,这个IPAM就是IP地址管理。
Docker daemon启动也就是dockerd这个进程,它会创建docker0,而docker0默认用的驱动就是bridge,也就是创建一个虚拟网桥设备,且具有IP地址,所以dockerd启动后你通过ifconfig 或者 ip addr可以看到docker0的IP地址。
接下来就可以创建容器,我们使用docker这个客户端工具来运行容器,容器的网络栈会在容器启动前创建完成,这一系列的工作都由Libnetwork的某些接口(底层还是Linux系统调用)来实现的,比如创建虚拟网卡对(Veth pair),一端连接容器、一端连接网桥、创建网络名称空间、关联容器中的进程到其自己的网络名称空间中、设置IP地址、路由表、iptables等工作。
在dockerd这个程序中有一个参数叫做--bridige和--bip,它就是设置使用哪个网桥以及网桥IP,如下:
dockerd --bridge=docker0 --bip=X.X.X.X/XX
通过上面的描述以及这样的设置,启动的容器就会连接到docker0网桥,不写--bridge默认也是使用docker0,--bip则是网桥的IP地址,而容器就会获得和网桥IP同网段的IP地址。
上述关于网络的东西也没有什么神秘的,其实通过Linux命令都可以实现,如下就是在主机上创建网桥和名称空间,然后进入名称空间配置该空间的网卡对、IP等,最后退出空间,将虚拟网卡对的一端连接在网桥上。
# 创建网桥 brctl addbr # 创建网络名称空间 ip netns add # 进入名称空间 ip netns exec bash # 启动lo ip link set lo up # 在创建的名称空间中建立veth pair ip link add eth0 type veth peer name veth00001 # 为eth0设置IP地址 ip addr add x.x.x.x/xx dev eth0 # 启动eth0 ip link set eth0 up # 把网络名称空间的veth pair的一端放到主机名称空间中 ip link set veth00001 netns # 退出名称空间 exit # 把主机名称空间的虚拟网卡连接到网桥上 brctl addif veth0001 # 在主机上ping网络名称空间的IP地址 ping x.x.x.x Kubernetes项目但是对于Kubernetes项目稍微有点不同,它自己不提供网络功能(早期版本有,后来取消了)。所以就导致了有些人的迷惑尤其是初学者,自己安装的Kubernetes集群使用的cni0这个网桥,有些人则使用docker0这个网桥。其实这就是因为Kubernetes项目本身不负责网络管理也不为容器提供具体的网络设置。而网络插件的目的就是为了给容器设置网络环境。
这就意味着在Kubernetes中我可以使用docker作为容器引擎,然后也可以使用docker的网络驱动来为容器提供网络设置。所以也就是说当你的POD启动时,由于infra是第一个POD中的容器,那么该容器的网络栈设置是由Docker daemon调用Libnetwork接口来做的。那么我也可以使用其他的能够完成为infra设置网络的其他程序来执行这个操作。所以CNI Plugin它的目的就是一个可执行程序,在容器需要为容器创建或者删除网络是进行调用来完成具体的操作。
所以这就是为什么之前要说一下POD中多容器是如何进行本地通信的原因,你设置POD的网络其实就是设置Infra这个容器的Network Namespace的网络栈。
在Kubernetes中,kubelet主要负责和容器打交道,而kubelet并不是直接去操作容器,它和容器引擎交互使用的是CRI(Container Runtime Interface,它规定了运行一个容器所必须的参数和标准)接口,所以只要容器引擎提供了符合CRI标准的接口那么可以被Kubernetes使用。那么容器引擎会把接口传递过来的数据进行翻译,翻译成对Linux的系统调用操作,比如创建各种名称空间、Cgroups等。而kubelet默认使用的容器运行时是通过kubelet命令中的--container-runtime=来设置的,默认就是docker。
如果我们不使用docker为容器设置网络栈的话还可以怎么做呢?这就是CNI,kubelet使用CNI规范来配置容器网络,那么同理使用CNI这种规范也是通过设置Infra容器的网络栈实现POD内容器共享网络的方式。那么具体怎么做呢?在kubelet启动的命令中有如下参数:
--cni-bin-dir=STRING这个是用于搜索CNI插件目录,默认/opt/cni/bin
--cni-conf-dir=STRING这个是用于搜索CNI插件配置文件路径,默认是/opt/cni/net.d
--network-plugin=STRING这个是要使用的CNI插件名,它就是去--cni-bin-dir目录去搜索
我们先看看CNI插件有哪些,官网分了三大类,如下图: