容器互联机制

容器的互联 (linking) 是一种让多个容器中应用进行快速交互的方式。它会在源和接收容器之间创建连接关系,接收容器可以通过容器名快速访问到源容器,而不用指定具体的 IP 地址。

1. 自定义容器命名

连接系统依据容器的名称来执行。虽然当创建容器的时候,系统默认会分配一个名字,但自定义容器名字有两个好处:

  • 自定义的命名比较好记
  • 当要连接其他容器时,即便重启,也可以使用容器名而不用改变

使用 --name 标记可以为容器自定义命名:

wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$ docker run -d -P --name web training/webapp python app.py
57043fa975a05bf03bb9f590a57432dfb06977c70f9ea6b15ede665537b199bd
wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                      PORTS                     NAMES
57043fa975a0        training/webapp     "python app.py"     5 seconds ago       Up 3 seconds                0.0.0.0:32769->5000/tcp   web
4233fd67e97c        training/webapp     "python app.py"     22 hours ago        Up 22 hours                 0.0.0.0:32768->5000/tcp   reverent_blackburn
wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$

也可以使用 docker inspect 来查看容器的名字:

wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$ docker inspect -f "{{ .Name }}" 57
/web
wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$

容器的名称是唯一的。如果已经命名了一个叫 web 的容器,当你要再次使用 web 这个名称的时候,需要先用 docker rm 来删除之前创建的同名容器。在执行 docker run 的时候如果添加 --rm 标记,则容器在终止后会立刻删除。注意,–rm 和 -d 参数不能同时使用。

2. 容器互联

使用 --link 参数可以让容器之间安全地进行交互。下面先创建一个新的数据库容器:

docker run -d --name db training/postgres

删除之前创建的web容器:

docker rm -f web

然后创建一个新的 web 容器,并将它连接到 db 容器:

docker run -d -P --name web --link db:db training/webapp python app.py

此时,db 容器和 web 容器建立互联关系:

  • –link参数的格式为 --link name:alias,其中name是要连接的容器名称,alias是这个连接的别名。

使用docker ps来查看容器的连接,如下所示:

wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                     NAMES
ed5b3fdd48f0        training/webapp     "python app.py"          8 seconds ago       Up 7 seconds        0.0.0.0:32770->5000/tcp   web
bcfcc084bd07        training/postgres   "su postgres -c '/us…"   18 seconds ago      Up 18 seconds       5432/tcp                  db
4233fd67e97c        training/webapp     "python app.py"          22 hours ago        Up 22 hours         0.0.0.0:32768->5000/tcp   reverent_blackburn
wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$

Docker 相当于在两个互联的容器之间创建了一个虚机通道,而且不用映射它们的端口到宿主主机上。在启动 db 容器的时候并没有使用 -p 和 -P 标记,从而避免了暴露数据库服务端口到外部网络上。

Docker 通过两种方式为容器公开连接信息:

  • 更新环境变量;
  • 更新/etc/hosts文件;

使用 env 命令来查看 web 容器的环境变量:

wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$ docker run --rm --name web2 --link db:db training/webapp env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=0c192de8f674
DB_PORT=tcp://172.17.0.3:5432
DB_PORT_5432_TCP=tcp://172.17.0.3:5432
DB_PORT_5432_TCP_ADDR=172.17.0.3
DB_PORT_5432_TCP_PORT=5432
DB_PORT_5432_TCP_PROTO=tcp
DB_NAME=/web2/db
DB_ENV_PG_VERSION=9.3
HOME=/root
wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$

其中 DB_ 开头的环境变量是供 web 容器连接 db 容器使用的,前缀采用大写的连接别名。

除了环境变量之外,Docker 还添加 host 信息到父容器的 /etc/hosts 文件。下面是父容器web的hosts文件:

wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$ docker run -t -i --rm --link db:db training/webapp /bin/bash 
root@00c0b5ac4599:/opt/webapp# cat /etc/hosts 
127.0.0.1	localhost
::1	localhost ip6-localhost ip6-loopback
fe00::0	ip6-localnet
ff00::0	ip6-mcastprefix
ff02::1	ip6-allnodes
ff02::2	ip6-allrouters
172.17.0.3	db bcfcc084bd07
172.17.0.5	00c0b5ac4599
root@00c0b5ac4599:/opt/webapp# exit
exit
wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$

这里有两个 hosts 信息,第一个是 web 容器,web 容器用自己的 id 作为默认主机名,第二个是 db 容器的 IP 和主机名。可以在 web 容器中安装 ping 命令来测试与 db 容器的连通:

wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$ docker exec -it web /bin/bash
root@ed5b3fdd48f0:/opt/webapp# cat /etc/hosts 
127.0.0.1	localhost
::1	localhost ip6-localhost ip6-loopback
fe00::0	ip6-localnet
ff00::0	ip6-mcastprefix
ff02::1	ip6-allnodes
ff02::2	ip6-allrouters
172.17.0.3	db bcfcc084bd07
172.17.0.4	ed5b3fdd48f0
root@ed5b3fdd48f0:/opt/webapp# ping db
PING db (172.17.0.3) 56(84) bytes of data.
64 bytes from db (172.17.0.3): icmp_seq=1 ttl=64 time=0.111 ms
64 bytes from db (172.17.0.3): icmp_seq=2 ttl=64 time=0.075 ms
64 bytes from db (172.17.0.3): icmp_seq=3 ttl=64 time=0.093 ms
64 bytes from db (172.17.0.3): icmp_seq=4 ttl=64 time=0.093 ms
^C
--- db ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 2998ms
rtt min/avg/max/mdev = 0.075/0.093/0.111/0.012 ms
root@ed5b3fdd48f0:/opt/webapp# exit
exit
wohu@iZm5egn5zptnov4j3oxh4fZ:~/docker$

用 ping 来测试 db 容器,它会解析成 172.17.0.3。用户可以连接多个子容器到父容器,比如可以连接多个 web 到同一个 db 容器上。