经过一个星期的加班到9点,终于将docker的网络部分小小的总结了一下,小编在这之前也发布过关于docker的内容,本来想就此结束,但是总感觉少了些什么,只会docker的命令,仿佛不能深入的理解docker强大之处,所以小编决定在补充一下关于docker的网络部分,包括docker的网络模式、容器通信、以及相应的实战操作。虽然这部分有些难以理解,但是细细研读之后,一定会有所收获。

1.docker的网络模式

  安装Docker时,它会自动创建三个网络,bridge(创建容器默认连接到此网络,也就是在不使用--network参数时)、 none 、host。还有以后一种自定义模式,自定义模式有三种:bridge、overlay、macvlan。 我们可以使用一下命令,查看本机容器间通信的几种方式:

 docker network ls

  我们可以在docker run的时候使用**--net= none/ host/ bridge**来设置容器具体使用哪种模式。

(1)默认网络通信模式bridge网桥

  默认情况下docker运行容器时,宿主机会创建一个bridge网桥,是一个名叫docker 0的虚拟网桥 ,默认docker 0 IP为172.17.0.1,网桥再给容器分配虚拟子网IP,并且以网桥IP作为网关。在不指定网络的情况下,容器之间的通信都是通过bridge网桥进行通信。然后网桥在与宿主机镜像进行IP转换,端口映射等通信。   这种bridge网桥与容器,与宿主机之间的通信,有点类似与三层路由交换:     

(2) host宿主机模式

  如果容器指定网络模式为host,容器不会有自己的network namespace,而是和宿主机共用一个network网络及IP,容器不会有虚拟出自己的网卡、IP等,当然除了网络通信这一块和宿主机绑定了,其余的容器内容还是和宿主机安全隔离了。这种在做容器迁移时,很不方便,不推荐使用。

(3) none模式

  容器指定网络模式-net为none时,docker容器不再拥有自己的network namespace,但是所有网络配置都得自行配置,如IP、网卡等,这种方式很麻烦。(关闭了容器的网络功能) 这里补充两个docker服务运行时参数 -b BRIDGE or--bridge=BRIDGE ——指定容器挂载的网桥; --fixed-cidr=10.200.55.64/26 #定制容器的IP地址范围

2.单机间的容器通信

  单机间的通信,就是同一宿主机中的不同容器之间的通信,容器之间可通过** IP,Docker DNS Server 和joined** 容器三种方式通信。

(1)IP通信

  两个容器要能通信,必须要有属于同一个网络的网卡。满足这个条件后,容器就可以通过 IP 交互了。这也是默认的方式,我们在使用--net= bridge,docker虚拟出来的一个docker0网桥,会给每一个容器在docker0网桥的网段中分配一个IP,这样同主机中的容器的IP是同一网段的自然可以通过IP相互访问。 演示:

[root@zzy ~]# ifconfig

这里看到我的这台机器中的docker0的网桥的地址为172.17.0.1,这台机器中启动的所有的docker的容器的IP都是这个网段的。

[root@zy ~]# docker ps  #查看正在运行的docker容器

我这里有两个一个是registry一个是MySQL。

[root@zy ~]# docker inspect 28b2c91d4be4|grep -i ipaddress #查看容器的IP

[root@zy ~]# docker inspect 5708c1dcbdd7|grep -i ipaddress #查看容器的IP

可以发现这两个容器的IP地址果然都是172.17.0.1网段的。

(2)docker DNS server

  通过 IP 访问容器虽然满足了通信的需求,但还是不够灵活。因为我们在部署服务之前可能不能确定IP。比如:现在部署一个Nginx web服务,但是每次容器启动分配的IP地址都会改变,我们无法通过固定的IIP地址去访问web服务,这样每次访问时都要查看IP,非常麻烦,对于这个问题,可以通过 docker 自带的 DNS 服务解决。   从 Docker 1.10 版本开始,docker daemon 实现了一个内嵌的 DNS server,使容器可以直接通过"容器名"通信。方法很简单,只要在启动时用 --name 为容器命名就可以了。 演示:

#下面在同主机启动两个Ubuntu系统并指定--name:
[root@zy ~]#docker run -it --network=brideg2 --name box1 ubuntu:net /bin/bash
[root@zy ~]#docker run -it --name --network= brideg2 box2 ubuntu:net /bin/bash

我们发现使用--name,的容器名称可以ping通其他容器。 注意:使用 docker DNS 有个限制:只能在** user-defined** 网络中使用。也就是说,默认的 bridge 网络是无法使用 DNS 的。

(3) joined 容器

  joined 容器是另一种实现容器间通信的方式。它可以使两个或多个容器共享一个网络栈,共享网卡和配置信息,joined 容器之间可以通过 127.0.0.1 直接通信。 演示:

