旧容器链接

警告

--link标志是 Docker 的一个遗留功能。它最终可能会被删除。除非您绝对需要继续使用它,否则我们建议您使用用户定义的网络来促进两个容器之间的通信,而不是使用 --link.用户定义的网络不支持但您可以使用的一项功能--link是在容器之间共享环境变量。但是,您可以使用其他机制(例如卷)以更受控制的方式在容器之间共享环境变量。

有关使用 的一些替代方法,请参阅 用户定义的桥和默认桥之间的差异--link

本节中的信息解释了 Docker 默认bridge网络中的旧容器链接,该网络是在安装 Docker 时自动创建的。

在Docker 网络功能出现之前,您可以使用 Docker 链接功能来允许容器相互发现并将有关一个容器的信息安全地传输到另一个容器。引入 Docker 网络功能后,您仍然可以创建链接,但默认bridge网络和 用户定义网络之间的行为有所不同。

本节简要讨论通过网络端口进行连接,然后详细介绍默认bridge网络中的容器链接。

使用网络端口映射进行连接

假设您使用此命令来运行一个简单的 Python Flask 应用程序:

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

笔记

容器有内部网络和IP地址。 Docker 可以有多种网络配置。您可以在此处查看有关 Docker 网络的更多信息。

创建该容器时,该-P标志用于自动将其中的任何网络端口映射到Docker 主机上临时端口范围内的随机高端口。接下来,docker ps运行时,您会看到容器中的端口 5000 绑定到主机上的端口 49155。

$ docker ps nostalgic_morse

CONTAINER ID  IMAGE                   COMMAND       CREATED        STATUS        PORTS                    NAMES
bc533791f3f5  training/webapp:latest  python app.py 5 seconds ago  Up 2 seconds  0.0.0.0:49155->5000/tcp  nostalgic_morse

您还了解了如何使用该标志将容器的端口绑定到特定端口-p。这里主机的80端口映射到容器的5000端口:

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

您明白了为什么这不是一个好主意,因为它限制您只能在该特定端口上使用一个容器。

相反,您可以指定将容器端口绑定到的主机端口范围,该范围与默认临时端口范围不同:

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

这会将容器中的端口 5000 绑定到主机上 8000 到 9000 之间的随机可用端口。

您还可以通过其他几种方法来配置该-p标志。默认情况下,该-p标志将指定端口绑定到主机上的所有接口。但您也可以指定绑定到特定接口,例如仅绑定到localhost.

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

这会将容器内的端口 5000 绑定到 主机上的端口 80localhost或接口。127.0.0.1

或者,要将容器的端口 5000 绑定到动态端口,但仅在 上 localhost,您可以使用:

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

/udp您还可以通过添加尾随或 来绑定 UDP 和 SCTP(通常由 SIGTRAN、Diameter 和 S1AP/X2AP 等电信协议使用)端口/sctp。例如:

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

您还了解了有用的docker port快捷方式,它向我们显示了当前的端口绑定。这对于显示特定端口配置也很有用。例如,如果您已将容器端口绑定到 localhost主机上的端口,则docker port输出会反映这一点。

$ docker port nostalgic_morse 5000

127.0.0.1:49155

笔记

-p标志可以多次使用以配置多个端口。

与链接系统连接

笔记

本节介绍默认网络中的旧链接功能bridge。 有关用户定义网络中链路的更多信息,请参阅 用户定义网桥和默认网桥之间的差异。

网络端口映射并不是 Docker 容器相互连接的唯一方式。 Docker 还有一个链接系统,允许您将多个容器链接在一起并将连接信息从一个容器发送到另一个容器。当容器链接时,有关源容器的信息可以发送到接收容器。这允许接收者看到描述源容器的各个方面的选定数据。

命名的重要性

为了建立链接,Docker 依赖于容器的名称。您已经看到您创建的每个容器都有一个自动创建的名称;事实上,nostalgic_morse通过本指南您已经熟悉了我们的老朋友 。您还可以自己命名容器。此命名提供了两个有用的功能:

  1. 以更容易记住的方式命名执行特定功能的容器非常有用,例如命名包含 Web 应用程序的容器web

  2. 它为Docker提供了一个参考点,允许它引用其他容器,例如,您可以指定将容器链接web到container db

