由于 Docker 提倡容器与应用共生的轻量级容器理念,所以容器中通常只包含一种应用程序,但我们知道,如今纷繁的系统服务,没有几个是可以通过单一的应用程序支撑的。拿最简单的 Web 应用为例,也至少需要业务应用、数据库应用、缓存应用等组成。也就是说,在 Docker 里我们需要通过多个容器来组成这样的系统。
而这些互联网时代的应用,其间的通讯方式主要以网络为主,所以打通容器间的网络,是使它们能够互相通讯的关键所在。
要让一个容器连接到另外一个容器,我们可以在容器通过 docker create 或 docker run 创建时通过 —link 选项进行配置。
例如,这里我们创建一个 MySQL 容器,将运行我们 Web 应用的容器连接到这个 MySQL 容器上,打通两个容器间的网络,实现它们之间的网络互通。

  1. sudo docker run -d --name mysql -e MYSQL_RANDOM_ROOT_PASSWORD=yes mysql
  2. sudo docker run -d --name webapp --link mysql webapp:latest

容器间的网络已经打通,那么我们要如何在 Web 应用中连接到 MySQL 数据库呢?Docker 为容器间连接提供了一种非常友好的方式,我们只需要将容器的网络命名填入到连接地址中,就可以访问需要连接的容器了。
假设我们在 Web 应用中使用的是 JDBC 进行数据库连接的,我们可以这么填写连接。

  1. String url = "jdbc:mysql://mysql:3306/webapp";

在这里,连接地址中的 mysql 就好似我们常见的域名解析,Docker 会将其指向 MySQL 容器的 IP 地址。
看到这里,读者们有没有发现 Docker 在容器互通中为我们带来的一项便利,也就是我们不再需要真实的知道另外一个容器的 IP 地址就能进行连接。再具体来对比,在以往的开发中,我们每切换一个环境 ( 例如将程序从开发环境提交到测试环境 ),都需要重新配置程序中的各项连接地址等参数,而在 Docker 里,我们并不需要关心这个,只需要程序中配置被连接容器的别名,映射 IP 的工作就交给 Docker 完成了。

暴露端口

需要注意的是,虽然容器间的网络打通了,但并不意味着我们可以任意访问被连接容器中的任何服务。Docker 为容器网络增加了一套安全机制,只有容器自身允许的端口,才能被其他容器所访问。
这个容器自我标记端口可被访问的过程,我们通常称为暴露端口。我们在 docker ps 的结果中可以看到容器暴露给其他容器访问的端口。

  1. sudo docker ps
  2. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  3. 95507bc88082 mysql:5.7 "docker-entrypoint.s…" 17 seconds ago Up 16 seconds 3306/tcp, 33060/tcp mysql

这里我们看到,MySQL 这个容器暴露的端口是 3306 和 33060。所以我们连接到 MySQL 容器后,只能对这两个端口进行访问。
端口的暴露可以通过 Docker 镜像进行定义,也可以在容器创建时进行定义。在容器创建时进行定义的方法是借助 —expose 这个选项。

  1. sudo docker run -d --name mysql -e MYSQL_RANDOM_ROOT_PASSWORD=yes --expose 13306 --expose 23306 mysql:5.7

这里我们为 MySQL 暴露了 13306 和 23306 这两个端口,暴露后我们可以在 docker ps 中看到这两个端口已经成功的打开。

  1. sudo docker ps
  2. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  3. 3c4e645f21d7 mysql:5.7 "docker-entrypoint.s…" 4 seconds ago Up 3 seconds 3306/tcp, 13306/tcp, 23306/tcp, 33060/tcp mysql

容器暴露了端口只是类似我们打开了容器的防火墙,具体能不能通过这个端口访问容器中的服务,还需要容器中的应用监听并处理来自这个端口的请求。

通过别名连接

纯粹的通过容器名来打开容器间的网络通道缺乏一定的灵活性,在 Docker 里还支持连接时使用别名来使我们摆脱容器名的限制。

  1. sudo docker run -d --name webapp --link mysql:database webapp:latest

在这里,我们使用 —link : 的形式,连接到 MySQL 容器,并设置它的别名为 database。当我们要在 Web 应用中使用 MySQL 连接时,我们就可以使用 database 来代替连接地址了。

  1. String url = "jdbc:mysql://database:3306/webapp";