最新消息:比度技术-是关注云计算、大数据、分布式存储、高并发、高性能、人工智能等互联网技术的个人博客。

Docker网络Link的链接性(翻译)

云计算 bidu 721浏览

Link网络

使用端口映射进行通讯

有三种方式

  • $ docker run -d -P training/webapp python app.py-P:(大写P)该参数:是容器的任意端口号映射到宿主机的临时端口号范围内的一个随机端口号。
  • $ docker run -d -p 80:5000 training/webapp python app.py 指定容器80端口映射到宿主机5000端口这种方式一个局限就是指定的80端口只能运行一个容器。
  • 可以指定一个主机端口号范围映射到容器指定端口:$ docker run -d -p 8000-9000:5000 training/webapp python app.py

    这把容器5000端口映射到主机端口范围:8000-9000

下面是其他配置组合

  • 当然可以指定绑定的Ip地址: $ docker run -d -p 127.0.0.1:80:5000 training/webapp python app.py
  • 绑定到指定Ip的动态端口:$ docker run -d -p 127.0.0.1::5000 training/webapp python app.py
  • 绑定UDP:$ docker run -d -p 127.0.0.1:80:5000/udp training/webapp python app.py
  • -p 该参数可以多次配置使用: The -p flag can be used multiple times to configure multiple ports.

Docker linking 系统

该系统允许把多个容器连接在一起 ,他们之间可以通信。

  • 对容器命名对建立容器link来说很重要。$ docker run -d -P –name web training/webapp python app.py
  • 通过links容器间通信: 使用 –link 创建link :(1)创建一个新容器:$ docker run -d –name db training/postgres

    (2)创建一个web容器可前面的web容器链接起来:$ docker run -d -P –name web –link db:db training/webapp python app.py (–link :alias,alias 是该link的别名)

    也可以使用:–link : $ docker run -d -P –name web –link db training/webapp python app.py

    $ docker inspect -f “{{ .HostConfig.Links }}” web [/db:/web/db] 这就允许 web去访问db容器了,注意db容器并没有进行任何端口映射,docker内部是通过如下两种方式来实现信息访问的:

  • 注意:db容器是源,web容器是目标
  • Environment variables
  • Updating the /etc/hosts file.

环境变量:

当创建链接时,docker自动在目标(web)容器创建一些环境变量,包括:源容器Dockerfile 中的ENV 变量;源容器启动时,docker run 参数 -e, –env 和 –env-file 指定的变量

docker为目标容器设定了环境变量:aliasNAME 。例如:一个新容器link到db :–link db:webdb 。docker会在目标容器(web)中创建环境变量:WEBDBNAME=/web/webdb 。Docker还会为源容器(db)暴露的端口在目标容器(web)中创建一些环境变量:<name>_PORT_<port>_<protocol> ,协议: TCP or UDP,Docker 通过前缀(WEBDB 即alias别名)创建三个不同的环境变量:

WEBDBPORT5432TCPADDR=172.17.0.82.

WEBDBPORT5432TCPPORT=5432

WEBDBPORT5432TCPPROTO=tcp.

上面三个变量会为每个暴露的port创建

  • 另外:docker会创建名为:<alias>_PORT的环境变量,例如:WEBDB_PORT=tcp://172.17.0.82:5432
  • 这个端口号是指暴露的第一个端口号(这里第一个指的是数字最小的端口号)

最后Docker会把源容器中的环境变量暴漏到目标容器中,在目标容器创建环境变量:<alias>_ENV_<name> 这里 alias 指的是–link 参数处的alias别名,name 指的是在源容器中定义的环境变量。 一个例子:


  $ 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
  • 特别注意:不像/etc/hosts file 中的Ip信息一样,这些目标容器中的环境变量在源容器重启时不会被更新,他们只被目标容器的第一个进程使用。
更新/etc/hosts文件

除了设置环境变量外,docker会为目标容器(web)设置host(在/etc/hosts文件中)


$ docker run -t -i --rm --link db:webdb training/webapp /bin/bash
root@aed84ee21bde:/opt/webapp# cat /etc/hosts
172.17.0.7  aed84ee21bde(web容器id)
. . .
172.17.0.5  webdb(--link 的 alias 别名) 6e5cdeb2d300 db(db源容器名字) 这里的Ip 在源容器(db重启时)会自动更新

Docker 网络

创建自定义网络,docker0 bridge 有些选项可以设置


