在网络的上篇中我们了解了命名空间是什么,已经如果让两个命名空间能够通信。
我们通过手动创建两个命名空间,然后创建一对VETH将两个命名空间连接起来,然后再分别赋予IP这样完成了命名空间之间的通信。
那直接创建的两个容器之间是为何能够直接通信的呢,为什么创建的容器内部可以连通外网呢?
让我们带着两个问题继续学习吧!!!!
Docker bridge详解
1 | [vagrant@docker-node1 ~]$ docker exec -it 2ac19f6c6c53 /bin/sh |
先介绍一个命令docker network ls:
1 | [vagrant@docker-node1 ~]$ docker network ls |
这个命令会将主机支持的网络类型列举出来。
我现在开着一个上节建的容器:
1 | [vagrant@docker-node1 ~]$ docker ps |
这个容器的网络是连到bridge上面的,通过docker network inspect NETWORKID查看
1 | [vagrant@docker-node1 ~]$ docker network inspect f3e37efd5e71 |
我们看到在Containers中包含我们创建的容器test1。
说明我们的容器链接到了bridge网络上,这个bridge到底是什么呢?
我们看下本地网络:
1 | [vagrant@docker-node1 ~]$ ip a |
我们看下最后两个接口,其中的docker0就是本机的网络命名空间。vethfff2d55@if11就是一个VETH的一个端口。
那我们新建的容器是如何链接到docker0上的呢?

其中的vethfff2d55@if11是链接到docker0,eth0@if12是链接到Docker的命名空间。
我们再新建一个容器test2:
1 | [vagrant@docker-node1 ~]$ docker network inspect f3e37efd5e71 |
新建容器之后我们看到容器test2也加入到了bridge中。

我们看下总得拓扑图:
我们先看第一个问题,不同容器如何通信的:
从图中我们看到不同的容器都会和本地的命名空间docker0关联起来,docker0起到了一个中间作用。
第二个问题,容器内部是如何与外网通信的:
我们通过一个网络地址转换NAT(iptables实现)将容器发送到docker0的数据通过地址转换发送到eth0进而发送到外网。
容器之间的link
我们之前创建两个容器,在容器内部可以相互ping通,前提是使用IP地址。我们可以使用link机制在创建第二个容器的时候link到第一个容器上,这样我们就可以在第二个容器中直接使用容器的名字而不是IP进行通信了。

相比之前创建容器的时候指定要链接的容器。
1 | [vagrant@docker-node1 ~]$ docker exec -it abdcec200555 /bin/sh |
从上面看出 我们在容器test2中可以直接使用容器test1的容器名进行通信,(相当于增加了一个DNS解析)那在容器test1中可以吗?

事实证明是不行,为什么会这样呢?
这是因为link是单向的,我们创建容器的test2的时候link到了test1,因此我们只能在test2里使用test1容器名通信。
link实际工作中不多
我们在创建容器的时候是可以指定网络类型的,如果没有指定则是默认的bridge。
1 | [vagrant@docker-node1 ~]$ docker network ls |
我们可以自己建个网络,然后创建容器的时候将网络指定为我们自己创建的。

现在新增一个容器,指定网络为我们自己创建的。

新的网络已经有了接口。
我们不仅可以在创建容器的时候指定网络,还可以再运行的时候更改网络。
1 | # 将容器 test2 的网络改为 my-bridge |
我们登上test3进行以下操作:

我们发现可以在test3中直接使用test2的容器名进行通信。这是因为当容器加入到我们自己创建的网络而不是默认的网络的时候,会自动建立好双向的link。
1 | [vagrant@docker-node1 ~]$ docker exec -it test2 ping test3 |
容器的端口映射
之所以需要端口映射是因为在容器中启动的某些服务如果不做端口映射我们在外网是无法访问使用的。

我们将docker的端口80映射到docker主机的80端口。在docker主机上进行访问。
因为我们是使用vagrant创建的虚拟机,在Vagrantfile中我们指定了当前容器的IP为192.168.205.10。
直接在本机mac上浏览器访问IP地址即可:

如果是云主机,直接访问云主机对应的公网IP即可。
容器网络的 host 和 none
这个小节我们看下host和none这两个网络。
关于host:
1 | [vagrant@docker-node1 ~]$ docker run -d --name test1 --network none busybox /bin/sh -c "while true; do sleep 3600; done" |

我们看到😀MacAddress等都是为空。
1 | [vagrant@docker-node1 ~]$ docker exec -it test1 /bin/sh |
容器内部的网络接口也只有本地回环。没有网络接口证明这容器test1是一个孤立的容器,只能通过exec进入。
关于host:

我们看到MacAddress等地址也是为空。

但是进入到容器内部之后看到的网络接口是外层docker主机的。
通过这种方式创建的容器有一个问题是会和docker主机竞争端口,因为离外层用的是同一套命名空间。
一个多容器的应用部署示栗
首先看下我们要部署的程序:
1 | from flask import Flask |
这个程序需要使用redis服务,我们将redis使用一个容器提供服务,flask应用使用一个容器进行部署。
首先我们创建一个redis容器

根据Dockerfile创建一个应用程序容器:
1 | [vagrant@docker-node1 labs]$ ls |

上面使用-e参数在运行容器的时候设定环境变量。
1 | curl 127.0.0.1:5000 |
在容器内访问我们的程序已经生效了。

我们将5000端口映射到docker主机,这样可以在docker主机进行访问部署在容器中的程序。
docker的多机器通信
我们这个小节学习下不同机器的容器是如何通信的

我们的实现方式是将容器发送的数据当成一个数据包放到外层的通信层中,因为10和11之间是可以相互通信的。

具体实现细节原理为VXLAN:https://cizixs.com/2017/09/25/vxlan-protocol-introduction/
原理大致了解下就好,重在知道怎么用!
docker overlay网络 和 etcd 实现多机容器通信
这个小节我们学习以overlay的模式实现多机通信。通过overlay的网络我们需要第三方的通信(分布式存储)。

为什么需要一个分布式的存储呢?
看上面的图,我们在多机容器通信中需要分配不同容器不同的IP,那么标识IP是否已经使用就是将IP存放到分布式存储中,每次分配IP查询一下是否占用。
分布式存储我们将使用etcd:https://coreos.com/etcd/
首先我们需要搭建一个etcd的cluster。
首先注备好两台主机
1 | ➜ chapter4 vagrant status |
下载安装集群工具包
1 | ## setup etcd cluster |
重启docker服务
在docker-node1上
1 | $ sudo service docker stop |
在docker-node2上
1 | $ sudo service docker stop |
创建overlay network
在docker-node1上创建一个demo的overlay network
1 | ubuntu@docker-node1:~$ sudo docker network ls |
我们会看到在node2上,这个demo的overlay network会被同步创建
1 | ubuntu@docker-node2:~$ sudo docker network ls |
通过查看etcd的key-value, 我们获取到,这个demo的network是通过etcd从node1同步到node2的
etcd是一个key-value的darabases。
我们看下etcd的目录结构:
1 | [vagrant@docker-node2 etcd-v3.0.12-linux-amd64]$ ./etcdctl ls /docker |
这样我们分别在两台主机上创建两个容器,这两个容器之间是可以直接通过容器内的IP相互ping通。
因为我的环境崩了,暂时不演示了! 上面只要再创建容器就好了!!
我们可以将上面部署的
flask-redis通过overlay网络进行部署。
我们再看一张图

这张图片里我们在本机又建了一个自己的网络docker_gwbridge然后将链接到overlay网络的容器也加到这个网络上。这样我们通过overlay网络传输数据,然后通过underlay网络层将数据传输到外面。
详情可以查看官方文档:https://github.com/docker/labs/blob/master/networking/concepts/06-overlay-networks.md