在Docker使用章节,你看到如何通过network port 连接运行在Docker container中的服务。但是端口连接只是一种与运行在Docker container中的服务或者应用互动的方式。在本节 ,我们将简单的回复建立network port连接的方式,然后介绍另外一种访问方式:container linking。

Network port映射回顾

         在Docker使用章节,我们创建了一个container来运行Python Flask应用。

$ sudo docker run -d -P training/webapp python app.py
         注意:containers有内部网络和IP地址(使用docker inspect命令看到container的IP地址)。Docker有不同的网络配置。我们可以在 这里查看网络配置。

        当容器被创建,-P用于自动将网络端口映射到主机在49153到65535之间的任意端口。接下来,运行docker ps

$ sudo 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
          你也可以显示的指定container端口绑定的主机端口,使用-p标签。

$ sudo docker run -d -p 5000:5000 training/webapp python app.py
         我们看到这不是一个好主意,因为这约束我们只能一个容器能够指定到这个特定端口上。

         有一些其他的方法使用-p标签来配置。默认,-p标签将绑定特定的端口到所有的在主机上的接口。但是我们也可以指定绑定特定的接口,例如只到localhost。

$ sudo docker run -d -p 127.0.0.1:5000:5000 training/webapp python app.py
         这将绑定container的内部5000端口到在主机上接口为localhost或者127.0.0.1的接口上的5000端口。

         或者,动态绑定容器的5000端口到localhost上,可以这样做:

$ sudo docker run -d -p 127.0.0.1:5000:5000/udp training/webapp python app.py
          我们可以使用docker port快捷方式查询当前绑定的端口。

          这是一个有用的方法来显示指定端口的配置。例如,如果你已经绑定容器的端口到主机上的localhost。那么docker port将输出这个结果。

$ sudo docker port nostalgic_morse 5000
127.0.0.1:49155
          注意:-p标签可以使用多次来配置多个端口。

Docker Container Linking

         网络端口的映射不是唯一的方法使一个container访问另外一个container。Docker也具有一个linking system,我们可以将多个container连接在一起,相互之间发送连接信息。当container被连接,关于来源container的信息将被发送给接收container。这将是接收信息放能够看到来源container的信息。

Container naming

         为了建立连接,Docker依赖Container的名字。你已经看到了每一个容器都有一个自动创建的名字。你也可以自己命名这个Container名字。这个命令提供了两种功能:

  1.          用名字表示这个Container特定功能的一种方法,使你更容易的记住它们。例如,命名包含一个wen应用的Container为web。
  2.          提供了Docker一个参考点,让其他容器容易索引到它,例如,你可以指定web容器连接到db容器。

         可以使用--name标签命名容器,例如:

$ sudo docker run -d -P --name web training/webapp python app.py
          启动了Container,命名为--name这个容器为web。你可以使用docker ps命令查看这个容器的名字。

$ sudo 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 来返回Container的名字。

$ sudo docker inspect -f "{{ .Name }}" aed84ee21bde
/web
           注意:Container名字必须是独一无二的。那么只能命名一个Container为web。如果你想要重新使用一个容器名字,必须删除原来的Container(用docker rm),然后才能创建同名的新Container。作为一种替代方案,在docker run命令中使用--rm标签,这将在Container停止后立即删除。

Container Linking

       连接让Container发现彼此,安全的传输信息。当我们建立连接,可以在来源Container和接收Container之间建立导管。这个接收方可以访问选择的关于来源方的数据。为了创建 连接,使用--link标签。首先,创建一个容器,这次一个包含数据库。

$ sudo docker run -d --name db training/postgres
        创建了一个新的Container叫做db,来自training/postgres image,它包含PostgreSQL 数据库。

       现在,你需要删除web Container,这样才可一个创建一个linked Container来代替:

$ sudo docker rm -f web
        现在创建一个web Container,与db Container连接起来。

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

         这将连接新的web Container到之前创建的db Container。这个--link标签的形成:

--link <name or id>:alias
         name是想要连接Container的名字,alias是link的名字的别名。

         你将看到别名为什么是名字缩小。

         下一步,检查被连接的Container,使用docker inspect:

