第二篇:docker容器之间互相通信之docker run --link

1、前言

最近用docker运行了一个elasticsearch容器和一个kibana容器,因为kibana需要访问elasticsearch容器,最开始是在启动kibana时指定了elasticsearch.url,但是由于每次重启elasticsearch容器时,ip会发生变化,所以,遇到了2个容器之间互相通信的问题,这个时候就用到了docker run --link选项。自己也花了一段时间泡官网研究了–link的用法,把自己对–link的理解分享下。注意!docker官方已不推荐使用docker run --link来链接2个容器互相通信,随后的版本中会删除–link,但了解其原理,对如何使2个容器之间互相通信还是有帮助的。

2、docker run --link的作用

docker run --link可以用来链接2个容器,使得源容器(被链接的容器,这里是elasticsearch容器)和接收容器(主动去链接的容器,这里是kibana容器)之间可以互相通信,并且接收容器可以获取源容器的一些数据,如源容器的环境变量。

–link的格式:
–link (name or id):alias
其中,name和id是源容器的name和id,alias是源容器在link下的别名。
当时我的源容器elasticsearch的启动脚本如下:

#!/bin/bash
#Writerriter by ***
#Description  use docker run start  appserver
#2019.12.11
set -e
########################################################################################
docker run -d --name elasticsearch --restart=always \
	-v /work/elasticsearch/config:/usr/share/elasticsearch/config \
	-v /work/elasticsearch/data:/usr/share/elasticsearch/data \
	-v /work/elasticsearch/plugins:/usr/share/elasticsearch/plugins \
	-p 9200:9200 -p 9300:9300 \
	-e "discovery.type=single-node" \
	elasticsearch:7.5.0

创建并启动名为elasticsearch的容器,启动之后容器id为263b2518accb。
接收容器kibana的启动脚本如下:

#!/bin/bash
#Writerriter by ***
#Description  use docker run start  appserver
#2019.12.11
set -e
#########################################################################################
docker run -d --name kibana --restart=always \
	-p 5601:5601 \
	-v /work/kibana/config:/usr/share/kibana/config \
	-v /work/kibana/data:/usr/share/kibana/data \
	--link elasticsearch:test \
	-e "elasticsearch.ssl.verify=false" \
	 kibana:7.5.0

创建并启动名为kibana的容器,并把该容器和名为elasticsearch的容器连接起来。其中:

–link elasticsearch:test

elasticsearch是作为源容器,test是源容器在link下的别名(alias),通俗易懂的讲,站在kibana容器的角度,elasticsearch和test都是263b2518accb容器的名字,并且作为容器的hostname,kibana用这2个名字中的哪一个都可以访问到elasticsearch容器并与之通信(docker通过DNS自动解析)。我们可以来看下:

docker exec -it kibana /bin/bash

在这里插入图片描述
可见,elasticsearch和test都指向172.17.0.2

3. --link下容器间的通信

按照上例的方法就可以成功的将elaticsearch和kibana容器链接起来,那这2个容器间是怎么通信传送数据的呢?另外,前言中提到的接收容器可以获取源容器的一些信息,比如环境变量,又是怎么一回事呢?
源容器和接收容器之间传递数据是通过以下2种方式:

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

