容器间的通信方式
一个分布式应用,多个容器之间往往需要通信,比如 HTTP 服务容器往往需要与数据库容器进行通信。容器的通信方式有以下几种:
- 通过
docker run起一个容器时带上--link参数指定该容器与其他容器进行相关联 (即将废弃,原理就不描述了) - 通过 Docker Network 系统来建立通信
- 通过
docker-compose容器编排工具,其本质也是通过 Docker Network 来通信的 - 更高级别的容器编排工具,如 Kubernetes 等
这次我们来讲解一下最基础的 Docker Network 系统。
Docker Network
网络驱动模式
Docker Network 有多种驱动模式,默认为 bridge,即桥接模式。bridge network 原理是在新建 network 时建立一个 bridge(即容器外的一个 Linux 网络接口,通过 ip a 命令可以查看),所有加入此 network 的容器会通过容器内部的网络接口与外部的 bridge 接口的 veth interface 相连,这样,network 内容器间需要彼此通信时就可以通过 bridge 进行转发。每一个 bridge network(包含其下的容器)都有一个独立的 IP 网段,不同网段间的容器无法通信,这也就是指定 bridge network 进行容器间网络隔离的原理。

我的 Linux 宿主机上的默认 bridge 的 docker0 网络接口

我的 Linux 宿主机上自建的 bridge 驱动模式的 network 的网络接口
默认 Network
$ docker network lsNETWORK ID NAME DRIVER SCOPE9c9d4fd4f950 bridge bridge local3ce82c0caf70 host host localf1a111712ad4 none null local
Docker 内置了一个默认 bridge network(名为 bridge,第一行),也就是上文中 docker0 接口所属的 network,所有未指定 network 的容器,默认连接到此 network 中,其网段为 172.17.0.1/16。所以,两个未进行任何连接操作的容器是可以通过 IP 地址互相通信的,因为他们同在一个 network 下,但通讯只能通过 IP 地址进行(比如 ping 172.17.0.5),不可以通过容器名通信(比如 ping container-name)。但自定义创建的网络可以通过容器名进行通信。

图中 docker0 即为默认 bridge 网络的网桥,它负责连通所有未指定 network 的容器,并且连通外网
None Network
网络模式为none的,即不为Docker Container创建任何的网络环境。一旦Docker Container采用了none网络模式,那么容器内部就只能使用loopback网络设备,不会再有其他的网络资源。
docker run -it --rm --network=none ubuntu:14.04 ifconfiglo Link encap:Local Loopbackinet addr:127.0.0.1 Mask:255.0.0.0UP LOOPBACK RUNNING MTU:65536 Metric:1RX packets:0 errors:0 dropped:0 overruns:0 frame:0TX packets:0 errors:0 dropped:0 overruns:0 carrier:0collisions:0 txqueuelen:0RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
Host Network
如果你在创建容器的时候使用--network=host选项,那么容器会使用宿主机的网络,容器与宿主机的网络并没有隔离。使用这种网络类型的好处就是网络性能很好,基本上跟宿主机的网络一样,它很大的弊端就是不安全。你可以在容器中更改宿主机的网络,如果你的程序是用root用户运行的,有可能会通过Docker容器来控制宿主机的网络。当我们在容器中执行类似ifconfig命令查看网络环境是,看到的都是宿主机上的信息。
docker run -it --network=host nginxcurl -i localhost
这里我们指定--network=host启动一个运行nginx的容器,然后在宿主机的命令行中请求localhost,在控制台中会输出nginx访问日志,其实这里并没有像以前那样通过-p或-P来暴露容器80端口。
自定义网络
$ docker network create NAME
- 不指定
-d参数,默认创建 bridge 驱动模式的 network。 - 自定义的 bridge network 会有自己专属的一个网段,与其他 network 隔离。
- 可以通过
docker network connect指令将容器连接到一个 network,也可以在起容器(docker run指令)时加入--network参数指定即将创建的容器加入到哪个 network,还可以通过docker network disconnect命令将容器移出自定义的 network。 - 加入到同一个自定义 bridge network 的容器间可以通过容器名进行通信,会自动进行 DNS 解析,但前提是需要给容器指定名称,随机分配的容器名无法被解析。也可以通过 IP 进行通信,因为属于同一个网段。
- 同一个容器可以同时加入到多个 network 下,此时该容器拥有多个网络接口,分别连接到不通的 bridge 上(可以通过
ip a查看)。