Option	Equivalent	Description
com.docker.network.bridge.name	-	bridge name to be used when creating the Linux bridge
com.docker.network.bridge.enable_ip_masquerade	--ip-masq	Enable IP masquerading
com.docker.network.bridge.enable_icc	--icc	Enable or Disable Inter Container Connectivity
com.docker.network.bridge.host_binding_ipv4	--ip	Default IP when binding container ports
com.docker.network.mtu	--mtu	Set the containers network MTU


For example, now let’s use -o or --opt options to specify an IP address binding when publishing ports:

$ docker network create -o "com.docker.network.bridge.host_binding_ipv4"="172.23.0.1" my-network
b1a086897963e6a2e7fc6868962e55e746bee8ad0c97b54a5831054b5f62672a
$ docker network inspect my-network
[
    {
        "Name": "my-network",
        "Id": "b1a086897963e6a2e7fc6868962e55e746bee8ad0c97b54a5831054b5f62672a",
        "Scope": "local",
        "Driver": "bridge",
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.23.0.0/16",
                    "Gateway": "172.23.0.1/16"
                }
            ]
        },
        "Containers": {},
        "Options": {
            "com.docker.network.bridge.host_binding_ipv4": "172.23.0.1"
        }
    }
]



  • 在创建网络时我们可以指定ip net subnet 等参数:对于overlay跨主机网络可以指定多个–subnet= 子网

$ docker network create -d overlay
  --subnet=192.168.0.0/16 --subnet=192.170.0.0/16
  --gateway=192.168.0.100 --gateway=192.170.0.100
  --ip-range=192.168.1.0/24
  --aux-address a=192.168.1.5 --aux-address b=192.168.1.6
  --aux-address a=192.170.1.5 --aux-address b=192.170.1.6
  my-multihost-network

注意子网不要跟其他网络重叠 否则会创建失败。

在运行容器时我们可以指定ip net 等参数(docker run and docker network connect 都可以指定–ip and –ip6)

docker run –net=isolated_nw –ip=172.25.3.3 -itd –name=container3 busybox 467a7863c3f0277ef8e661b38427737f28099b61fa55622d6c30fb288d88c551

可以动态的把容器加入一个网络:$ docker network connect isolated_nw container2 docker network connect 命令可以把一个容器(运行中或停止)加入到一个网络,但是 docker network inspect只能显示正在运行容器的信息

加入自定义网络: docker network 和 docker run -net的不同:

$ docker network connect isolatednw container2 $ docker run –net=isolatednw –ip=172.25.3.3 -itd –name=container3 busybox 467a7863c3f0277ef8e661b38427737f28099b61fa55622d6c30fb288d88c551

$ docker inspect --format='{{json .NetworkSettings.Networks}}'  container3
{
    "isolated_nw": {
        "IPAMConfig": {
            "IPv4Address": "172.25.3.3"
        },
        "NetworkID": "1196a4c5af43a21ae38ef34515b6af19236a3fc48122cf585e3f3054d509679b",
        "EndpointID": "dffc7ec2915af58cc827d995e6ebdc897342be0420123277103c40ae35579103",
        "Gateway": "172.25.0.1",
        "IPAddress": "172.25.3.3",
        "IPPrefixLen": 16,
        "IPv6Gateway": "",
        "GlobalIPv6Address": "",
        "GlobalIPv6PrefixLen": 0,
        "MacAddress": "02:42:ac:19:03:03"
    }
}
可见container3 通过 docker run  -net=isolated_nw   只加入到了自定义网络:isolated_nw 中

同样对于:container2 结果如下:
$ docker inspect --format='{{json .NetworkSettings.Networks}}'  container2 | python -m json.tool
{
    "bridge": {
        "NetworkID":"7ea29fc1412292a2d7bba362f9253545fecdfa8ce9a6e37dd10ba8bee7129812",
        "EndpointID": "0099f9efb5a3727f6a554f176b1e96fca34cae773da68b3b6a26d046c12cb365",
        "Gateway": "172.17.0.1",
        "GlobalIPv6Address": "",
        "GlobalIPv6PrefixLen": 0,
        "IPAMConfig": null,
        "IPAddress": "172.17.0.3",
        "IPPrefixLen": 16,
        "IPv6Gateway": "",
        "MacAddress": "02:42:ac:11:00:03"
    },
    "isolated_nw": {
        "NetworkID":"1196a4c5af43a21ae38ef34515b6af19236a3fc48122cf585e3f3054d509679b",
        "EndpointID": "11cedac1810e864d6b1589d92da12af66203879ab89f4ccd8c8fdaa9b1c48b1d",
        "Gateway": "172.25.0.1",
        "GlobalIPv6Address": "",
        "GlobalIPv6PrefixLen": 0,
        "IPAMConfig": null,
        "IPAddress": "172.25.0.2",
        "IPPrefixLen": 16,
        "IPv6Gateway": "",
        "MacAddress": "02:42:ac:19:00:02"
    }
}
可以看到container2属于两个网络,默认的加入到了默认网络:bridge 和自定义网络:isolated_nw

