了解Docker容器网络
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你都可以使用。
这个bridge
network 代表所有安装了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)
这个none
network 会将容器添加到一个 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
脱离容器。
这个host
network,将container添加到主机的network stack。你会发现这个container的网络配置与主机是一致的。
除了bridge
network,你可能不需要其他的默认network。虽然你可以列出并查看这些network,但是你不能删除它们。这些是Docker所需要的。然而你可以添加属于你的自定义network,当你不再需要这些network的时候你可以删除它们。在你了解更多关于创建属于你自己的network之前,默认的bridge
network还是值得你看看的。
详解brigde
network
这个默认的bridge
network存在于所有的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 会自动创建一个 Subnet
和Gateway
在这个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地址相互通信。在默认的bridge
network中Docker不支持自动的服务发现。如果你的container想要通过其他container的name在这个默认的bridge
network中通行,你必须通过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秒测试,测试这个在bridge
network上的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的端口暴露出来。如果你想使一部分桥接网络开放给外部网络这是很有用的。
一个bridge
network在单主机的相对较小的网络环境中是很有用的一种解决方案。然而当需要创建一个很庞大的网络环境的时候你需要一个overlay
network.
覆盖网络(overlay network)
Docker的overlay
network 驱动原生就支持一个多主机网络。这种支持是在libnetwork
的帮助下完成的,一个内建的基于VXLAN
的overlay
network驱动还有Docker的libkv
库。
这个overlay
network需要一个有效的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
存贮服务可能需要额外的端口。检查你的供应商文档然后打开所有需要的端口。