Skip to content

10. 端口映射与容器互联

Docker 除了通过网络访问外, 还提供了两个很方便的功能来满足服务访问的基本需求:

  • 一个是允许映射容器内应用的服务端口到本地宿主主机;

  • 另一个是互联机制实现多个容器间通过容器名来快速访问。

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

1.1 从外部访问容器应用

在启动容器的时候,如果不指定对应参数,在容器外部是无法通过网络来访问容器内的网络应用和服务的。

要让外部访问这些应用时, 可以通过-P或-p参数来指定端口映射。 当使用-P(大写的)标记时, Docker 会随机映射一个 49000~49900 的端口到内部容器开放的网络端口。然后使用docker port CONTAINER查看端口。

$ docker run -P -itd --name test_mount changedcentos:latest /bin/bash

$ docker port test_mount

-p (小写的)则可以指定要映射的端口,并且,在一个指定端口上只可以绑定一个容器。支持的格式有 IP:HostPort:ContainerPort 或 IP::ContainerPort 或 HostPort:ContainerPort

1.2 映射到指定地址的指定端口

IP:HostPort:ContainerPort指定映射使用一个特定的地址:

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

1.3 映射到指定地址的随机端口

IP::ContainerPort绑定一个端口到容器的端口,本地主机自动分配一个端口:

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

1.4 映射所有接口地址

HostPort:ContainerPort将本地所有接口上的所有地址的特定端口映射到容器的端口,可以执行如下命令:

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

多次使用-p可以绑定多个端口:

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

Note

容器有自己的内部网络和IP地址,使用 docker [container] inspect+容器ID 可以获取容器的具体信息。

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

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

在执行docker [container] run的时候如果添加--rm标记,则容器在终止后会立刻删除。

2.1 容器互联

使用--link参数可以让容器之间安全地进行交互。

# 先创建新的数据库容器
# 没有使用端口映射,避免暴露数据库服务端口到外部网络
$ docker run -d --name mysqldb -e MYSQL_ROOT_PASSWORD=abcd1234 mysql

# 然后创建一个新的web容器,并将它连接到db容器
# --link 容器名:别名
$ docker run -d -P --name my_flask --link mysqldb:db jcdemo/flaskapp

# 可以看到现在web容器的名字多了一个值:my_flask/db
$ docker ps --no-trunc
CONTAINER ID                                                       IMAGE                                                                     COMMAND                                            CREATED             STATUS              PORTS                     NAMES
fb662a99332d4825e7bacfc914718b0d7097330efa10893232f1c7a16c0a5415   jcdemo/flaskapp                                                           "python /src/app.py"                               8 minutes ago       Up 8 minutes        0.0.0.0:32770->5000/tcp   my_flask
aae4ae2138f76f945a042157755d6f1fc4f30d1b884b98902270d9d6826a2e7f   mysql                                                                     "docker-entrypoint.sh mysqld"                      21 minutes ago      Up 21 minutes       3306/tcp, 33060/tcp       my_flask/db,mysqldb

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

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

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

$ docker run --rm -P --name my_registry2 --link mysqldb:db daocloud.io/registry env
DB_PORT_33060_TCP_ADDR=172.17.0.3
HOSTNAME=901607172aa7
DB_PORT=tcp://172.17.0.3:3306
DB_PORT_3306_TCP=tcp://172.17.0.3:3306
DB_PORT_33060_TCP_PORT=33060
DB_ENV_MYSQL_VERSION=8.0.16-2debian9
SHLVL=1
DB_PORT_33060_TCP_PROTO=tcp
HOME=/root
DB_NAME=/my_registry2/db
DB_PORT_33060_TCP=tcp://172.17.0.3:33060
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
DB_ENV_MYSQL_MAJOR=8.0
DB_PORT_3306_TCP_ADDR=172.17.0.3
DB_ENV_MYSQL_ROOT_PASSWORD=abcd1234
PWD=/
DB_ENV_GOSU_VERSION=1.7
DB_PORT_3306_TCP_PORT=3306
DB_PORT_3306_TCP_PROTO=tcp

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

除了环境变量, Docker 还添加 host信息到父容器的 /etc/hosts 的文件:

$ docker run --rm -P -it --name my_centos2 --link mysqldb:db changedcentos /bin/bash

# 其实也可以在这里执行env查看环境变量
[root@7881bcf7a164 /]# cat /etc/hosts
127.0.0.1       localhost
::1     localhost ip6-localhost ip6-loopback
······
172.17.0.3      db aae4ae2138f7 mysqldb
172.17.0.5      7881bcf7a164

# 还可以去ping容器
[root@7881bcf7a164 /]# 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.258 ms
64 bytes from db (172.17.0.3): icmp_seq=2 ttl=64 time=0.114 ms
64 bytes from db (172.17.0.3): icmp_seq=3 ttl=64 time=0.125 ms

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