在自定义网络isolated_nw 中,Docker内嵌DNS为同一网络中的其他容器名字进行了解析。在container2 中可以通过名字ping container3:

/ # ping -w 4 container3
PING container3 (172.25.3.3): 56 data bytes
64 bytes from 172.25.3.3: seq=0 ttl=64 time=0.070 ms
64 bytes from 172.25.3.3: seq=1 ttl=64 time=0.080 ms
64 bytes from 172.25.3.3: seq=2 ttl=64 time=0.080 ms
64 bytes from 172.25.3.3: seq=3 ttl=64 time=0.097 ms

--- container3 ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 0.070/0.081/0.097 ms

在默认网络bridge 中Docker不支持同一网络中容器名字的自动发现:container2 和container1 都在默认网络 bridge 中,在container2通过名字ping container1 会失败:
/ # ping -w 4 container1
ping: bad address 'container1'

可以通过docker run --link 让container1和和container2 通过名字通讯


自定义网络中的link容器

在上面的例子中在同一自定义网络中的container2可以自动解析container3的名字,但在默认网络bridge 却不可以,这是为了保持与legacy link(传统链接)的向后兼容。legacy link(传统链接)为默认网络bridge提供了四种能力如下:

name resolution(名字解析)
name alias for the linked container using --link=CONTAINER-NAME:ALIAS(容器别名)
secured container connectivity (in isolation via --icc=false)(容器安全链接)
environment variable injection(环境变量注入)
  • 自定义网络比如:isolated_nw 提供了如下几种能力:
automatic name resolution using DNS(自动名字解析:docker 内嵌DNS)
automatic secured isolated environment for the containers in a network(在网络中自动安全隔离环境)
ability to dynamically attach and detach to multiple networks(支持动态加入多个网络)
supports the --link option to provide name alias for the linked container(支持 --link 为--link容器创建别名)
例如:$ docker run --net=isolated_nw -itd --name=container4 --link container5:c5 busybox
01b5df970834b77a9eadbaff39051f237957bd35c4c56f11193e0594cfd5117c

docker run --net=isolated_nw -itd --name=container5 --link container4:c4 busybox
72eccf2208336f31e9e33ba327734125af00d1e1d2657878e2ee8154fbb23c7a

通过:--link ,container4可以使用名字:c5和container5 通讯
  • 注意上面的container5还没有被创建,这是自定义网络中–link和默认网络 bridge 中 –link的不同之处之一。
  • legacy link(传统link)是静态的很难支持alias别名,也不支持容器重启(restart),相反自定义网络中–link是动态的支持源容器(container5)重启和ip变化。
  • 注意 容器可以在不同的网络中有不同的link别名(link alias)
  • 总之,自定义网络link比默认网络bridge中link提供更多能力,自定义网络link没有环境变量注入。虽然环境变量注入很有用,但是他是静态的,而且必须在容器启动时注入。默认网络的link 环境变量不能注入一个已经运行的容器,与docker network 动态加入技术是不兼容的。

Network-scoped alias(网络范围的别名)

  • Network-scoped alias(网络范围的别名) 可以让一个容器以一个别名,被指定网络范围内所有的容器发现。
  • 区别:link alias,link alias 是由目标容器(服务的消费者)定义的。Network-scoped alias(网络范围的别名) 是由源容器(服务提供者)定义,如下:

$ docker run –net=isolated_nw -itd –name=container6 –net-alias app busybox 8ebe6767c1e0361f27433090060b33200aac054a68476c3be87ef4005eb1df17

