libnetwork插件化网络功能
Docker把网络跟存储这两部分的功能实现都以插件化形式剥离出来,允许用户通过指令来选择不同的后端实现。这也是Docker希望构建围绕着容器的强大生态系统的一些积极的尝试。剥离出来的独立容器网络项目叫libnetwork,从名字就能看出来,它希望将来为不同容器定义统一规范的网络层标准。
容器网络模型
libnetwork中容器网络模型(Container Networking Model,CNM)十分简洁,可以让上层使用网络的大量应用容器最大程度上不去关心底层实现。
容器网络模型的结构如图所示。
包括三种基本元素:
- Sandbox(沙盒):代表一个容器(准确地说,是其网络命名空间);
- Endpoint(接入点):代表网络上可以挂载容器的接口,会分配IP地址;
- Network可以连通多个接入点的一个子网。
对于使用CNM的容器管理系统来说,具体底下网络如何实现,不同子网彼此怎么隔离,有没有QoS,都可以不关心。只要插件能提供网络和接入点,只需把容器给接上或者拔下,剩下的都是插件驱动自己去实现。这样就解耦和容器和网络功能,十分灵活。
首先,是驱动注册自己到网络控制器,网络控制器使用驱动类型,来创建网络,然后在创建的网络上创建接口,最后把容器连接到接口上即可。销毁过程则正好相反,先把容器从接入口上卸载,然后删除接入口和网络即可。
CNM的典型生命周期如图所示:
目前CNM支持的驱动类型有四种:Null、Bridge、Overlay、Remote。简单介绍如下:
- Null:不提供网络服务,容器启动后无网络连接;
- Bridge:就是Docker传统上默认用Linux网桥和Iptables实现的单机网络;
- Overlay:是用vxlan隧道实现的跨主机容器网络;
- Remote:扩展类型,预留给其他外部实现的方案,比如有一套第三方的SDN方案(如OpenStack Neutron),就可以接进来。
从位置上看,libnetwork上面支持Docker,下面支持网络插件,自身处于十分关键的中间层。如果熟悉计算机网络协议模型的话,libnetwork就是最核心的TCP/IP层。目前,已有大量的网络方案开始支持libnetwork。包括OpenStack Kuryr项目,通过支持libnetwork,让Docker可以直接使用Neutron提供的网络功能。Calico等团队也编写了插件支持libnetwork,从而无缝地支持Docker网络功能。
Docker网络相关命令
在libnetwork支持下,Docker网络相关命令都作为network的子命令出现。
围绕着管理CNM的生命周期,主要包括以下命令:
- ls:列出所有的网络;
- create:创建一个网络;
- rm:删除一个网络;
- connect:把容器接入到网络;
- disconnect:把容器从网络卸载下来;
- inspect:查看网络的详细信息。
下面分别介绍这些命令。
1.列出网络
命令格式:docker network ls [OPTIONS]
支持参数包括:
-f:指定输出过滤器;
--no-trunc:不截断输出内容。
实际上,在不执行额外网络命令的情况下,用户执行docker network ls命令,一般情况下可以看到已创建的三个网络:
$ docker network ls
NETWORK ID NAME DRIVER 461e02c94370 bridge bridge e4d5886b2d2f none null adbc1879bac5 host host
分别为三种驱动的网络:null、host和bridge。
2.创建网络
命令格式:docker network create [OPTIONS] NETWORK
支持参数包括:
--aux-address value:辅助的IP地址;
-d,--driver string:网络驱动类型,如bridge或overlay;
--gateway value:网关地址;
--internal:禁止外部对创建网络的访问;
--ip-range value:分配IP地址范围;
--ipam-driver string:IP地址管理的插件类型;
--ipam-opt value:IP地址管理插件的选项;
--ipv6:支持IPv6地址;
--label value:为网络添加元标签信息;
-o,--opt value:网络驱动支持的选项;
--subnet value:网络地址段。
3.删除网络
删除指定的网络。当网络上并不存在接入点时,删除成功。
命令格式:docker network rm NETWORK [NETWORK...]
4.接入容器
将一个容器连接到一个已存在的网络上。命令格式:docker network connect [OPTIONS] NETWORK CONTAINER
支持参数包括:
--alias value:为容器添加一个别名,此别名仅在所添加网络上可见;
--ip string:指定IP地址;
--ip6 string:指定IPv6地址;
--link value:添加链接到另外一个容器;
--link-local-ip value:为容器添加一个链接地址。
5.卸载容器
将一个连接到网络上的容器从网络上移除。命令格式:docker network disconnect [OPTIONS] NETWORK CONTAINER
支持参数包括-f、--force:强制把容器从网络上移除。
6.查看网络信息
查看已存在网络的具体信息。命令格式:docker network inspect [OPTIONS] NETWORK [NETWORK...]
支持参数包括-f、--format string:给定一个golang模板字符串,对输出结果进行格式化。
构建跨主机容器网络
使用libnetwork自带的Overlay类型驱动来轻松实现跨主机的网络通信。Overlay驱动默认采用VXLAN协议,在IP地址可以互相访问的多个主机上之间搭建隧道,让容器可以互相访问。
1.配置网络信息管理数据库
我们知道,在现实世界中,要连通不同的主机需要交换机或路由器(跨子网时需要)这样的互联设备。这些设备一方面是在物理上起到连接作用,但更重要的是起到了网络管理的功能。例如,主机位置在什么地方,地址是多少等信息,都需要网络管理平面来维护。
在libnetwork的网络方案中,要实现跨主机容器网络也需要类似的一个网络信息管理机制,只不过这个机制简单得多,只是一个键值数据库而已,如Consul、Etcd、ZooKeeper等工具都可以满足需求如图所示。
以Consul为例,启动一个progrium/consul容器,并映射服务到本地的8500端口,用如下命令即可:
$ docker run -d \
-p "8500:8500" \
-h "consul" \
progrium/consul -server -bootstrap
所在主机作为数据库节点。
2.配置Docker主机
启动两台Docker主机n1和n2,分别安装好最新的Docker-engine(1.7.0+)。确保这两台主机之间可以通过IP地址互相访问,另外,都能访问到数据库节点的8500端口。
配置主机的Docker服务启动选项如下所示:
DOCKER_OPTS="$DOCKER_OPTS --cluster-store=consul://<consul_node>:8500 --cluster-advertise=eth0:2376"
重新启动Docker服务如下所示:
$ sudo service docker restart
3.创建网络
分别在n1和n2上查看现有的Docker网络,包括三个默认网络:分别为bridge、host和none类型。
n1:$ docker network ls
n2:$ docker network ls
在任意节点上创建网络multi,例如在n1上执行如下命令即可完成对跨主机网络的创建:
n1:$ docker network create -d overlay multi
创建成功后,可以同时在n1和n2上查看到新的网络multi的信息:
n1:$ docker network ls
n2:$ docker network ls
NETWORK ID NAME DRIVER dc581a3eab4c bridge bridge ee21a768c6f6 host host eadd374a1843 multi overlay 8d1ee747b894 none null
此时,还可以通过docker network inspect命令查看网络的具体信息:
$ docker network inspect multi
4.测试网络
在n1上启动一个容器c1,通过--net选项指定连接到multi网络上。查看网络信息,其中一个接口eth0已经连接到了multi网络上:
n1:$ docker run -it --name=c1 --net=multi busybox
/ # ip a
在n2上启动一个容器c2,同样连接到multi网络上。
通过ping c1进行测试,可以访问到另外一台主机n1上的容器c1:
n2:$ docker run -it --name=c2 --net=multi busybox
/ # ping c1