您可以使用标志来命名容器--name,例如:

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

这将启动一个新容器并使用该--name标志来命名该容器web。您可以使用该命令查看容器的名称 docker ps

$ docker ps -l

CONTAINER ID  IMAGE                  COMMAND        CREATED       STATUS       PORTS                    NAMES
aed84ee21bde  training/webapp:latest python app.py  12 hours ago  Up 2 seconds 0.0.0.0:49154->5000/tcp  web

您还可以使用docker inspect返回容器的名称。

笔记

容器名称必须是唯一的。这意味着你只能调用一个容器web。如果要重新使用容器名称,则必须先删除旧容器(使用docker container rm),然后才能创建同名的新容器。作为替代方案,您可以--rmdocker run命令中使用该标志。这会在容器停止后立即删除该容器。

链接允许容器发现彼此并将一个容器的信息安全地传输到另一个容器。设置链接时,您将在源容器和接收容器之间创建管道。然后,接收者可以访问有关源的选定数据。要创建链接,您可以使用该--link 标志。首先,创建一个新容器,这次包含一个数据库。

$ docker run -d --name db training/postgres

这将创建一个dbtraining/postgres 映像调用的新容器,其中包含 PostgreSQL 数据库。

现在,您需要删除web之前创建的容器,以便可以将其替换为链接的容器:

$ docker container rm -f web

现在,创建一个新容器并将其与您的容器web链接。db

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

这会将新web容器与db您之前创建的容器链接起来。标志--link采用以下形式:

--link <name or id>:alias

其中name是我们链接到的容器的名称,alias是链接名称的别名。该别名很快就会被使用。该--link标志也采用以下形式:

--link <name or id>

在这种情况下,别名与名称匹配。您可以将前面的示例写为:

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

接下来,使用以下命令检查链接的容器docker inspect

$ docker inspect -f "{{ .HostConfig.Links }}" web

[/db:/web/db]

您可以看到web容器现在已链接到db容器 web/db。这允许它访问有关db容器的信息。

那么链接容器实际上有什么作用呢?您已经了解到,链接允许源容器向接收容器提供有关其自身的信息。在我们的示例中,接收者web可以访问有关源 的信息db。为此,Docker 在容器之间创建了一条安全隧道,不需要在容器上向外部公开任何端口;当我们启动 db容器时,我们没有使用-P-p标志。这是链接的一大好处:我们不需要将源容器(此处为 PostgreSQL 数据库)暴露给网络。

Docker 通过两种方式向接收容器公开源容器的连接信息:

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

环境变量

当您链接容器时,Docker 会创建多个环境变量。 Docker根据--link参数自动在目标容器中创建环境变量。它还公开来自源容器的 Docker 的所有环境变量。其中包括以下变量:

  • ENV源容器的 Dockerfile 中的命令
  • 源容器启动时命令上的-e--env、 和选项--env-filedocker run

这些环境变量允许从目标容器内以编程方式发现与源容器相关的信息。

警告

重要的是要了解,容器内源自 Docker 的所有环境变量都可供链接到该容器的任何容器使用。如果敏感数据存储在其中,这可能会产生严重的安全隐患。

Docker<alias>_NAME为参数中列出的每个目标容器设置一个环境变量--link。例如,如果一个名为 via 的新容器 web链接到名为dbvia 的数据库容器--link db:webdb,则 DockerWEBDB_NAME=/web/webdb在该容器中创建一个变量web

Docker 还为源容器公开的每个端口定义了一组环境变量。每个变量在表单中都有一个唯一的前缀<name>_PORT_<port>_<protocol>

