又开一个新坑,Docker 系列打算记录一下个人学习 Docker,使用 Docker 应用于项目实践中的一些感悟,可能不会像之前的文章成一个体系,一方面自己对 Docker 的理解程度,不如像 Java 一样熟悉,二是 Docker 的官方文档和 Docker 相关的入门知识点还是挺多的。不过后续会尽量整理成一个系列。
Docker 强大的原因之一在于多个 Docker 容器之间的互相连接。涉及到连接,就引出了网络通信的几种模式。Docker 默认提供了 5 种网络驱动模式。
通过在 Docker 上安装和使用第三方网络插件可以算作额外的扩展方式。
1kiritodeMacBook-Pro:~ kirito$ docker network ls
2NETWORK ID NAME DRIVER SCOPE
315315759c263 bridge bridge local
4d72064d9febf host host local
583ea989d3fec none null local
这 3 个网络包含在 Docker 实现中。运行一个容器时,可以使用 --network 参数指定在哪种网络模式下运行该容器。
这篇文章重点介绍 bridge 模式。 所有 Docker 安装后都存在的 docker0 网络,这在 Docker 基础中有过介绍。除非使用 docker run --network=选项另行指定,否则 Docker 守护进程默认情况下会将容器连接到 docker0 这个网络。
使用如下命令就可以创建一个名称为 my-net ,网络驱动模式为 bridge 的自定义网络。
1$ docker network create my-net
再次查看存在的网络可以发现上述命令执行之后产生的变化:
1kiritodeMacBook-Pro:~ kirito$ docker network ls
2NETWORK ID NAME DRIVER SCOPE
315315759c263 bridge bridge local
4d72064d9febf host host local
573e32007f19f my-net bridge local
683ea989d3fec none null local
BusyBox 是一个集成了一百多个最常用 Linux 命令和工具(如 cat、echo、grep、mount、telnet 、ping、ifconfig 等)的精简工具箱,它只需要几 MB 的大小,很方便进行各种快速验证,被誉为“Linux 系统的瑞士军刀”。
我们使用 busybox 来测试容器间的网络情况。(一开始我尝试使用 ubuntu 作为基础镜像来构建测试容器,但 ubuntu 镜像删减了几乎所有的常用工具,连同 ping,ifconfig 等命令都需要额外安装软件,而 busybox 则不存在这些问题。)
1kiritodeMacBook-Pro:~ kirito$ docker run --name box1 -it --rm busybox sh
2/ # ifconfig
3eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:07
4 inet addr:172.17.0.7 Bcast:172.17.255.255 Mask:255.255.0.0
—rm 指令可以让我们在退出容器时自动销毁该容器,这样便于测试。查看自身的 ip 为 172.17.0.7,接下来创建第二个容器 box2。
1kiritodeMacBook-Pro:~ kirito$ docker run --name box2 -it --rm busybox sh
2/ # ifconfig
3eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:08
4 inet addr:172.17.0.8 Bcast:172.17.255.255 Mask:255.255.0.0
查看自身的 ip 为 172.17.0.8。
在 box2 中执行 ping 命令测试与 box1 的连通性:
1使用 IP
2/ # ping 172.17.0.8
3PING 172.17.0.8 (172.17.0.8): 56 data bytes
464 bytes from 172.17.0.8: seq=0 ttl=64 time=0.107 ms
564 bytes from 172.17.0.8: seq=1 ttl=64 time=0.116 ms
664 bytes from 172.17.0.8: seq=2 ttl=64 time=0.114 ms
764 bytes from 172.17.0.8: seq=3 ttl=64 time=0.126 ms
8
9使用容器名称
10/ # ping box1
11无响应
我们发现使用默认网桥 docker0 的桥接模式下,ip 是通的,但是无法使用容器名作为通信的 host。
1kiritodeMacBook-Pro:~ kirito$ docker run --name box3 -it --rm --network my-net busybox sh
2/ # ifconfig
3eth0 Link encap:Ethernet HWaddr 02:42:AC:15:00:02
4 inet addr:172.21.0.2 Bcast:172.21.255.255 Mask:255.255.0.0
使用 —network
指定使用的网络模式,my-net
便是在此之前我们通过 docker network create
命令新创建的网络。新启动一个 shell 创建 box4
1kiritodeMacBook-Pro:~ kirito$ docker run -it --name box4 --rm --network my-net busybox sh
2/ # ifconfig
3eth0 Link encap:Ethernet HWaddr 02:42:AC:15:00:03
4 inet addr:172.21.0.3 Bcast:172.21.255.255 Mask:255.255.0.0
在 box4 中执行 ping 命令测试与 box3 的连通性:
1使用 IP
2/ # ping 172.21.0.2
3PING 172.21.0.2 (172.21.0.2): 56 data bytes
464 bytes from 172.21.0.2: seq=0 ttl=64 time=0.203 ms
564 bytes from 172.21.0.2: seq=1 ttl=64 time=0.167 ms
664 bytes from 172.21.0.2: seq=2 ttl=64 time=0.169 ms
764 bytes from 172.21.0.2: seq=3 ttl=64 time=0.167 ms
8
9使用容器名称
10/ # ping box3
11PING box3 (172.21.0.2): 56 data bytes
1264 bytes from 172.21.0.2: seq=0 ttl=64 time=0.229 ms
1364 bytes from 172.21.0.2: seq=1 ttl=64 time=0.170 ms
1464 bytes from 172.21.0.2: seq=2 ttl=64 time=0.165 ms
1564 bytes from 172.21.0.2: seq=3 ttl=64 time=0.168 ms
与默认的网络 docker0 不同的是,指定了自定义 network 的容器可以使用容器名称相互通信,实际上这也是 docker 官方推荐使用 —network
参数运行容器的原因之一。
连接到同一个自定义 bridge 网络的容器会自动将所有端口相互暴露,并且无法连接到容器之外的网络。这使得容器化的应用能轻松地相互通信,并且与外部环境产生了良好的隔离性。
例如一个包含了 web 应用,数据库,redis 等组件的应用程序。很有可能只希望对外界暴露 80 端口,而不允许外界访问数据库端口和 redis 端口,而又不至于让 web 应用本身无法访问数据库和 redis, 便可以使用自定义 bridge 网络轻松实现。如果在默认 bridge 网络上运行相同的应用程序,则需要使用 -p 或 —publish 标志打开 web 端口,数据库端口,redis 端口。这意味着 Docker 宿主机需要通过其他方式阻止对数据库端口,redis 端口的访问,无意增大了工作量。
这一点在上一节的实验中已经验证过了。默认 bridge 网络上的容器只能通过 IP 地址互相访问,除非使用在 docker run 时添加 —link
参数。这么做个人认为有两点不好的地方:
一:容器关系只要稍微复杂一些,便会对管理产生不便。
二: —link
参数在官方文档中已经被标记为过期的参数,不被建议使用。
在用户定义的桥接网络上,容器可以通过容器名称(--name
指定的名称)或别名来解析对方。可能有人说,在默认 bridge 模式下我可以去修改 /etc/hosts
文件呀,但这显然不是合理的做法。
在容器的生命周期中,可以在运行中将其与自定义网络连接或断开连接。 而要从默认 bridge 网络中移除容器,则需要停止容器并使用不同的网络选项重新创建容器。
如果容器使用默认 bridge 网络,虽然可以对其进行配置,但所有容器都使用相同的默认设置,例如 MTU 和防火墙规则。另外,配置默认 bridge 网络隔离于 Docker 本身之外,并且需要重新启动 Docker 才可以生效。
自定义的 bridge 是使用 docker network create 创建和配置的。如果不同的应用程序组具有不同的网络要求,则可以在创建时分别配置每个用户定义的 bridge 网络,这无疑增加了灵活性和可控性。
在 Docker 的旧版本中,两个容器之间共享环境变量的唯一方法是使用 —link
标志来进行链接。这种类型的变量共享对于自定义的网络是不存在的。但是,自定义网络有更好方式来实现共享环境变量:
结合上述这些论述和官方文档的建议,使用 bridge 网络驱动模式时,最好添加使用 —network
来指定自定义的网络。
https://docs.docker.com/network/bridge/#connect-a-container-to-the-default-bridge-network
https://www.ibm.com/developerworks/cn/linux/l-docker-network/index.html