在实践中,经常会碰到需要多个服务组件容器共同协作的情况,这往往需要多个容器之间能够互相访问对方的服务。
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(网络功能虚拟化)的相关技术。