上面的Network-scoped alias是:app

  • 把container6 使用一个不同的Network-scoped alias(网络范围的别名) 加入到网络:local_alias 如下:
  • docker network connect –alias scoped-app local_alias container6
  • 现在container6 在isolatednw网络中的网络别名是app,在网络localalias中的网络别名是scoped-app, 这两个别名都只能被定义是加入的网络中的容器访问,其他网络的容器是不能使用不属于自己网络的容器别名的。
  • 另外,在同一网络的多个容器可以共享同一个Network-scoped alias(网络别名):

$ docker run –net=isolated_nw -itd –name=container7 –net-alias app busybox 3138c678c123b8799f4c7cc6a0cecc595acbdfa8bf81f621834103cd4f504554

这样网络中的名字解析只是解析到其中的一个容器,往往是第一个启动的容器,当第一个容器失效(宕掉或从网络中断开)时会尝试解析到下一个容器。例子:

$ docker attach container4
/ # ping -w 4 app
PING app (172.25.0.6): 56 data bytes
64 bytes from 172.25.0.6: seq=0 ttl=64 time=0.070 ms
64 bytes from 172.25.0.6: seq=1 ttl=64 time=0.080 ms
64 bytes from 172.25.0.6: seq=2 ttl=64 time=0.080 ms
64 bytes from 172.25.0.6: seq=3 ttl=64 time=0.097 ms

--- app ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 0.070/0.081/0.097 ms

$ docker stop container6

$ docker attach container4
/ # ping -w 4 app
PING app (172.25.0.7): 56 data bytes
64 bytes from 172.25.0.7: seq=0 ttl=64 time=0.095 ms
64 bytes from 172.25.0.7: seq=1 ttl=64 time=0.075 ms
64 bytes from 172.25.0.7: seq=2 ttl=64 time=0.072 ms
64 bytes from 172.25.0.7: seq=3 ttl=64 time=0.101 ms

--- app ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 0.072/0.085/0.101 ms

Disconnecting containers(从网络中断开容器)

$ docker network disconnect isolated_nw container2

docker inspect --format='{{json .NetworkSettings.Networks}}'  container2 | python -m json.tool
{
    "bridge": {
        "NetworkID":"7ea29fc1412292a2d7bba362f9253545fecdfa8ce9a6e37dd10ba8bee7129812",
        "EndpointID": "9e4575f7f61c0f9d69317b7a4b92eefc133347836dd83ef65deffa16b9985dc0",
        "Gateway": "172.17.0.1",
        "GlobalIPv6Address": "",
        "GlobalIPv6PrefixLen": 0,
        "IPAddress": "172.17.0.3",
        "IPPrefixLen": 16,
        "IPv6Gateway": "",
        "MacAddress": "02:42:ac:11:00:03"
    }
}


$ docker network inspect isolated_nw
[
    {
        "Name": "isolated_nw",
        "Id": "06a62f1c73c4e3107c0f555b7a5f163309827bfbbf999840166065a8f35455a8",
        "Scope": "local",
        "Driver": "bridge",
        "IPAM": {
            "Driver": "default",
            "Config": [
                {
                    "Subnet": "172.21.0.0/16",
                    "Gateway": "172.21.0.1/16"
                }
            ]
        },
        "Containers": {
            "467a7863c3f0277ef8e661b38427737f28099b61fa55622d6c30fb288d88c551": {
                "Name": "container3",
                "EndpointID": "dffc7ec2915af58cc827d995e6ebdc897342be0420123277103c40ae35579103",
                "MacAddress": "02:42:ac:19:03:03",
                "IPv4Address": "172.25.3.3/16",
                "IPv6Address": ""
            }
        },
        "Options": {}
    }
]
  • 存在这种情景,在多主机网络中 docker daemon 重启,docker daemon 不能清除陈旧的容器链接,导致同名的新容器启动失败:container already connected to network。 为了在容器中清除endpoit 使用docker network disconnect -f 一旦endpoid被清除:新容器就可以加入到网络
$ docker run -d --name redis_db --net multihost redis
ERROR: Cannot start container bc0b19c089978f7845633027aa3435624ca3d12dd4f4f764b61eac4c0610f32e: container already connected to network multihost

$ docker rm -f redis_db
$ docker network disconnect -f multihost redis_db

$ docker run -d --name redis_db --net multihost redis
7d986da974aeea5e9f7aca7e510bdb216d58682faa83a9040c2f2adc0544795a

移除网络:

$ docker network disconnect isolated_nw container3

$ docker network rm isolated_nw

 

转载请注明:比度技术-关注互联网技术的个人博客 » Docker网络Link的链接性(翻译)