Swarmdocker

了解Docker容器网络

2016-07-12  本文已影响1265人  zerolinke

Docker Engine -> User guide -> Network configuration -> Docker container networking

了解Docker容器网络

利用Docker的网络功能去构件一个web app会更安全。Docker的network可以为容器提供一个完全隔离的网络环境。能够掌控运行的app网络对你是非常重要的。Docker的容器网络可以给予你这个掌控网络的能力。

这一节关于Docker Engine原生提供的默认的网络行为。描述了默认创建的或是属于你自己的用户自定义的network类型,还有当创建一个network在单主机或是一个跨主机集群中需要的资源。

默认的网络

当你安装Docker后,它会自动创建三个network,你可以使用命令:docker network ls 列出它们:

$ docker network ls
NETWORK ID          NAME                DRIVER
7fca4eb8c647        bridge              bridge
9f904ee27bf5        none                null
cf03ee007fb4        host                host

从历史上看,这三个network是Docker实现的一部分。当你运行一个container时,你可以用--net 标志去指定这个container运行在哪一种network上。这三种network你都可以使用。

这个bridgenetwork 代表所有安装了Docker的主机的docker0 network。除非使用docker run --set=<NETWORK>选项指定一个其它的network,否则Docker daemon会默认使用这个network连接contrainer。你可以使用系统的ifconfig命令查看主机的network stack中的docker0:

$ ifconfig
docker0   Link encap:Ethernet  HWaddr 02:42:47:bc:3a:eb  
          inet addr:172.17.0.1  Bcast:0.0.0.0  Mask:255.255.0.0
          inet6 addr: fe80::42:47ff:febc:3aeb/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:9001  Metric:1
          RX packets:17 errors:0 dropped:0 overruns:0 frame:0
          TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:1100 (1.1 KB)  TX bytes:648 (648.0 B)

这个nonenetwork 会将容器添加到一个 container-specific 的 network stack。这个容器缺少一个network interface。如果你想连接这个容器并查看它的stack,你可以这样:

// use the commond "docker attach <container-name>" to attaching this container
$ docker attach nonenetcontainer

root@0cb243cd1293:/# 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
root@0cb243cd1293:/# ifconfig
lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

root@0cb243cd1293:/#

注意:你可以通过 CTRL-p CTRL-q 脱离容器。

这个hostnetwork,将container添加到主机的network stack。你会发现这个container的网络配置与主机是一致的。

除了bridgenetwork,你可能不需要其他的默认network。虽然你可以列出并查看这些network,但是你不能删除它们。这些是Docker所需要的。然而你可以添加属于你的自定义network,当你不再需要这些network的时候你可以删除它们。在你了解更多关于创建属于你自己的network之前,默认的bridgenetwork还是值得你看看的。

详解brigdenetwork

这个默认的bridgenetwork存在于所有的Docker主机。docker network inspect命令可以返回关于network的信息:

$ docker network inspect bridge
[
   {
       "Name": "bridge",
       "Id": "f7ab26d71dbd6f557852c7156ae0574bbf62c42f539b50c8ebde0f728a253b6f",
       "Scope": "local",
       "Driver": "bridge",
       "IPAM": {
           "Driver": "default",
           "Config": [
               {
                   "Subnet": "172.17.0.1/16",
                   "Gateway": "172.17.0.1"
               }
           ]
       },
       "Containers": {},
       "Options": {
           "com.docker.network.bridge.default_bridge": "true",
           "com.docker.network.bridge.enable_icc": "true",
           "com.docker.network.bridge.enable_ip_masquerade": "true",
           "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
           "com.docker.network.bridge.name": "docker0",
           "com.docker.network.driver.mtu": "9001"
       }
   }
]

Docker Engine 会自动创建一个 SubnetGateway在这个network。docker run命令自动添加一个新的container到这个network:

$ docker run -itd --name=container1 busybox
3386a527aa08b37ea9232cbcace2d2458d49f44bb05a6b775fba7ddd40d8f92c

$ docker run -itd --name=container2 busybox
94447ca479852d29aeddca75c28f7104df3c3196d7b6d83061879e339946805c

在启动两个新的container之后,查看一下bridge网络。这两个容器的id会出现在 Containers这个字段中:

$ docker network inspect bridge
{[
    {
        "Name": "bridge",
        "Id": "f7ab26d71dbd6f557852c7156ae0574bbf62c42f539b50c8ebde0f728a253b6f",
        "Scope": "local",
        "Driver": "bridge",
        "IPAM": {
            "Driver": "default",
            "Config": [
                {
                    "Subnet": "172.17.0.1/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Containers": {
            "3386a527aa08b37ea9232cbcace2d2458d49f44bb05a6b775fba7ddd40d8f92c": {
                "EndpointID": "647c12443e91faf0fd508b6edfe59c30b642abb60dfab890b4bdccee38750bc1",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            },
            "94447ca479852d29aeddca75c28f7104df3c3196d7b6d83061879e339946805c": {
                "EndpointID": "b047d090f446ac49747d3c37d63e4307be745876db7f0ceef7b311cbba615f48",
                "MacAddress": "02:42:ac:11:00:03",
                "IPv4Address": "172.17.0.3/16",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "9001"
        }
    }
]

上面是 docker network inspect命令根据给定的network回显的这个network已连接的容器和它的一些网络资源。在这个默认的network中的container可以利用IP地址相互通信。在默认的bridgenetwork中Docker不支持自动的服务发现。如果你的container想要通过其他container的name在这个默认的bridgenetwork中通行,你必须通过docker run --linke选项来实现。

你可以attach一个正在运行的container并查看它的网络配置:

$ docker attach container1

root@0cb243cd1293:/# ifconfig
ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:02  
          inet addr:172.17.0.2  Bcast:0.0.0.0  Mask:255.255.0.0
          inet6 addr: fe80::42:acff:fe11:2/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:9001  Metric:1
          RX packets:16 errors:0 dropped:0 overruns:0 frame:0
          TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:1296 (1.2 KiB)  TX bytes:648 (648.0 B)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

然后使用ping命令来做一个3秒测试,测试这个在bridgenetwork上的container的连通性。

root@0cb243cd1293:/# ping -w3 172.17.0.3
PING 172.17.0.3 (172.17.0.3): 56 data bytes
64 bytes from 172.17.0.3: seq=0 ttl=64 time=0.096 ms
64 bytes from 172.17.0.3: seq=1 ttl=64 time=0.080 ms
64 bytes from 172.17.0.3: seq=2 ttl=64 time=0.074 ms

--- 172.17.0.3 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.074/0.083/0.096 ms

最后,使用cat命令来检查container1的网络配置:

root@0cb243cd1293:/# cat /etc/hosts
172.17.0.2  3386a527aa08
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

使用CTRL-p CTRL-q脱离container1后,连接到container2并重复这三个命令。

$ docker attach container2

root@0cb243cd1293:/# ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:03  
          inet addr:172.17.0.3  Bcast:0.0.0.0  Mask:255.255.0.0
          inet6 addr: fe80::42:acff:fe11:3/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:9001  Metric:1
          RX packets:15 errors:0 dropped:0 overruns:0 frame:0
          TX packets:13 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:1166 (1.1 KiB)  TX bytes:1026 (1.0 KiB)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

root@0cb243cd1293:/# ping -w3 172.17.0.2
PING 172.17.0.2 (172.17.0.2): 56 data bytes
64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.067 ms
64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.075 ms
64 bytes from 172.17.0.2: seq=2 ttl=64 time=0.072 ms

--- 172.17.0.2 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.067/0.071/0.075 ms
/ # cat /etc/hosts
172.17.0.3  94447ca47985
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

这个默认的桥接网络docker0支持使用端口映射和通过docker run --link使两个在docker0中的container可以彼此通信。这些方式设置起来很麻烦并且容易出错。虽然你仍然可以这样使用,但是最好避免这样,更推荐你去定义你自己的桥接网路来替代它。

自定义的network

你可以创建属于你的自定义network来更好的隔离container。为了创建这些network,Docker提供了一些默认的network drivers。你可以创建一个新的bridge network或者overlay network。你也可以创建一个network plugin或是一个remote network

你可以创建多个网络。可以添加一个container到多个网络。container只能在这个网络中通行不能跨越这个网络。一个container可以附着到两个network中,并分别与这两个network中的container成员通信。

接下来的几节更加详细的描述每一个Docker内建的网络驱动。

桥接网络(bridge network)

很容易就可以创建一个自定义的bridge模式的network。这个network和docker0很像。这里又一些已添加的功能和一些已经不可用的旧功能。

$ docker network create --driver bridge isolated_nw
1196a4c5af43a21ae38ef34515b6af19236a3fc48122cf585e3f3054d509679b

$ docker network inspect isolated_nw
[
    {
        "Name": "isolated_nw",
        "Id": "1196a4c5af43a21ae38ef34515b6af19236a3fc48122cf585e3f3054d509679b",
        "Scope": "local",
        "Driver": "bridge",
        "IPAM": {
            "Driver": "default",
            "Config": [
                {
                    "Subnet": "172.21.0.0/16",
                    "Gateway": "172.21.0.1/16"
                }
            ]
        },
        "Containers": {},
        "Options": {}
    }
]

$ docker network ls
NETWORK ID          NAME                DRIVER
9f904ee27bf5        none                null
cf03ee007fb4        host                host
7fca4eb8c647        bridge              bridge
c5ee82f76de3        isolated_nw         bridge

创建这个network之后,你可以使用这个创建的network通过docker run --net=<NETWORK>选项启动一个container。

$ docker run --net=isolated_nw -itd --name=container3 busybox
8c1a0a5be480921d669a073393ade66a3fc49933f08bcc5515b37b8144f6d47c

$ docker network inspect isolated_nw
[
    {
        "Name": "isolated_nw",
        "Id": "1196a4c5af43a21ae38ef34515b6af19236a3fc48122cf585e3f3054d509679b",
        "Scope": "local",
        "Driver": "bridge",
        "IPAM": {
            "Driver": "default",
            "Config": [
                {}
            ]
        },
        "Containers": {
            "8c1a0a5be480921d669a073393ade66a3fc49933f08bcc5515b37b8144f6d47c": {
                "EndpointID": "93b2db4a9b9a997beb912d28bcfc117f7b0eb924ff91d48cfa251d473e6a9b08",
                "MacAddress": "02:42:ac:15:00:02",
                "IPv4Address": "172.21.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {}
    }
]

推入到这个network的container必须存在于同一个Docker主机。每一个network中的container可以立即与在这个network中的其它container通信。这个network将外部网络与其内部的container隔离开来。

用户自定义的桥接网络是不支持link的。你可以将这个network中开放的container的端口暴露出来。如果你想使一部分桥接网络开放给外部网络这是很有用的。

一个bridgenetwork在单主机的相对较小的网络环境中是很有用的一种解决方案。然而当需要创建一个很庞大的网络环境的时候你需要一个overlaynetwork.

覆盖网络(overlay network)

Docker的overlaynetwork 驱动原生就支持一个多主机网络。这种支持是在libnetwork的帮助下完成的,一个内建的基于VXLANoverlaynetwork驱动还有Docker的libkv库。

这个overlaynetwork需要一个有效的key-value存贮服务。当前,Docker的libkv支持Consul,Etcd和ZooKeeper(分布式存贮)。在创建这样一个网络之前你必须安装配置一个你选用的key-value存贮服务。你创建network的Docker主机必须能够与服务通信。


这个network中的主机必须运行Docker Engine实例。最简单的方式是为每个主机提供一个Docker Machine。


你应当在每个主机上打开下面的端口。

Protocol Port Description
udp 4789 Data plane(VXLAN)
tcp/udp 7946 Control plane

你的key-value存贮服务可能需要额外的端口。检查你的供应商文档然后打开所有需要的端口。

自定义的网络插件

Docker中嵌入DNS服务

Links

Related information

上一篇下一篇

猜你喜欢

热点阅读