此前缀中的组件是:

  • <name>参数中指定的别名--link(例如,webdb
  • <port>暴露的数量
  • a<protocol>是 TCP 或 UDP

Docker 使用此前缀格式定义三个不同的环境变量:

  • prefix_ADDR变量包含 URL 中的 IP 地址,例如WEBDB_PORT_5432_TCP_ADDR=172.17.0.82
  • prefix_PORT例如,该变量仅包含 URL 中的端口号WEBDB_PORT_5432_TCP_PORT=5432
  • 例如,该prefix_PROTO变量仅包含 URL 中的协议WEBDB_PORT_5432_TCP_PROTO=tcp

如果容器公开多个端口,则为每个端口定义一组环境变量。这意味着,例如,如果容器公开 4 个端口,则 Docker 将创建 12 个环境变量,每个端口 3 个。

此外,Docker 创建一个名为 的环境变量<alias>_PORT。此变量包含源容器的第一个公开端口的 URL。 “第一个”端口定义为编号最小的公开端口。例如,考虑WEBDB_PORT=tcp://172.17.0.82:5432变量。如果该端口同时用于 tcp 和 udp,则指定 tcp 端口。

最后,Docker 还将源容器中的每个 Docker 发起的环境变量公开为目标中的环境变量。对于每个变量,Docker<alias>_ENV_<name>在目标容器中创建一个变量。该变量的值设置为 Docker 启动源容器时使用的值。

回到我们的数据库示例,您可以运行命令env 来列出指定容器的环境变量。

$ docker run --rm --name web2 --link db:db training/webapp env

<...>
DB_NAME=/web2/db
DB_PORT=tcp://172.17.0.5:5432
DB_PORT_5432_TCP=tcp://172.17.0.5:5432
DB_PORT_5432_TCP_PROTO=tcp
DB_PORT_5432_TCP_PORT=5432
DB_PORT_5432_TCP_ADDR=172.17.0.5
<...>

您可以看到 Docker 创建了一系列环境变量,其中包含有关源db容器的有用信息。每个变量都以 为前缀 DB_,它是根据alias您在上面指定的值填充的。如果aliasdb1,变量将以 为前缀DB1_。您可以使用这些环境变量来配置应用程序以连接到容器上的数据库db。连接安全且私密;只有链接的web容器才能与容器通信db

关于 Docker 环境变量的重要说明

/etc/hosts与文件中的主机条目不同 ,如果源容器重新启动,存储在环境变量中的 IP 地址不会自动更新。我们建议使用主机条目来 /etc/hosts解析链接容器的 IP 地址。

这些环境变量仅为容器中的第一个进程设置。某些守护进程(例如sshd)会在生成用于连接的 shell 时清除它们。

更新 /etc/hosts 文件

除了环境变量之外,Docker 还会向/etc/hosts文件中添加源容器的主机条目。这是容器的条目web

$ docker run -t -i --rm --link db:webdb training/webapp /bin/bash

root@aed84ee21bde:/opt/webapp# cat /etc/hosts
172.17.0.7  aed84ee21bde
<...>
172.17.0.5  webdb 6e5cdeb2d300 db

您可以看到两个相关的主机条目。第一个是web 使用容器 ID 作为主机名的容器条目。第二个条目使用链接别名来引用db容器的 IP 地址。除了您提供的别名之外,链接容器的名称(如果与提供给参数的别名唯一--link)以及链接容器的主机名也会添加到/etc/hosts链接容器的 IP 地址中。您可以通过以下任意条目 ping 该主机:

root@aed84ee21bde:/opt/webapp# apt-get install -yqq inetutils-ping
root@aed84ee21bde:/opt/webapp# ping webdb

PING webdb (172.17.0.5): 48 data bytes
56 bytes from 172.17.0.5: icmp_seq=0 ttl=64 time=0.267 ms
56 bytes from 172.17.0.5: icmp_seq=1 ttl=64 time=0.250 ms
56 bytes from 172.17.0.5: icmp_seq=2 ttl=64 time=0.256 ms

笔记

在示例中,您必须安装,ping因为它最初并未包含在容器中。

在这里,您使用ping命令通过其主机条目对容器执行 pingdb操作,该条目解析为172.17.0.5.您可以使用此主机条目来配置应用程序以使用您的db容器。

笔记

您可以将多个收件人容器链接到单个源。例如,您可以将多个(不同名称的)Web 容器附加到您的 db容器。

如果重新启动源容器,/etc/hosts链接容器上的文件将自动更新为源容器的新 IP 地址,从而允许链接通信继续。

$ docker restart db
db

$ docker run -t -i --rm --link db:db training/webapp /bin/bash

root@aed84ee21bde:/opt/webapp# cat /etc/hosts
172.17.0.7  aed84ee21bde
<...>
172.17.0.9  db