在网络的上篇中我们了解了命名空间是什么,已经如果让两个命名空间能够通信。
我们通过手动创建两个命名空间,然后创建一对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