3.1 设置环境变量

  1. 当使用–link时,docker会自动在接收容器内创建基于–link参数的环境变量:
    docker会在接收容器中设置名为(alias)_NAME的环境变量,该环境变量的值为:(alias)_NAME=/接收容器名/源容器alias。
    我们进入kibana容器,看下此环境变量:

    docker exec -it kibana /bin/bash
    bash-4.2$ env |grep -i test_name
    TEST_NAME=/kibana/test
    

    可见,确实有名为TEST_NAME=/kibana/test的环境变量存在。
    另外,docker还会在接收容器中创建关于源容器暴露的端口号的环境变量,这些环境变量有一个统一的前缀名称:

    (name)PORT(port)_(protocol)

    其中:

    (name)表示链接的源容器alias
    (port)是源容器暴露的端口号
    (protocol)是通信协议:TCP or UDP

    docker用上面定义的前缀定义3个环境变量:

    (name)PORT(port)(protocol)ADDR
    (name)PORT(port)
    (protocol)PORT
    (name)PORT(port)_(protocol)_PROTO

    注意,若源容器暴露了多个端口号,则每1个端口都有上面的一组环境变量(包含3个环境变量),即若源容器暴露了4个端口号,则会有4组12个环境变量。
    我们的源容器暴露了9200和9300两个端口,因此我们来查看一下:

    docker exec -it kibana /bin/bash
    bash-4.2$ env |grep -i TEST_PORT_9200_TCP
    TEST_PORT_9200_TCP_PROTO=tcp
    TEST_PORT_9200_TCP_ADDR=172.17.0.2
    TEST_PORT_9200_TCP_PORT=9200
    TEST_PORT_9200_TCP=tcp://172.17.0.2:9200
    bash-4.2$ env |grep -i TEST_PORT_9300_TCP
    TEST_PORT_9300_TCP_ADDR=172.17.0.2
    TEST_PORT_9300_TCP=tcp://172.17.0.2:9300
    TEST_PORT_9300_TCP_PORT=9300
    TEST_PORT_9300_TCP_PROTO=tcp
    

    可见,确实有6个以(name)PORT(port)_(protocol)为前缀的环境变量存在。
    另外,docker还在接收容器中创建1个名为(alias)_PORT的环境变量,值为源容器的URL:源容器暴露的端口号中最小的那个端口号。

    我们进入kiana容器,看下此环境变量:

    docker exec -it kibana /bin/bash
    bash-4.2$ env |grep -i TEST_Port=
    TEST_PORT=tcp://172.17.0.2:9200
    
  2. 接收容器还会获取源容器暴露的环境变量,这些变量包括:

  • 源容器Dockerfile中ENV标签设置的环境变量

  • 源容器用docker run命令创建,命令中包含的 -e或–env或–env-file设置的环境变量
    docker会在接收容器中创建一些环境变量,这些环境变量是的值是关于源容器本身的环境变量的值。这些环境变量的定义格式为:
    (alias)ENV(name)
    我们进入kibana容器进行查看:

    docker exec -it kibana /bin/bash
    bash-4.2$ env |grep -i test_env
    TEST_ENV_ELASTIC_CONTAINER=true
    TEST_ENV_discovery.type=single-node
    

    环境变量的注意事项
    注意,接收容器环境变量中存储的源容器的IP,不会自动更新,即,若源容器重启,则接收容器环境变量中存储的源容器的IP很可能就失效了。所以,docker官方建议使用/etc/hosts来解决上述的IP失效问题。

3.2 更新/etc/hosts文件

docker会将源容器的host更新到目标容器的/etc/hosts中:
我们再进入kibana容器,查看kibana容器中的/etc/hosts文件的内容:

docker exec -it kibana /bin/bash
bash-4.2$ cat /etc/hosts
127.0.0.1       localhost
::1     localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.2      test 263b2518accb elasticsearch
172.17.0.5      4d9b3eb74946

其中172.17.0.5是kibana容器的ip,并使用kibana容器的容器id作为host name。另外,源容器的ip和hostname也写进来了,172.17.0.2是elasticsearch容器的ip,test是源容器在link下的alias,后面是test容器的容器id。
如果重启了源容器,接收容器的/etc/hosts会自动更新源容器的新ip。

总结

在–link标签下,接收容器就是通过设置环境变量和更新/etc/hosts文件来获取源容器的信息,并与之建立通信和传递数据的。

在docker的后续版本中,会取消docker run中的–link选项,但了解其如何在2个容器之间建立通信的原理是非常有用的,因为这有助于理解如何用官方推荐的所有容器在同一个network下来通信的方法,以及用docker-compose来链接2个容器来通信的方法。

发布了47 篇原创文章 · 获赞 0 · 访问量 1190

猜你喜欢

转载自blog.csdn.net/weixin_43103748/article/details/103493116