#启动一个http服务
[root@zy ~]# docker run -dit --name my-apache-app  -p 8099:80 -v "/http":/usr/local/apache2/htdocs/ httpd
#创建一个Ubuntu容器容器并通过 --network=container: my-apache-app指定 jointed 容器为 my-apache-app
[root@zy ~]# docker run -it --network=container:my-apache-app ubuntu:net /bin/bash
#使用命令去访问my-apache-app容器中的web页面
root@ec745e2fbf4a:/# curl 127.0.0.1

此时我们发现访问成功!原因是:我们分别查看着两个容器的IP: Ubuntu: http: 我们发现两个容器的网卡 mac 地址与 IP 完全一样,它们共享了相同的网络栈。所以Ubuntu容器可以使用127.0.0.1直接访问http容器的web服务。

(4) 补充

docker run 命令的参数介绍:

	-h 运行容器时指定主机名,这样我们可以使用主机名去与容器通信。
	--link=容器名 别名  ,这样使用--link连接的容器间就可以使用主机名进行通信。
	-p host_port:container_port 端口映射,容器的服务端口映射到宿主机。
	-P  container_port    端口映射,映射到宿主机的任意空闲端口。

容器的访问控制 容器访问外部网络:两种方法:   - sysctl -w net.ipv4.ip_forward=1 (设置宿主机的开启数据转发)   - 启动Docker服务的时候设定--ip-forward=true,docker会自动打开宿主机系统的转发服务 外部访问容器:这里很简单,通过docker run -h hostname -p 端口映射,来实现外部访问容器。

3.跨主机间的容器通信

(1)Docker网桥实现跨主机容器连接

  在同一宿主机下docker容器之间是可以相同连通的。这是因为默认的docker容器在同一宿主机下,所有容器分配的IP处于同一个地址段的,相互之间可以ping通;当我们使用ifconfig命令查看IP时会发现,其中有一个docker0的网桥,docker容器通过docker0 网桥实现同一主机间中,容器的IP地址分配和访问,这就保证了所有的容器在同一地址段。   虽然这些IP地址在同一宿主机中是处于同一网段并且相互之间可以通信,但是如果在不同宿主机之间,如果网桥的网段不同,容器之间还是不可能实现跨住进的通信,那么我们可以将每个主机下的容器的网段都处于同一网段,这样,就可以实现跨主机的访问啦,这也是Docker容器默认跨主机之间的连接方法的第一种:网桥实现。   上图就是网桥方式实现跨主机的连接,但是缺点也很明显,宿主机和容器的IP处于同一网段,如果在局域网下,IP地址是有限的,那么一个容器占据一个IP地址,IP地址很快就会被用光,这就是个不友好的现象,所以这种方式仅仅只用来学习测试使用。 实战操作: 实验环境:

主机名 IP Gateway Netmask
Host1 192.168.130.130 192.168.130.2 255.255.255.0
Host2 192.168.130.131 192.168.130.2 255.255.255.0

① 下载网桥管理工具

yum install -y bridge-utils

② 分别在docker主机上建立网桥

Host1: $ sudo brctl addbr br0
Host2: $ sudo brctl addbr br0

③ 为网桥分配一个同网段IP

Host1: $ sudo ifconfig br0 192.168.130.10 netmask 255.255.255.0
Host2: $ sudo ifconfig br0 192.168.130.20 netmask 255.255.255.0

④ 桥接本地网卡

Host1: $ brctl addif br0 eth0
Host2: $ brctl addif br0 eth0

⑤ 修改docker配置文件

$ Host1 vim /etc/default/docker
$ Host2 vim /etc/default/docker

改成:Host1: DOCKER_OPTS=” -b=br0 –fixed-cidr=‘192.168.130.64/26“ Host2: DOCKER_OPTS=” -b=br1 –fixed-cidr=‘192.168.130.128/26“ 这里的: **-b **:用来指定容器连接的网桥的名字。 **--fixed-cidr **:用来限定容器分配的IP地址的范围。 ⑥重启docker

$ Host1 systemctl daemon-reload
$ Host1 systemctl restart docker 
$ Host2 systemctl daemon-reload
$ Host2 systemctl restart docker

⑦ 测试 这里在host1和host2中各启动一个容器,然后相互ping对方容器IP,如果可以ping桶表示配置成功。

(2)Open vSwitch 实现跨主机容器通信

  Open vSwitch是一个高质量、多层虚拟交换机。使用Apache2.0许可协议,旨在通过编程扩展,使庞大的网络自动化(配置、管理、维护),同时还支持标准的管理接口和协议。 实战操作:

实验环境:

主机名 IP Gateway Netmask
Host1 192.168.130.130 192.168.130.2 255.255.255.0
Host2 192.168.130.131 192.168.130.2 255.255.255.0