$ sudo docker inspect -f "{{ .HostConfig.Links }}" web
[/db:/web/db]
          你可以看到web Container已经已经与db Container建立连接 web/db。这个允许web Container访问dbContainer的信息。

          那么两个连接的Container做了什么呢?连接时来源Container提供信息给接收Container。在我们的例子中,接收方web,可以访问关于来源方db的信息。为了实现这个,docker创建在容器之间创建一个安全通道,不需要向外界暴露任何端口。在我们启动db Container时,没有使用任何-P或者-p标签。这就是连接的益处:我不需要去网络中暴露我们来源Container,这里PostgreSQL数据库。

        Docker暴露来源容器的连接信息给接收容器,有两种方法:

  •         环境变量
  •         更新/etc/hosts文件
         环境变量
         当两个容器被连接,Docker需要在目标容器中设置一些环境 变量,使程序化的发现来源容器的信息。
         首先,Docker将设置<alias>_NAME环境变量指定每个目标容器的别名,将在--link 参数中使用。那么,例如如果一个新的容器叫做web,与数据库容器db建立了连接,通过db:webdb,然后在web容器中将WEBDB_NAME=/web/webdb。
         Docker也可以定义为每个源容器暴露的端口,定义一系列的环境变量。样式如下:
  •          <name>_PORT_<port>_<protocol>将包含一个URL索引到这个端口。<name>是在--link参数指定的 别名,(例如webdb),<port>是被暴露的端口号,<protocol>是TCP或者UDP。URL的格式如下:<protocol>://<container_ip_address>:<port>(例如tcp://172.17.0.82:8080)。这个URL为了便于使用被分为3个环境变量:

  •          <name>_PORT_<port>_<portocol>_ADDR包含URL的IP地址(例如WEBDB_PORT_8080_TCP_ADDR=172.17.0.82)。
  •          <name>_PORT_<port>_<portocol>_PORT包含URL端口号(例如WEBDB_PORT_8080_TCP_PORT=8080)。
  •         <name>_PORT_<port>_<portocol>_PRPTO包含URL协议(例如WEBDB_PORT_8080_TCP_PROTO=tcp)。

        如果多个端口被暴露,则以上的环境变量设置将为每个端口设置。

        最后,被称为<alias>_PORT的环境变量将包含第一个源容器暴露的URL。例如WEBD_PORT=tcp://172.17.0.82:8080。在这个例子中,‘first’被定义为被暴露的最小端口编号。如果端口被用于tcp和udp,那么tcp端口被指定。

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

    $ sudo 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
    . . .
        注意:这些环境变量只是配置给Container的第一个进程。 Similarly, some daemons (such as  sshd ) will scrub them when spawning shells for connection.

        注意:不像在/etc/hosts文件中的host条目,IP地址储存在环境变量中,不能自动的更新如果源Container重启了。所以建议使用在/etc/hosts/中的host条目来解决被连接的容器之间的IP问题。

        你可以看到创建有用信息的环境变量关于db容器。每一个环境变量带前缀DB_,这来源于指定的别名。如果alias是db1,那么变量将以DB1_为前缀。你可以使用这些环境变量来配置的应用来连接到在db容器上的数据库。这个连接是安全的和私有的。只有被连接web容器能够与db容器通信。


更新/etc/hosts文件

        除了环境变量,Docker可以在源容器的,/etc/hosts文件上添加host entity。这是web容器的目录:

$ sudo 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.5  db
        你可以看到两个相关的host目录。第一个目录是web容器将Container ID作为主机名字。第二个目录使用连接别名,索引到db容器的IP地址。你可以通过ping这个主机名。

root@aed84ee21bde:/opt/webapp# apt-get install -yqq inetutils-ping
root@aed84ee21bde:/opt/webapp# ping db
PING db (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命令来ping db容器,使用它的host目录,解析为172.17.0.5。你可以使用这个host条目配置应用,从而使用db容器。

        注意:你可以连接多个接收容器到单个来源。例如你可以有多个不同名字的web容器连接到db容器上。

        如果你重启了源容器,被连接的容器/etc/hosts文件将被自动更新为新源容器的IP地址,来继续保持通讯。

$ sudo docker restart db
db
$ sudo 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

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