主要内容
容器网络简介
容器之所以强大,是因为它的隔离性和连通性。隔离性是指每个容器是一个互相封闭的运行空间;而连通性指的是:当容器之间需要互相联系,可以通过Docker提供的网络模块进行通讯。Docker默认提供了3种内置网络模型和3种用户自定义网络模型。
三种内置网络模型分别是:
- bridge: docker默认的网络驱动。当没有指定,所有的容器都挂在默认的bridge设备上。
- host: 容器直接使用宿主机的网络环境,包括域名也是宿主机的
- none: docker不适用任何网络,这种容器只有lo(本地回环)设备
可以使用docker network ls
命令查看
1 2 3 4 5 6 |
[root@dellcentos7 ~]# docker network ls NETWORK ID NAME DRIVER SCOPE 8af7da60026e bridge bridge local dbe591d292f5 host host local 51c12e8ab320 none null local |
三种自定义网络模型分别是:
- bridge: 类似默认的桥接网络,但功能更加强大
- overlay: 使不同主机上的容器可以互相通讯
- macvlan: 为容器添加一个mac地址,使它看起来像是本地上的一个物理设备
默认bridge网络和自定义bridge网络的区别
- 自定义bridge提供了更好的隔离性和更强大的协同性
处于同一自定义bridge网络的所有容器,容器间的所有端口互相开放,可自由访问,但对外界来说,这些端口是不可见的。这使得容器间的通讯更加简单,也更加安全。
对于默认的bridge来说,被访问的特定端口必须通过-p(–publish)参数向外暴漏,否则容器不能访问这些端口。从安全性考虑,我们必须手动block掉其他不需要访问这些端口的容器,例如通过iptables。
-
自定义bridge提供了DNS解析功能
一般来说,我们访问其他容器的时候都是使用IP地址的,但自定义bridge网络提供了DNS解析功能,也就是说,我们可以使用域名进行容器间的通讯。容器域名由
docker run
命令的--name
参数指定。默认的bridge网络只能使用IP地址通讯,要使用域名,必须先通过旧式的
--link
(已废弃,未来可能移除)参数进行容器间的链接 -
容器可以在运行时动态地断开或连接到用户自定义bridge网络
要把容器从默认的bridge网络中断开,必须先让容器停止运行
使用bridge网络
上面已经介绍了两种bridge网络的区别,现在我们来实际操作它们。
默认bridge网络
一旦主机安装好docker,docker就会创建一个名为docker0
的bridge设备,如果没有指定,默认所有容器都会挂在这个设备下面。可以通过brctl
检查主机上的所有bridge设备,brctl命令在centos中由bridge-utils
软件包提供,如果没有要先安装。
1 2 3 4 |
[root@dellcentos7 ~]# brctl show bridge name bridge id STP enabled interfaces docker0 8000.02428eae4a50 no |
使用ifconfig观察docker0的信息
1 2 3 4 5 6 7 8 9 10 |
[root@dellcentos7 ~]# ifconfig docker0 docker0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500 inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255 inet6 fe80::42:8eff:feae:4a50 prefixlen 64 scopeid 0x20<link> ether 02:42:8e:ae:4a:50 txqueuelen 0 (Ethernet) RX packets 12 bytes 634 (634.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 8 bytes 871 (871.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 |
现在创建一个容器
1 2 |
[root@dellcentos7 ~]# docker run --name busybox1 -itd busybox /bin/sh |
再执行一次brctl命令
1 2 3 4 |
[root@dellcentos7 ~]# brctl show bridge name bridge id STP enabled interfaces docker0 8000.02428eae4a50 no vethe800a9d |
这次interfaces下面多了一个vethe800a9d
设备,这个设备正是属于前面创建的busybox1容器的。
我们再进入容器里面环境观察它的网络结构:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
[root@dellcentos7 ~]# docker exec -it busybox1 /bin/sh / # ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever 43: eth0@if44: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0 valid_lft forever preferred_lft forever / # ip route default via 172.17.0.1 dev eth0 172.17.0.0/16 dev eth0 scope link src 172.17.0.2 |
在busybox1容器中我们执行了两条查询
- 第一条查询获取容器的IP地址信息,地址段是172.17.0.0
- 第二条查询获取容器的默认网关,是172.17.0.1,这个是docker0设备的IP地址,说明它隶属于docker0网络
查看对应网络中的所有容器
我们可以查看指定网络中都有什么容器,通过docker network inspect
命令即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
[root@dellcentos7 ~]# docker network inspect bridge [ ...... "Containers": { "97d499a89660b572b1cde91161c4dffff93f6657b5c0aa1cd6e23c200437ebad": { "Name": "busybox1", "EndpointID": "1de1978bd0516864d48206686a97575261bc6aae4096f64275fe96ca82f01b9d", "MacAddress": "02:42:ac:11:00:02", "IPv4Address": "172.17.0.2/16", "IPv6Address": "" } }, ....... ] |
其中Containers片段就列出了所有挂在这个网络中的容器。也可以通过--format
参数提取特定字段的内容
1 2 3 |
[root@dellcentos7 ~]# docker network inspect bridge --format "{{json .Containers}}" {"97d499a89660b572b1cde91161c4dffff93f6657b5c0aa1cd6e23c200437ebad":{"Name":"busybox1","EndpointID":"1de1978bd0516864d48206686a97575261bc6aae4096f64275fe96ca82f01b9d","MacAddress":"02:42:ac:11:00:02","IPv4Address":"172.17.0.2/16","IPv6Address":""}} |
创建第二个容器,检查它们是否相通
1 2 |
[root@dellcentos7 ~]# docker run --name busybox2 -itd busybox /bin/sh |
现在brctl命令应该显示docker0下有两个设备
1 2 3 4 5 |
[root@dellcentos7 ~]# brctl show bridge name bridge id STP enabled interfaces docker0 8000.02428eae4a50 no veth1ec2768 vethe800a9d |
进入busybox2对busybox1执行ping命令
1 2 3 4 5 6 7 8 9 10 11 |
[root@dellcentos7 ~]# docker exec -it busybox2 /bin/sh / # ping 172.17.0.2 -c 3 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.118 ms 64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.107 ms 64 bytes from 172.17.0.2: seq=2 ttl=64 time=0.138 ms --- 172.17.0.2 ping statistics --- 3 packets transmitted, 3 packets received, 0% packet loss round-trip min/avg/max = 0.107/0.121/0.138 ms |
很明显它们的网络是互通的,再使用域名ping busybox1
1 2 3 |
/ # ping busybox1 ping: bad address 'busybox1' |
由于默认的bridge不支持DNS解析,因此ping不通。
最后,默认的bridge网络结构如下图:
用户自定义bridge网络
通过docker network create
命令创建自定义bridge网络,下面的命令创建了一个名为my_bri的网络
1 2 3 |
[root@dellcentos7 ~]# docker network create --driver bridge my_bri 351e7a677db5574f49274b2ce7b337eb9b374d7d43e9a3a4e7df6793ddf6908b |
--driver
选项用于指定网络的驱动类型,可选值有bridge、macvlan和overlay。
使用brctl命令查看
1 2 3 4 5 6 |
[root@dellcentos7 ~]# brctl show bridge name bridge id STP enabled interfaces br-351e7a677db5 8000.0242d681385d no docker0 8000.02428eae4a50 no veth1ec2768 vethe800a9d |
br-351e7a677db5
设备正是我们创建的自定义网络设备
创建两个容器,把它们都挂在my_bri网络上,只需要使用--network
选项指定要加入的网络即可
1 2 3 4 5 |
[root@dellcentos7 ~]# docker run --name busybox3 --network my_bri -itd busybox /bin/sh 99e93eb9086a5553aee694af1239a03d67ddb40c40406cf27a01440fa8cac08c [root@dellcentos7 ~]# docker run --name busybox4 --network my_bri -itd busybox /bin/sh 271422ab3f56777f8e09df24c6a4914a4cf513d99d59bcef7fca9ecc01652eb0 |
再次执行brctl命令和ifconfig命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
[root@dellcentos7 ~]# brctl show bridge name bridge id STP enabled interfaces br-351e7a677db5 8000.0242d681385d no veth0132504 vetheebd90e docker0 8000.02428eae4a50 no veth1ec2768 vethe800a9d [root@dellcentos7 ~]# ifconfig br-351e7a677db5 br-351e7a677db5: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 172.19.0.1 netmask 255.255.0.0 broadcast 172.19.255.255 inet6 fe80::42:d6ff:fe81:385d prefixlen 64 scopeid 0x20<link> ether 02:42:d6:81:38:5d txqueuelen 0 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 |
一切准备就绪,进入busybox3容器
这次我们直接使用容器的名称进行ping测试
1 2 3 4 5 6 7 8 9 10 11 |
[root@dellcentos7 ~]# docker exec -it busybox3 /bin/sh / # ping busybox4 -c 3 PING busybox4 (172.19.0.3): 56 data bytes 64 bytes from 172.19.0.3: seq=0 ttl=64 time=0.092 ms 64 bytes from 172.19.0.3: seq=1 ttl=64 time=0.129 ms 64 bytes from 172.19.0.3: seq=2 ttl=64 time=0.147 ms --- busybox4 ping statistics --- 3 packets transmitted, 3 packets received, 0% packet loss round-trip min/avg/max = 0.092/0.122/0.147 ms |
结果是通的,证明自定义bridge确实提供了DNS解析服务。
容器间的互相通讯
不同网络间的容器默认是不能互相通讯的,即docker0和my_bri上的容器是隔离的。现在我们的容器关系如下:
能不能让两个不同网络的容器通讯,例如busybox2和busybox3?答案是肯定的,只需要把busybox2连接到自定义的my_bri网络上,具体如下:
使用docker network connect
命令
1 2 |
[root@dellcentos7 ~]# docker network connect my_bri busybox2 |
现在busybox2已经加入到my_bri网络中,既然在同一个网络中,它们自然可以通讯了。进入busybox2看一下改变了什么
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
[root@dellcentos7 ~]# docker exec -it busybox2 /bin/sh / # ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever 45: eth0@if46: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0 valid_lft forever preferred_lft forever 52: eth1@if53: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue link/ether 02:42:ac:13:00:04 brd ff:ff:ff:ff:ff:ff inet 172.19.0.4/16 brd 172.19.255.255 scope global eth1 valid_lft forever preferred_lft forever |
其实就是添加了一块网卡eth1,这是理所当然的。使用brctl命令检查
1 2 3 4 5 6 |
[root@dellcentos7 ~]# brctl show br-351e7a677db5 bridge name bridge id STP enabled interfaces br-351e7a677db5 8000.0242d681385d no veth0132504 vethb5e1308 vetheebd90e |
多了一块设备和它关联,接着ping一下busybox3和busybox4
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
/ # ping busybox3 -c 3 PING busybox3 (172.19.0.2): 56 data bytes 64 bytes from 172.19.0.2: seq=0 ttl=64 time=0.084 ms 64 bytes from 172.19.0.2: seq=1 ttl=64 time=0.144 ms 64 bytes from 172.19.0.2: seq=2 ttl=64 time=0.130 ms --- busybox3 ping statistics --- 3 packets transmitted, 3 packets received, 0% packet loss round-trip min/avg/max = 0.084/0.119/0.144 ms / # ping busybox4 -c 3 PING busybox4 (172.19.0.3): 56 data bytes 64 bytes from 172.19.0.3: seq=0 ttl=64 time=0.131 ms 64 bytes from 172.19.0.3: seq=1 ttl=64 time=0.138 ms 64 bytes from 172.19.0.3: seq=2 ttl=64 time=0.136 ms --- busybox4 ping statistics --- 3 packets transmitted, 3 packets received, 0% packet loss round-trip min/avg/max = 0.131/0.135/0.138 ms |
现在busybox2和busybox3、busybox4都可以连接了,而且是通过DNS通讯的。
网络结构如下:
容器和外界相互通讯
这里的外界指的是Docker Host之外的网络。分别有容器访问外界和外界访问容器两个方向。
容器访问外网
现在我们尝试一下进入busybox1 ping百度
1 2 3 4 5 6 7 8 9 10 11 |
[root@dellcentos7 ~]# docker exec -it busybox1 /bin/sh / # ping www.baidu.com -c 3 PING www.baidu.com (183.232.231.172): 56 data bytes 64 bytes from 183.232.231.172: seq=0 ttl=54 time=10.957 ms 64 bytes from 183.232.231.172: seq=1 ttl=54 time=10.749 ms 64 bytes from 183.232.231.172: seq=2 ttl=54 time=11.009 ms --- www.baidu.com ping statistics --- 3 packets transmitted, 3 packets received, 0% packet loss round-trip min/avg/max = 10.749/10.905/11.009 ms |
从现象来看,似乎bridge网络默认就可以和外界通讯,但事实并非如下,运行如下命令
1 2 |
[root@dellcentos7 ~]# sysctl net.ipv4.conf.all.forwarding=0 |
然后删除busybox1容器重新执行docker run命令创建一个
1 2 3 4 5 6 |
[root@dellcentos7 ~]# docker stop busybox1 [root@dellcentos7 ~]# docker rm busybox1 [root@dellcentos7 ~]# docker run --name busybox1 -itd busybox /bin/sh WARNING: IPv4 forwarding is disabled. Networking will not work. 78f14e6011e0478b10b4742e01d36a32b640ea99f6d6b058170253f2a78b2d62 |
明显有一个WARNING,警告信息是:IPV4转发已被禁用,网络不可用。这时你再ping外网,发现已经不通了。
因此,我们可以这样认为:Docker Host实际上是一个路由器,docker容器要访问外网的主机,就要经过Docker Host的转发,即经过宿主机的NAT转换。
注意:net.ipv4.conf.all.forwarding参数开启与否对同一主机上的容器互相通讯没有影响
外网访问容器
我们假设宿主机已经拥有公网IP地址,否则宿主机所在的路由器必须做端口映射。
外网主机访问Docker Host容器提供的服务,只需通过-p
选项把容器的端口暴露出来即可,例如nginx服务
1 2 3 |
[root@dellcentos7 ~]# docker run --name webapp -p 80:80 -itd nginx fae88cb950c1dd31371a2a95ce1b36057ace749396ba8a4ce98ce984f28bac87 |
-p(–publish)选项的作用是把宿主机的80端口映射到容器的80端口
网络管理
docker默认的网络设置并不一定适合每个人,例如掩码,网关等,幸运的是,我们可以自由修改这些信息
1 2 3 |
[root@dellcentos7 ~]# docker network create --driver bridge --subnet 10.0.0.0/24 --gateway 10.0.0.1 my_bri2 43081e4e91015aaa38cf49cbc7ffa0943121fddae6f110a37874813dfc58ecfe |
--subnet
用于设置子网信息,--gateway
用于设置网关信息
使用ifconfig命令查看
1 2 3 4 5 6 7 8 9 |
[root@dellcentos7 ~]# ifconfig br-43081e4e9101 br-43081e4e9101: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500 inet 10.0.0.1 netmask 255.255.255.0 broadcast 10.0.0.255 ether 02:42:9f:ab:eb:01 txqueuelen 0 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 |
断开容器和网络间的连接
使用docker network disconnect命令断开网络连接
1 2 |
[root@dellcentos7 ~]# docker network disconnect my_bri2 busybox5 |
删除指定网络
使用docker network rm命令删除网络
1 2 |
[root@dellcentos7 ~]# docker network rm my_bri2 |
转载请注明:Pure nonsense » Docker容器之bridge网络