容器互联机制
容器的互联 (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 容器上。