您的位置:首页 > 运维架构 > Docker

Docker网络(一)---------原生支持

2017-05-01 20:41 567 查看
在部署大规模Docker集群时,网络成为了最大挑战。

纯粹的Docker原生网络功能无法满足广大云计算厂商的需要,于是一大批第三方的SDN解决方案如雨后春笋般涌现出来,如Pipework, Weave, Flannel, SocketPlane等。

2015年3月,Docker宣布收购SocketPlane,一个新的Docker子项目"Libnetwork"开始酝酿。一个月后,Libnetwork在github上正式与开发者见面,预示着Docker开始在网络方面发力。

Libnetwork

https://github.com/docker/libnetwork



libnetwork提出了新的容器网络模型(CNM, Container Network Model),定义了标准的API用于为容器配置网络,其底层可以适配各种网络驱动。如下图所示:



CNM有三个重要的组件

沙盒:

沙盒是一个隔离的网络运行环境,保存了容器网络栈的配置,包括了对网络接口,路由表和DNS配置的管理。在Linux上,是用Network Namespace实现的,在其他平台上可能有不同的实现,比如FreeBSD Jail。一个沙盒可以包含来自多个网络的多个Endpoint。

Endpoint:

一个Endpoint用于将沙盒加入一个网络。Endpoint的实现可以是veth pair或者OVS内部端口。当前libnetwork的实现是veth pair.一个Endpoint只能属于一个沙盒及一个网络。通过给沙盒增加多个Endpoint可以将一个沙盒加入多个网络。

网络:

网络由一组能够相互通信的Endpoint组成。网络的实现可以是linux bridge,vlan等。

Libnetwork的出现使得Docker具备了跨主机多子网的能力,同一个子网内的不同容器可以运行在不同的主机上。

Libnetwork目前已经实现了5种驱动:

bridge:

Docker默认的容器网络驱动。Container通过一对veth pair连接到docker0网桥上,由Docker为容器动态分配IP及配置路由,防火墙规则等。

host:

容器与主机共享同一Network Namespace,共享同一套网络协议栈,路由表及iptables规则等。容器与主机看到的是相同的网络视图。

null:

容器内网络配置为空,需要用户手动为容器配置网络接口及路由。

remote:

Docker网络插件的实现。Remote driver使得Libnetwork可以通过HTTP RESTFUL API对接第三方的网络方案,类似SocketPlane的SDN方案,只要实现了约定的HTTP URL处理函数及底层的网络接口配置方法,就可以替换Docker原生的网络实现。

overlay:

Docker原生的跨主机多子网网络方案。主要通过使用Linux bridge和vxlan隧道实现,底层通过类似于etcd和consul的KV存储系统实现多机的信息同步。

基本网络配置

Docker网络初探

none:不为容器配置任何网络


$ docker run --net=none -it --name d1 debian ip addr show

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000

    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

zhangxa@ubuntu:~$

可以看到容器仅有一个lo环回接口,使用--net=none启动容器之后,仍然可以手动为容器配置网络。

container:与另一个运行中的容器共享Network namespace,共享相同的网络视图。
首先以默认网络配置(birdge模式)启动一个容器,设置hostname为dockeNet,dns为8.8.4.4

$ docker run -h dockerNet --dns 8.8.4.4 -itd debian bash

b8e47afe77af504ca8c46d52b1a7e709aa9abae8532df74ace8887d87887dd24

zhangxa@ubuntu:~$ docker exec -it b8e4 bash

root@dockerNet:/# ip addr show

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000

    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

25: eth0@if26: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default

    link/ether 02:42:ac:11:00:0c brd ff:ff:ff:ff:ff:ff

    inet 172.17.0.12/16 scope global eth0

       valid_lft forever preferred_lft forever

    inet6 fe80::42:acff:fe11:c/64 scope link

       valid_lft forever preferred_lft forever

root@dockerNet:/#

然后以--net=container:b8e4方式启动另一个容器:

$ docker run --net=container:b8e4 -it debian bash

root@dockerNet:/# ip addr show

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000

    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

25: eth0@if26: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default

    link/ether 02:42:ac:11:00:0c brd ff:ff:ff:ff:ff:ff

    inet 172.17.0.12/16 scope global eth0

       valid_lft forever preferred_lft forever

    inet6 fe80::42:acff:fe11:c/64 scope link

       valid_lft forever preferred_lft forever

root@dockerNet:/#

可以看到,使用--net=container:b8e4参数启动容器,其IP地址,DNS,hostname都继承了容器b8e4。实质上两个容器是共享同一个Network Namespace的,自然网络配置也是完全相同的。

host:与主机共享Root Network Namespace,容器有完整的权限可以操纵主机的协议栈,路由表和防火墙等,所以是不安全的。
相应的,host模式启动时需要指定--net=host参数。

$ docker run -it --net=host debian bash

root@ubuntu:/# ip addr

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000

    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: ens34: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 1000

    link/ether 00:0c:29:30:e2:e6 brd ff:ff:ff:ff:ff:ff

    inet 192.168.124.6/24 brd 192.168.124.255 scope global dynamic ens34

       valid_lft 74081sec preferred_lft 74081sec

    inet6 fe80::3b06:154f:8b60:76e5/64 scope link

       valid_lft forever preferred_lft forever

3: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000

    link/ether 00:0c:29:30:e2:dc brd ff:ff:ff:ff:ff:ff

    inet 192.168.17.140/24 brd 192.168.17.255 scope global dynamic ens33

       valid_lft 1339sec preferred_lft 1339sec

    inet6 fe80::d1e2:6e4d:a046:a2ed/64 scope link

       valid_lft forever preferred_lft forever

4: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default

    link/ether 02:42:4d:eb:09:d0 brd ff:ff:ff:ff:ff:ff

    inet 172.17.0.1/16 scope global docker0

       valid_lft forever preferred_lft forever

    inet6 fe80::42:4dff:feeb:9d0/64 scope link

       valid_lft forever preferred_lft forever

root@ubuntu:/#

host模式下,容器可以操纵主机的网络配置,这是很危险的,除非万不得已,应该尽可能避免使用host模式。

bridge:Docker设计的NAT网络模型。
Docker daemon启动时会在主机创建一个Linux网桥(默认为docker0,可通过-b参数手动指定)。容器启动时,Docker会创建一对veth pair设备,veth设备的特点是成对存在,从一端进入的数据会同时出现在另一端。Docker会将一端挂载到docker0网桥上,另一端放入容器的Network Namespace内,从而实现容器与主机通信的目的。

bridge模式下的风格拓扑如下图所示:



在桥接模式下,Docker容器与Internet的通信,以及不同容器之间的通信,都是通过iptables控制的。

Docker网络的初始化动作包括:创建docker0网桥,为docker0网桥新建子网及路由,创建相应的iptables规则等。

我们可以查看主机的路由表:

$ route -n

Kernel IP routing table

Destination     Gateway         Genmask         Flags Metric Ref    Use Iface

0.0.0.0         192.168.17.2    0.0.0.0         UG    100    0        0 ens33

0.0.0.0         192.168.124.1   0.0.0.0         UG    101    0        0 ens34

169.254.0.0     0.0.0.0         255.255.0.0     U     1000   0        0 ens33
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0

查看iptables:

# iptables -vnL

Chain INPUT (policy ACCEPT 93127 packets, 32M bytes)

 pkts bytes target     prot opt in     out     source               destination         

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)

 pkts bytes target     prot opt in     out     source               destination         

  678  109K DOCKER-ISOLATION  all  --  *      *       0.0.0.0/0            0.0.0.0/0           

  326 76320 DOCKER     all  --  *      docker0  0.0.0.0/0            0.0.0.0/0           

  326 76320 ACCEPT     all  --  *      docker0  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED

  352 32742 ACCEPT     all  --  docker0 !docker0  0.0.0.0/0            0.0.0.0/0           

    0     0 ACCEPT     all  --  docker0 docker0  0.0.0.0/0            0.0.0.0/0           

Chain OUTPUT (policy ACCEPT 58576 packets, 27M bytes)

 pkts bytes target     prot opt in     out     source               destination         

Chain DOCKER (1 references)

 pkts bytes target     prot opt in     out     source               destination         

    0     0 ACCEPT     tcp  --  !docker0 docker0  0.0.0.0/0            172.17.0.2           tcp dpt:12384

    0     0 ACCEPT     tcp  --  !docker0 docker0  0.0.0.0/0            172.17.0.2           tcp dpt:12383

    0     0 ACCEPT     tcp  --  !docker0 docker0  0.0.0.0/0            172.17.0.4           tcp dpt:12382

    0     0 ACCEPT     tcp  --  !docker0 docker0  0.0.0.0/0            172.17.0.9           tcp dpt:12380

    0     0 ACCEPT     tcp  --  !docker0 docker0  0.0.0.0/0            172.17.0.9           tcp dpt:2379

    0     0 ACCEPT     tcp  --  !docker0 docker0  0.0.0.0/0            172.17.0.11          tcp dpt:8080

    0     0 ACCEPT     tcp  --  !docker0 docker0  0.0.0.0/0            172.17.0.5           tcp dpt:12381

    0     0 ACCEPT     tcp  --  !docker0 docker0  0.0.0.0/0            172.17.0.6           tcp dpt:4443

    0     0 ACCEPT     tcp  --  !docker0 docker0  0.0.0.0/0            172.17.0.7           tcp dpt:2375

    0     0 ACCEPT     tcp  --  !docker0 docker0  0.0.0.0/0            172.17.0.3           tcp dpt:2376

    0     0 ACCEPT     tcp  --  !docker0 docker0  0.0.0.0/0            172.17.0.8           tcp dpt:4443

Chain DOCKER-ISOLATION (1 references)

 pkts bytes target     prot opt in     out     source               destination         

  678  109K RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0           

root@ubuntu:~#

查看docker0网桥:

# brctl show

bridge name    bridge id        STP enabled    interfaces

docker0        8000.02424deb09d0    no        veth0f652b1

                            veth11e2546

                            veth3d102a8

                            veth4c5b172

                            veth9b3638d

                            vethab542f0

                            vethae532c8

                            vethcd8f58a

                            vethd23a8f0

                            vethf32305b

                            vethf8df181

每个bridge模式启动的容器都会在docker0上创建一个veth.

overlay:Docker原生的跨主机多子网模型
overlay网络模型比较复杂,底层需要类似consul或etcd的KV存储系统进行消息同步,核心是通过linux bridge与vxlan隧道实现跨主机划分子网。

如下图所示:每创建一个网络,Docker会在主机上创建一个单独的沙盒,沙盒的实现实质上是一个Network Namespace。在沙盒中,Docker会创建名为br0的网桥,并在网桥上增加一个vxlan接口,每个网络占用一个vxlan ID,当前Docker创建vlxan隧道的ID范围为256~1000,因而最多可以创建745个网络。当添加一个容器到某一个网络上时,Docker会创建一对veth网卡设备,一端连接到此网络相关沙盒内的br0网桥上,别一端放入容器沙盒内,并设置br0的IP地址作为容器内路由默认的网关地址,从而实现容器加入网络的目的。



容器1和容器4属于一个网络,容器1需要通过256号vxlan隧道访问另一台主机的容器4.Docker通过vxlan和linux网桥实现了跨主机的虚拟子网功能。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: