目标
本博客已经为大家推出了关于Docker的系列内容,相信各位已经对容器产生了浓厚的兴趣,但是如果你深入进来可能会发现,容器与虚拟机的差别还是比较大,特别是在网络方面,还需要很多完善,当然,随着docker 1.11版本的推出,容器的网络技术越来越完善,接下来,我们就给各位介绍几个我们平常经常会碰到的一些需求。
例如
宿主机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
2、下载pipework
4、我们进入test2容器,查看IP是否已经设置
然后再test2容器里面,ping test1和网关测试
说明配置都没有问题
5、我们再看上图,目前c1和C2我们已经联通,而且都在14网段,那么现在宿主机还是ping不通容器实例,我们只需要将宿主机的eth0网卡添加到br0网桥即可
问题
pipework目前还有缺陷,就是容器重启后IP设置会自动消失,需要重新设置,后面我们再介绍其他更加有效的方法。
当然,关于容器的网络还有更多事情要做,例如如何实现跨宿主机所在的容器实例网络连接等,后面我们一块探讨该问题。
题记
前面已经提到通过使用pipework方式,为容器设置固定IP,但是该方法有一个问题就是如果我们的容器实例重启,设置的固定IP会丢失,这显然回事一件令人头疼的事情,如果我们重启后IP依然保持设置的,岂不是一件很好的事情,接下来我们就介绍一下如何完成这个需求。
通过这个图可以看到,与上一篇使用pipework架构基本类似,本次只是用了一个网卡,而且我只创建了一个容器实例C1,相关环境可以参考上一篇介绍。
1、为容器服务器设置br0网桥,该网桥写入到配置文件里面,dns-nameservers如果需求可以添加
2、安装相应的包文件
3、启动一个容器实例
4、下载相关文件(docker-static-ip-master.zip)
解压之后,进入该文件夹,该文件夹其实就是通过python脚本实现了设置固定IP的步骤。
我们需要修改相关的配置文件,添加需要设置的容器实例信息
5、查看信息(在容器实例)
在容器实例测试连接
在宿主机查看信息
6、重启容器实例,测试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
root@controller:~/docker-static-ip-master# docker exec -it test1 /bin/bash
root@b1308e21f885:/# ip a
1: lo: 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
29: eth0: mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::42:acff:fe11:2/64 scope link
valid_lft forever preferred_lft forever
2、添加容器固定IP
root@b1308e21f885:/# ip a
1: lo: 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
29: eth0: mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::42:acff:fe11:2/64 scope link
valid_lft forever preferred_lft forever
31: eth1: mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 62:68:d9:65:27:1d brd ff:ff:ff:ff:ff:ff
inet 192.168.14.243/24 scope global eth1
valid_lft forever preferred_lft forever
inet6 fe80::6068:d9ff:fe65:271d/64 scope link
valid_lft forever preferred_lft forever
这种需求经常存在,例如SuperMap iServer集群,Hadoop\Spark集群等,都可以使用该方式设置网络,节省大量的主机网络IP资源。
需要注意的是,前面介绍了两种方式:
1、pipework的方式,直接为容器添加了一个eth1网卡,这个直接可以用
2、使用python脚本的方式,该脚本默认添加到eth0网卡,所以需要修改一下脚本即可,也比较简单,直接把脚本里面的eth0修改为eth1即可。
#!/usr/bin/python
# -*- coding:UTF-8 -*-
'''
__author__ = 'lioncui'
__date__ = '2015-6-16'
'''
import docker
import os
import time
try:
connect = docker.Client(base_url='unix:///var/run/docker.sock',version='1.17',timeout=120)
connect.version()
except:
exit()
def Duration(id, br, addr, gw):
try:
container_info = connect.inspect_container(resource_id=id)
pid = str(container_info['State']['Pid'])
except:
pid = 0
if int(pid) != 0:
if not os.path.exists('/var/run/netns'):
os.makedirs('/var/run/netns')
source_namespace = '/proc/'+pid+'/ns/net'
destination_namespace = '/var/run/netns/'+pid
if not os.path.exists(destination_namespace):
link = 'ln -s %s %s' % (source_namespace,destination_namespace)
os.system(link)
os.system('ip link add tap%s type veth peer name veth%s 2>> /var/log/docker-static-ip.log' % (pid,pid) )
os.system('brctl addif %s tap%s 2>> /var/log/docker-static-ip.log' % (br,pid) )
os.system('ip link set tap%s up 2>> /var/log/docker-static-ip.log' % pid )
os.system('ip link set veth%s netns %s 2>> /var/log/docker-static-ip.log' % (pid,pid) )
os.system('ip netns exec %s ip link set dev veth%s name eth1 2>> /var/log/docker-static-ip.log' % (pid,pid) )
os.system('ip netns exec %s ip link set eth1 up 2>> /var/log/docker-static-ip.log' % pid)
os.system('ip netns exec %s ip addr add %s dev eth1 2>> /var/log/docker-static-ip.log' % (pid,addr) )
os.system('ip netns exec %s ip route add default via %s 2>> /var/log/docker-static-ip.log' % (pid,gw) )
syspid = os.fork()
if syspid == 0:
while True:
file = open('./containers.cfg')
if file:
for i in file:
i = i.strip('\n')
cfg = i.split(',')
Duration(*cfg)
file.close()
time.sleep(10)
else:
exit()
问题
当然,你也可能提到,你现在举得例子是一个容器主机,如果跨主机容器连接,通过172.17网段如何实现,而且他们可能出现IP重叠情况,带着这个问题,我们继续探求。
转自:http://blog.csdn.net/chinagissoft/article/details/51250839