在实践中,经常会碰到需要多个服务组件容器共同协作的情况,这往往需要多个容器之间能够互相访问对方的服务。

docker除了通过网络访问外,还提供了2个很方便的功能来满足服务访问的基本需求:一个是允许映射容器内应用的服务端口到本地宿主机;另一个是互联机制实现多个容器间通过容器名来快速访问。

1.端口映射实现容器访问

1.1.从外部访问容器应用

在容器自动时,如果不指定参数,容器外部是不能访问容器的网络应用和服务的。可以通过加-P或-p参数来指定端口映射。

1.1.1.

-P:会随机映射一个49000-49900的端口到容器内部开放的网络端口

docker run -d -P training/webapp python app.py

docker ps -l

0.0.0.0:49155-->5000/tcp nostalgic_morse

  

或者docker logs来查看应用的信息:

docker logs -f nostalgic_morse
* runnung on http:/0.0.0.0:5000/

  

1.1.2.

-p:可以指定要映射的端口,并且,在一个指定端口上只可以绑定一个容器。

支持的格式有:

IP:HostPort:ContainerPort | IP::ContainerPort | HostPort:ContainerPort

  

  • 映射所有接口地址

把本地5000映射到容器5000端口

docker run -d -p 5000:5000 training/webapp python app.py

  

此时会默认绑定本地所有接口上的所有地址。多次使用-p标记可以绑定多个端口。

docker run -d -p 5000:5000 -p 3000:80 training/webapp python app.py

  

  • 1.1.2.2.映射到指定地址的指定端口

指定127.0.0.1的5000端口映射到容器的5000端口

docker run -d -p 127.0.0.1:5000:5000 training/webapp python app.py

  

  • 映射到指定地址的任意端口
docker run -d -p 127.0.0.1::5000 training/webapp python app.py

  

还可以使用udp标记来指定udp端口:

docker run -d -p 127.0.0.1:5000:5000/udp training/webapp python app.py

  

1.2.查看映射端口配置

docker ps -l 

0.0.0.0:49155-->5000/tcp nostalgic_morse

docker port nostalgic_morse 5000
127.0.0.1:49155.

  

提示:容器有自己的内部网络和ip地址,使用docker inspect +容器ID 可以获取容器的具体信息。

2.互联机制实现便捷互访

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

2.1.自定义容器命名

虽然当容器创建时容器会自动分配一个名字,但自定义命名容器有2个好处:

  • 比较好记,一目了然,比如创建一个web应用容器我们可以起名叫web
  • 当要连接其他容器时候(即便重启),也可以使用容器名而不用改变,比如连接web容器到db容器。

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

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

##验证设定的命名

docker ps -l

aed84ee21bde 0.0.0.0:49154-->5000/tcp web

##查看命名

docker inspect -f "{{ .Name }}" aed84ee21bde
/web

  

注意:容器的命名是唯一的,如果已经有了叫web的容器,当你再次使用web这个名字时,需要先用docker rm 删除之前的容器。

在执行docker run 的时候如果加上--rm参数,则容器在终止时会立刻删除。而且,--rm和-d不能同时使用。

2.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 tarining/webapp python app.py

  

此时,db和web建立互联关系。

--link参数的格式为--link name:alias,其中name是要链接的容器的名称,alias是别名。

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

2.3.docker通过2种方式为容器公开连接信息:

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

2.3.1.使用env来查看web的环境变量

dokcer run --rm -it --name web2 --link db:db training/webapp env

...

DB_NAME=/web2/db

DB_PORT=tcp://172.17.0.5:5432

...

  

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

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

docker run -it --rm --link db:db training/webapp /bin/bash

root@aed84ee21dbe:/opt/webapp# cat /etc/hosts

127.17.0.7 aed84ee21dbe

127.17.0.5 db

  

这里有2个host信息,第一个是web容器,web容器用自己的id做默认主机名,第二个是db容器的ip和主机名。

我可以在web中ping db容器来测试连通性:

root@aed84ee21dbe:/opt/webapp# ping db

  

用户可以连接多个子容器到父容器,,比如可以连接多个db到一个web上。

3.小结

毫无疑问,容器服务的访问是很关键的一个用途。本文通过案例讲解了容器服务访问的两大基本操作,包括基础的端口映射机制和容器互联机制。同时,docker目前可以成熟支持linux自带的网络服务和功能,这既可以利用现有的成熟的技术提供稳定支持,又可以实现快速的高性能转发。

在生产环境中,网络方面的需求更加复杂多变,包括跨主机甚至跨数据中心的通信,这时候往往需要引入额外的机制,例如SDN(软件定义网络)或NFV(网络功能虚拟化)的相关技术。