虚拟机网段:

主机名 网段
Host1 192.168.1.1
Host2 192.168.2.1

操作步骤:

  • 在虚拟机中建立ovs网桥

  • 添加gre连接

  • 配置docker容器虚拟网桥接

  • 为虚拟网桥添加ovs接口

  • 添加不同Docker容器网段路由 ① 安装Open vSwitch并启动

    [root@ Host1~]#yum install -y openvswitch.x86_64 [root@ Host1~]#systemctl start openvswitch

② 安装网桥

[root@ Host1~]# yum install -y bridge-utils

③ 建立ovs网桥并添加GRE接口

[root@ Host1~]# ovs-vsctl add-br obr0
[root@ Host1~]# ovs-vsctl add-port obr0 gre0

④ 设置远程的网桥连接

[root@ Host1~]#ovs-vsctl set interface gre0 type=gre options:remote_ip=192.168.130.131
#查看osv网桥配置
[root@ Host1~]#ovs-vsctl show

⑤ 设置docker的虚拟网桥

[root@ Host1~]#brctl addbr br0
[root@ Host1~]#ifconfig br0 192.168.1.1 netmask 255.255.255.0
[root@ Host1~]#brctl addif br0 obr0
[root@ Host1~]#brctl show

⑥ 设置路由规则

[root@ Host1~]#ip route add 192.168.2.0/24 via 192.168.130.131 dev ens33

同理host2也需要按照上述方式配置。最后两个容器之间就可以通信。

(3)Weave实现跨主机容器通信

   Weave是由weaveworks公司开发的解决Docker跨主机网络的解决方案,它能够创建一个虚拟网络,用于连接部署在多台主机上的Docker容器,这样容器就像被接入了同一个网络交换机,那些使用网络的应用程序不必去配置端口映射和链接等信息。   外部设备能够访问Weave网络上的应用程序容器所提供的服务,同时已有的内部系统也能够暴露到应用程序容器上。Weave能够穿透防火墙并运行在部分连接的网络上,另外,Weave的通信支持加密,所以用户可以从一个不受信任的网络连接到主机。 原理:

  Weave会在主机上创建一个网桥,每一个容器通过 veth pair 连接到该网桥上,同时网桥上有个 Weave router 的容器与之连接,该router会通过连接在网桥上的接口来抓取网络包(该接口工作在Promiscuous模式)。   在每一个部署Docker的主机(可能是物理机也可能是虚拟机)上都部署有一个W(即Weave router),它本身也可以一个容器的形式部署。Weave run的时候就可以给每个veth的容器端分配一个ip和相应的掩码。veth的网桥这端就是Weave router容器,并在Weave launch的时候分配好ip和掩码。   Weave网络是由这些weave routers组成的对等端点(peer)构成,每个对等的一端都有自己的名字,其中包括一个可读性好的名字用于表示状态和日志的输出,一个唯一标识符用于运行中相互区别,即使重启Docker主机名字也保持不变,这些名字默认是mac地址。   每个部署了Weave router的主机都需要将TCP和UDP的6783端口的防火墙设置打开,保证Weave router之间控制面流量和数据面流量的通过。控制面由weave routers之间建立的TCP连接构成,通过它进行握手和拓扑关系信息的交换通信。 这个通信可以被配置为加密通信。而数据面由Weave routers之间建立的UDP连接构成,这些连接大部分都会加密。这些连接都是全双工的,并且可以穿越防火墙。 实战操作: 实验环境:

主机名 IP Gateway Netmask
Host1 192.168.130.130 192.168.130.2 255.255.255.0
Host2 192.168.130.131 192.168.130.2 255.255.255.0

① 下载复制weave二进制执行文件

[root@ Host1~]#git clone https://github.com/weaveworks/weave
[root@ Host1~]#cp -p /root/weave/weave  /usr/bin/
[root@ Host1~]#cd /usr/bin/
#查看weave版本
[root@ Host1~]#weave version

② 启动weave服务

[root@ Host1~]# weave launch --no-detect-tls  #注意第一次启动会在docker中拉取相应的镜像

③ 运行一个容器

[root@ Host1~]#docker run -it ubuntu:net /bin/bash  

然后Ctrl+p+q退出容器,并且让容器后台运行 ④ 进入容器

[root@ Host1~]#weave attach 192.168.2.1/24 c45932ef7da4

注意:这里的192.168.2.1/24 是默认的给当前容器分配的一个weaveIP 之后再host2宿主机中也执行以上的命令,并且在“weave attach 192.168.2.1/24 容器ID” 这里分配一相同网段的不同IP。 此时通过这个ethwe中的IP,去相同ping对方容器,这里就可以相同访问: