理解docker,主要从namesapce,cgroups,联合文件,运行时(runC),网络几个方面。接下来咱们会花一些时间,分别介绍。git
namesapce主要是隔离做用,cgroups主要是资源限制,联合文件主要用于镜像分层存储和管理,runC是运行时,遵循了oci接口,通常来讲基于libcontainer。网络主要是docker单机网络和多主机通讯模式。github
咱们在使用docker run建立Docker容器时,能够用--net选项指定容器的网络模式,Docker有如下4种网络模式:docker
下面分别介绍一下Docker的各个网络模式。ubuntu
1)none:不为容器配置任何网络功能。
在该模式下,须要以--net=none参数启动容器:segmentfault
$ docker run --net=none -ti ubuntu:latest ip addr show 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever
能够看到Docker容器仅有一lo环回接口,用户使用--net=none启动容器以后,仍然能够手动为容器配置网络。安全
2)container:与另外一个运行中的容器共享Network Namespace,共享相同的网络视图。
举个例子,首先以默认网络配置(bridge模式)启动一个容器,设置hostname为dockerNet,dns为8.8.4.4。bash
$ docker run -h dockerNet --dns 8.8.4.4 -tid ubuntu:latest bash d25864df1a3bbdd40613552197bd1a965acaf7f3dcb2673d50c875d4a303a67f $ docker exec -ti d25864df1a3b bash root@dockerNet:/# ip addr show 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 1739: eth0: <BROADCAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:ac:11:00:01 brd ff:ff:ff:ff:ff:ff inet 172.17.0.1/16 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::42:acff:fe11:1/64 scope link valid_lft forever preferred_lft forever root@dockerNet:/# cat /etc/resolv.conf nameserver 8.8.4.4 root@dockerNet:/# exit exit
而后以--net=container:d25864df1a3b方式启动另外一个容器:网络
$ docker run --net=container:d25864df1a3b -ti ubuntu:latest bash root@dockerNet:/# ip addr show 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 1739: eth0: <BROADCAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:ac:11:00:01 brd ff:ff:ff:ff:ff:ff inet 172.17.0.1/16 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::42:acff:fe11:1/64 scope link valid_lft forever preferred_lft forever root@dockerNet:/# cat /etc/resolv.conf nameserver 8.8.4.4
能够看到,使用--net=container:d25864df1a3b参数启动的容器,其IP地址、DNS、hostname都继承了容器d25864df1a3b。实质上两个容器是共享同一个Network Namespace的,天然网络配置也是彻底相同。oop
3)host:与主机共享Root Network Namespace,容器有完整的权限能够操纵主机的协议栈、路由表和防火墙等,因此被认为是不安全的。
相应的,host模式启动时须要指定--net=host参数。举个例子:google
$ docker run -ti --net=host ubuntu:latest bash root@darcy-HP:/# ip addr show 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast state DOWN group default qlen 1000 link/ether 2c:41:38:9e:e4:d5 brd ff:ff:ff:ff:ff:ff 3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 link/ether 00:1b:21:cc:ee:6d brd ff:ff:ff:ff:ff:ff inet 10.110.52.38/22 brd 10.110.55.255 scope global eth1 valid_lft forever preferred_lft forever inet6 fe80::21b:21ff:fecc:ee6d/64 scope link valid_lft forever preferred_lft forever 1642: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 22:f2:f3:18:62:5d brd ff:ff:ff:ff:ff:ff inet 172.17.42.1/16 scope global docker0 valid_lft forever preferred_lft forever inet6 fe80::348e:71ff:fe44:2d41/64 scope link valid_lft forever preferred_lft forever
host模式下,容器能够操纵主机的网络配置,这是危险的,除非万不得已,应该尽量避免使用host模式。
4)bridge:Docker设计的NAT网络模型。
Docker daemon启动时会在主机建立一个Linux网桥(默认为docker0,可经过-b参数手动指定)。容器启动时,Docker会建立一对veth pair(虚拟网络接口)设备,veth设备的特色是成对存在,从一端进入的数据会同时出如今另外一端。Docker会将一端挂载到docker0网桥上,另外一端放入容器的Network Namespace内,从而实现容器与主机通讯的目的。bridge模式下的网络拓扑图以下图所示。
在桥接模式下,Docker容器与Internet的通讯,以及不一样容器之间的通讯,都是经过iptables规则控制的。
总之,Docker网络的初始化动做包括:建立docker0网桥、为docker0网桥新建子网及路由、建立相应的iptables规则等。
docker在跨主机通讯方面一直比较弱。目前主要有容器网络模型(CNM)和容器网络接口(CNI),下面咱们分别介绍。固然k8s和docker之间通讯采纳的是CNI。
CNM是一个被 Docker 提出的规范。如今已经被Cisco Contiv, Kuryr, Open Virtual Networking (OVN), Project Calico, VMware 和 Weave 这些公司和项目所采纳。
Libnetwork是CNM的原生实现。它为Docker daemon和网络驱动程序之间提供了接口。网络控制器负责将驱动和一个网络进行对接。每一个驱动程序负责管理它所拥有的网络以及为该网络提供的各类服务,例如IPAM等等。由多个驱动支撑的多个网络能够同时并存。网络驱动能够按提供方被划分为原生驱动(libnetwork内置的或Docker支持的)或者远程驱动 (第三方插件)。原生驱动包括 none, bridge, overlay 以及 MACvlan。驱动也能够被按照适用范围被划分为本地(单主机)的和全局的 (多主机)。
『Network Sandbox』– 一个容器内部的网络栈。
『Endpoint』– 一个一般成对出现的网络接口。一端在网络容器内,另外一端在网络内。 一个Endpoints能够加入一个网络。一个容器能够有多个endpoints。
『Network』– 一个endpoints的集合。该集合内的全部endpoints能够互联互通。
最后,CNM还支持标签(labels)。Lable是以key-value对定义的元数据。用户能够经过定义label这样的元数据来自定义libnetwork和驱动的行为。
接着咱们看下通常使用libnetwork的方法,具体的步骤通常是下面这样的:
(1)获取一个NetworkController对象用于进行下面的操做。获取对象的时候指定Driver。
(2)经过NetworkController对象的NewNetwork()创建一个网络。这里最简单的理解就是如今咱们有了一个bridge了。
(3)经过网络的CreateEndpoint()在这个网络上创建Endpoint。这里最简单的理解就是每创建一个Endpoint,咱们上面创建的bridge上就会多出一个VIF口等着虚拟机或者Sandbox连上来。假设这里使用的是veth,则veth的一头目前接在了bridge中,另外一头还暴露在外面。
(4) 调用上面创建的Endpoint的Join方法,提供容器信息,因而libnetwork的代码就会创建一个Sandbox对象(通常这里的Sandbox就是容器的namespace,因此不会重复创建),而后将第三步创建的veth的一头接入到这个Sandbox中,也就是将其放到Sandbox的namespace中。
(5)当Sandbox的生命周期结束时,调用Endpoint的Leave方法使其从这个Network中解绑。简单的说就是将veth从Sandbox的namespace中拿出来回到物理机上。
(6)若是一个Endpoint无用了,则能够调用Delete方法删除。
(7)若是一个Network无用了,则能够调用Delete方法删除。
CNI(Conteinre Network Interface) 是 google 和 CoreOS 主导制定的容器网络标准,它 自己并非实现或者代码,能够理解成一个协议。这个标准是在 rkt 网络提议 的基础上发展起来的,综合考虑了灵活性、扩展性、ip 分配、多网卡等因素。
这个协议链接了两个组件:容器管理系统和网络插件。它们之间经过 JSON 格式的文件进行通讯,实现容器的网络功能。具体的事情都是插件来实现的,包括:建立容器网络空间(network namespace)、把网络接口(interface)放到对应的网络空间、给网络接口分配 IP 等等。
CNI自己实现了一些基本的插件(https://github.com/containern..., 好比bridge、ipvlan、macvlan、loopback、vlan等网络接口管理插件,还有dhcp、host-local等IP管理插件,而且主流的container网络解决方案都有对应CNI的支持能力,好比Flannel、Calico、Weave、Contiv、SR-IOV、Amazon ECS CNI Plugins等。
具体Flannel的分析能够阅读我以前的文章(k8s与网络--Flannel解读)。