目标
本博客已经为大家推出了关于Docker的系列内容,相信各位已经对容器产生了浓厚的兴趣,但是如果你深入进来可能会发现,容器与虚拟机的差别还是比较大,特别是在网络方面,还需要很多完善,当然,随着docker 1.11版本的推出,容器的网络技术越来越完善,接下来,我们就给各位介绍几个我们平常经常会碰到的一些需求。
1、通过Pipework为Docker容器设置
例如
宿主机A 和宿主机B是网络联通关系,在宿主机A上面创建了多个容器组成集群,但是我希望通过宿主机B也可以访问到宿主机A的容器,当然,你也可能会说,端口映射非常方便,如果我需要的端口比较多,或者着如果我临时需要增加某些端口,可能设置起来比较麻烦,那么如果我们将宿主机A里面的容器的IP与宿主机的IP在同一个网络,不就可以直接来进行互联互通了么。
步骤
其实这些需求在以前可能需要比较多繁杂的步骤,对于我们非网络出身的用户来说比较麻烦,但是docker原厂工程师在github上推出了pipework工具,这个工具可以使用一条命令就可以实现更改容器的IP,更准确来说为容器IP添加一个新的网卡,这岂不是非常好的事情,感谢开源!
原理
环境:(图上的右边IP 应该是192.168.14.117,不改了)
VMWare Workstation 12
Ubuntu14.04
Docker1.10
容器虚拟机有两个网卡,eth0和eth1,eth1作为管理口 192.168.14.223,我的笔记本IP相当于与虚拟机一个网络的另一个机器,IP为192.168.14.117,我的目标就是通过我的笔记本访问到容器虚拟机的容器实例。
1、在容器虚拟机里面创建两个容器实例
这里,我并不需要默认docker0网桥分配的172.17.0.1网段,所以我设置--net=none
- root@controller:~# docker run -d --name test1 --net=none ubuntu:14.04 /bin/bash
- ef8a344fd5f99f1711b9e0f1b3c7303d91cb750747ad723d1e3838983b352304
- root@controller:~# docker run -d --name test2 --net=none ubuntu:14.04 /bin/bash
- ef5179fe1058cb71aa710642c9b6cb3417213e194e5c8d76ba0def28077ce267
2、下载pipework
- git clone https://github.com/jpetazzo/pipework
- cp pipework/pipework /usr/local/bin/
- chmod +x /usr/local/bin/pipework
3、接下来,通过pipework命令直接为容器设置固定IP
- root@controller:~# pipework br0 test1 192.168.14.243/24@192.168.14.254
- root@controller:~# pipework br0 test2 192.168.14.244/24@192.168.14.254
pipework包含了200多行的shell脚本,通过network namespace,veth pair以及linux bridge完成容器网络的设置,执行过程大概包括:
- 查看主机是否包含br0(可以自定义)网桥,如果不存在就创建
- 向容器实例test1添加一块网卡(可以设置网卡名),并配置固定IP:192.168.14.243
- 若test1已经有默认的路由,则删除掉,将@后面的192.168.14.254设置为默认路由的网关
- 将test1容器实例连接到创建的br0上
4、我们进入test2容器,查看IP是否已经设置
- root@controller:~# docker ps -a
- CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
- 4940085f9358 ubuntu:14.04 "/bin/bash" 48 seconds ago Up 48 seconds test2
- 19da8f983a5c ubuntu:14.04 "/bin/bash" 54 seconds ago Up 54 seconds test1
- root@controller:~# docker exec -it 4940085f9358 /bin/bash
- root@4940085f9358:/# ip a
- 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default
- 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
- inet6 ::1/128 scope host
- valid_lft forever preferred_lft forever
- 9: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
- link/ether 76:b0:22:b6:3b:b6 brd ff:ff:ff:ff:ff:ff
- inet 192.168.14.244/24 scope global eth1
- valid_lft forever preferred_lft forever
- inet6 fe80::74b0:22ff:feb6:3bb6/64 scope link
- valid_lft forever preferred_lft forever
然后再test2容器里面,ping test1和网关测试
- root@4940085f9358:/# ping 192.168.14.243
- PING 192.168.14.243 (192.168.14.243) 56(84) bytes of data.
- 64 bytes from 192.168.14.243: icmp_seq=1 ttl=64 time=0.087 ms
- 64 bytes from 192.168.14.243: icmp_seq=2 ttl=64 time=0.128 ms
- ^C
- --- 192.168.14.243 ping statistics ---
- 2 packets transmitted, 2 received, 0% packet loss, time 999ms
- rtt min/avg/max/mdev = 0.087/0.107/0.128/0.022 ms
- root@4940085f9358:/# ping 192.168.14.254
- PING 192.168.14.254 (192.168.14.254) 56(84) bytes of data.
- From 192.168.14.244 icmp_seq=1 Destination Host Unreachable
- From 192.168.14.244 icmp_seq=2 Destination Host Unreachable
- From 192.168.14.244 icmp_seq=3 Destination Host Unreachable
- From 192.168.14.244 icmp_seq=4 Destination Host Unreachable
- From 192.168.14.244 icmp_seq=5 Destination Host Unreachable
- From 192.168.14.244 icmp_seq=6 Destination Host Unreachable
- ^C
- --- 192.168.14.254 ping statistics ---
- 9 packets transmitted, 0 received, +6 errors, 100% packet loss, time 7999ms
- pipe 4
说明配置都没有问题
5、我们再看上图,目前c1和C2我们已经联通,而且都在14网段,那么现在宿主机还是ping不通容器实例,我们只需要将宿主机的eth0网卡添加到br0网桥即可
- root@controller:~# brctl addif br0 eth0
- root@controller:~# brctl show
- bridge name bridge id STP enabled interfaces
- br0 8000.000c29d35afe no eth0
- veth1pl1844
- veth1pl1866
- docker0 8000.0242e420d7c6 no
然后再进行相关测试
- root@controller:~# ping 192.168.14.243
- PING 192.168.14.243 (192.168.14.243) 56(84) bytes of data.
- 64 bytes from 192.168.14.243: icmp_seq=1 ttl=64 time=0.398 ms
- 64 bytes from 192.168.14.243: icmp_seq=2 ttl=64 time=0.831 ms
- 64 bytes from 192.168.14.243: icmp_seq=3 ttl=64 time=0.842 ms
- 64 bytes from 192.168.14.243: icmp_seq=4 ttl=64 time=0.844 ms
- 64 bytes from 192.168.14.243: icmp_seq=5 ttl=64 time=0.876 ms
- ^C
- --- 192.168.14.243 ping statistics ---
- 5 packets transmitted, 5 received, 0% packet loss, time 4005ms
- rtt min/avg/max/mdev = 0.398/0.758/0.876/0.181 ms
- root@controller:~# ping 192.168.14.244
- PING 192.168.14.244 (192.168.14.244) 56(84) bytes of data.
- 64 bytes from 192.168.14.244: icmp_seq=1 ttl=64 time=0.262 ms
- 64 bytes from 192.168.14.244: icmp_seq=2 ttl=64 time=1.00 ms
我们看到宿主机也可以ping通固定IP的容器实例,那么接下来在我的笔记本测试应该就很简单了,因为我的笔记本都是windows10,所以在cmd直接测试
- C:\Users\Administrator>ping 192.168.14.244
-
- 正在 Ping 192.168.14.244 具有 32 字节的数据:
- 来自 192.168.14.244 的回复: 字节=32 时间<1ms TTL=64
- 来自 192.168.14.244 的回复: 字节=32 时间<1ms TTL=64
- 来自 192.168.14.244 的回复: 字节=32 时间<1ms TTL=64
-
- 192.168.14.244 的 Ping 统计信息:
- 数据包: 已发送 = 3,已接收 = 3,丢失 = 0 (0% 丢失),
- 往返行程的估计时间(以毫秒为单位):
- 最短 = 0ms,最长 = 0ms,平均 = 0ms
- Control-C
- ^C
- C:\Users\Administrator>ping 192.168.14.243
-
- 正在 Ping 192.168.14.243 具有 32 字节的数据:
- 来自 192.168.14.243 的回复: 字节=32 时间<1ms TTL=64
- 来自 192.168.14.243 的回复: 字节=32 时间<1ms TTL=64
- 来自 192.168.14.243 的回复: 字节=32 时间<1ms TTL=64
- 来自 192.168.14.243 的回复: 字节=32 时间<1ms TTL=64
-
- 192.168.14.243 的 Ping 统计信息:
- 数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失),
- 往返行程的估计时间(以毫秒为单位):
- 最短 = 0ms,最长 = 0ms,平均 = 0ms
问题
pipework目前还有缺陷,就是容器重启后IP设置会自动消失,需要重新设置,后面我们再介绍其他更加有效的方法。
当然,关于容器的网络还有更多事情要做,例如如何实现跨宿主机所在的容器实例网络连接等,后面我们一块探讨该问题。
2、通过Python脚本实现并解决pipework缺陷
题记
前面已经提到通过使用pipework方式,为容器设置固定IP,但是该方法有一个问题就是如果我们的容器实例重启,设置的固定IP会丢失,这显然回事一件令人头疼的事情,如果我们重启后IP依然保持设置的,岂不是一件很好的事情,接下来我们就介绍一下如何完成这个需求。
通过这个图可以看到,与上一篇使用pipework架构基本类似,本次只是用了一个网卡,而且我只创建了一个容器实例C1,相关环境可以参考上一篇介绍。
1、为容器服务器设置br0网桥,该网桥写入到配置文件里面,dns-nameservers如果需求可以添加
- root@controller:~# cat /etc/network/interfaces
- # This file describes the network interfaces available on your system
- # and how to activate them. For more information, see interfaces(5).
-
- # The loopback network interface
- auto lo
- iface lo inet loopback
-
- # The primary network interface
- #auto eth0
- #iface eth0 inet static
- # address 10.0.0.11
- # netmask 255.255.255.0
- auto br0
- iface br0 inet static
- address 192.168.14.225
- netmask 255.255.255.0
- gateway 192.168.14.254
- bridge_ports eth0
- bridge_stp off
2、安装相应的包文件
- #安装pip
- apt-get install python-pip python-dev build-essential
-
- #安装docker python的api
- pip install docker-py
3、启动一个容器实例
- root@controller:~# docker ps -a
- CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
- root@controller:~# docker run -i -t --name test1 --net=none ubuntu:14.04 /bin/bash
- root@443b6fa7416a:/#
- root@443b6fa7416a:/# ip a
- 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default
- 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
- inet6 ::1/128 scope host
- valid_lft forever preferred_lft forever
4、下载相关文件(docker-static-ip-master.zip)
解压之后,进入该文件夹,该文件夹其实就是通过python脚本实现了设置固定IP的步骤。
我们需要修改相关的配置文件,添加需要设置的容器实例信息
- root@controller:~# cd docker-static-ip-master/
- root@controller:~/docker-static-ip-master# ls
- containers.cfg duration.py README.md
- root@controller:~/docker-static-ip-master# cat containers.cfg
- #<container-id>,<bridge-name>,<ipaddress/netmask>,<gateway>
- root@controller:~/docker-static-ip-master# docker ps -a
- CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
- 443b6fa7416a ubuntu:14.04 "/bin/bash" 3 minutes ago Exited (0) 3 minutes ago test1
- root@controller:~/docker-static-ip-master#
- root@controller:~/docker-static-ip-master# echo "443b6fa7416a,br0,192.168.14.243/24,192.168.14.254" >> containers.cfg
- root@controller:~/docker-static-ip-master# python duration.py
5、查看信息(在容器实例)
- root@443b6fa7416a:/# ip a
- 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default
- 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
- inet6 ::1/128 scope host
- valid_lft forever preferred_lft forever
- 7: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
- link/ether 3a:9d:3b:13:89:db brd ff:ff:ff:ff:ff:ff
- inet 192.168.14.243/24 scope global eth0
- valid_lft forever preferred_lft forever
- inet6 fe80::389d:3bff:fe13:89db/64 scope link
- valid_lft forever preferred_lft forever
在容器实例测试连接
- root@443b6fa7416a:/# ping 192.168.14.254
- PING 192.168.14.254 (192.168.14.254) 56(84) bytes of data.
- 64 bytes from 192.168.14.254: icmp_seq=1 ttl=255 time=22.5 ms
- 64 bytes from 192.168.14.254: icmp_seq=2 ttl=254 time=2.00 ms
- ^C
- --- 192.168.14.254 ping statistics ---
- 2 packets transmitted, 2 received, 0% packet loss, time 1002ms
- rtt min/avg/max/mdev = 2.005/12.282/22.559/10.277 ms
- root@443b6fa7416a:/# ping 192.168.14.225
- PING 192.168.14.225 (192.168.14.225) 56(84) bytes of data.
- 64 bytes from 192.168.14.225: icmp_seq=1 ttl=64 time=0.127 ms
- 64 bytes from 192.168.14.225: icmp_seq=2 ttl=64 time=0.104 ms
- ^C
- --- 192.168.14.225 ping statistics ---
- 2 packets transmitted, 2 received, 0% packet loss, time 999ms
- rtt min/avg/max/mdev = 0.104/0.115/0.127/0.015 ms
在宿主机查看信息
- root@controller:~# ifconfig br0
- br0 Link encap:Ethernet HWaddr 00:0c:29:d3:5a:fe
- inet addr:192.168.14.225 Bcast:192.168.14.255 Mask:255.255.255.0
- inet6 addr: fe80::20c:29ff:fed3:5afe/64 Scope:Link
- UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
- RX packets:7139 errors:0 dropped:0 overruns:0 frame:0
- TX packets:976 errors:0 dropped:0 overruns:0 carrier:0
- collisions:0 txqueuelen:0
- RX bytes:552522 (552.5 KB) TX bytes:123821 (123.8 KB)
-
- root@controller:~# brctl show
- bridge name bridge id STP enabled interfaces
- br0 8000.000c29d35afe no eth0
- tap1923
- docker0 8000.02427810a053 no
- root@controller:~# ping 192.168.14.243
- PING 192.168.14.243 (192.168.14.243) 56(84) bytes of data.
- 64 bytes from 192.168.14.243: icmp_seq=1 ttl=64 time=0.033 ms
- 64 bytes from 192.168.14.243: icmp_seq=2 ttl=64 time=0.065 ms
- 64 bytes from 192.168.14.243: icmp_seq=3 ttl=64 time=0.100 ms
- ^C
- --- 192.168.14.243 ping statistics ---
- 3 packets transmitted, 3 received, 0% packet loss, time 2000ms
- rtt min/avg/max/mdev = 0.033/0.066/0.100/0.027 ms
在我的笔记本测试连接
- C:\Users\Administrator>ping 192.168.14.243
-
- 正在 Ping 192.168.14.243 具有 32 字节的数据:
- 来自 192.168.14.243 的回复: 字节=32 时间<1ms TTL=64
- 来自 192.168.14.243 的回复: 字节=32 时间<1ms TTL=64
- 来自 192.168.14.243 的回复: 字节=32 时间<1ms TTL=64
- 来自 192.168.14.243 的回复: 字节=32 时间<1ms TTL=64
-
- 192.168.14.243 的 Ping 统计信息:
- 数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失),
- 往返行程的估计时间(以毫秒为单位):
- 最短 = 0ms,最长 = 0ms,平均 = 0ms
6、重启容器实例,测试IP
- root@443b6fa7416a:/# exitroot@controller:~#
- root@controller:~# docker stop 443b6fa7416a
- 443b6fa7416a
- root@controller:~# docker start 443b6fa7416a
- 443b6fa7416a
- root@controller:~# docker exec -it 443b6fa7416a /bin/bash
- root@443b6fa7416a:/# ifconfig
- eth0 Link encap:Ethernet HWaddr 4e:ef:ea:8d:0a:30
- inet addr:192.168.14.243 Bcast:0.0.0.0 Mask:255.255.255.0
- inet6 addr: fe80::4cef:eaff:fe8d:a30/64 Scope:Link
- UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
- RX packets:30 errors:0 dropped:0 overruns:0 frame:0
- TX packets:7 errors:0 dropped:0 overruns:0 carrier:0
- collisions:0 txqueuelen:1000
- RX bytes:2364 (2.3 KB) TX bytes:578 (578.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)
-
- root@443b6fa7416a:/# ping 192.168.14.225
- PING 192.168.14.225 (192.168.14.225) 56(84) bytes of data.
- 64 bytes from 192.168.14.225: icmp_seq=1 ttl=64 time=0.160 ms
- 64 bytes from 192.168.14.225: icmp_seq=2 ttl=64 time=0.113 ms
- 64 bytes from 192.168.14.225: icmp_seq=3 ttl=64 time=0.113 ms
- ^C
- --- 192.168.14.225 ping statistics ---
- 3 packets transmitted, 3 received, 0% packet loss, time 1999ms
- rtt min/avg/max/mdev = 0.113/0.128/0.160/0.025 ms
- root@443b6fa7416a:/#
3、如何节省IP资源防止主机网络广播风暴
题记
前面我们提到使用两种方式实现Docker容器实例与主机网络的固定IP设置,也实现了外部网络与Docker容器的相互访问,而且这种方式支持跨主机容器实例的网络连通,但是不知道大家考虑过没有,使用这种方式其实也存在大量的问题:
1、Docker容器占用大量的主机网络的IP地址资源
2、大量Docker容器可能引起广播风暴,导致主机所在网络性能下降
3、Docker容器连在主机的网络中可能引起安全问题
那么接下来,我们就以上面的问题,看看如何解决。
本博客就是用最简单的方法,如果你已经理解了上两个博客设置固定IP的话,其实原理很简单,还记得我们为容器设定固定IP的时候,在创建容器实例添加了一个--net=none,也就是不使用默认的网络资源,其实在实际中,我们可以使用已经默认的docker0网桥,为容器实例添加一个新的网卡,这个网卡可以设置主机网络的固定IP,另外一个docker0网络与其他容器实例组成集群连接,不就解决问题了么。
如上图所示,在一个主机服务器上,安装完Docker程序后,默认创建一个docker0网桥,172.17.0.1,如果创建docker实例,实例上自动添加一个eth0网卡,IP默认172.17.0.x,在同一主机服务器上的容器实例都在docker0网桥上可以相互连接,为了节省IP资源,我们可以为容器C1添加一个新的网卡eth1,设置主机固定IP,这样我们就可以直接访问容器C1,而c1又可以与其他容器进行连接。
1、创建容器实例已经不需要添加--net=none
2、添加容器固定IP
这种需求经常存在,例如SuperMap iServer集群,Hadoop\Spark集群等,都可以使用该方式设置网络,节省大量的主机网络IP资源。
需要注意的是,前面介绍了两种方式:
1、pipework的方式,直接为容器添加了一个eth1网卡,这个直接可以用
2、使用python脚本的方式,该脚本默认添加到eth0网卡,所以需要修改一下脚本即可,也比较简单,直接把脚本里面的eth0修改为eth1即可。
问题
当然,你也可能提到,你现在举得例子是一个容器主机,如果跨主机容器连接,通过172.17网段如何实现,而且他们可能出现IP重叠情况,带着这个问题,我们继续探求。
转自:http://blog.csdn.net/chinagissoft/article/details/51250839