最近在看“KVM虚拟化技术实战与原理解析”这本书, 略读了前四章后, 开始动手创建并安装一个虚拟机. 然后发现一个很严重的问题, 就是我没有办法通过ssh连接到虚拟机(linux), 也没有办法通过mstsc连到到虚拟机(windows), 因为我在创建虚拟机时网卡模式只能选择NAT, 不知道为什么没有其他选择方式.
我知道解决这个情况的办法是使用桥接, 因为以前用virtualbox或者vmware的时候都是选择网卡桥接模式, 然后我就开始阅读第四章的网卡配置. 按照书上的例子, 无法实现桥接(连最基本的virbr0是怎么来的都没有介绍……中间省略500字……, 就不继续吐嘈了).
然后上网找了一些文档阅读了之后, 明白了几个关键点:
1. virbr0是虚拟网络适配器(即虚拟网卡), 该网卡由virsh维护.
2. 创建的虚拟机都会绑定在这个网卡上, 通过brctl show可以看到.
3. 需要将物理网卡(eth0)与virbr0绑定在一起并且将物理网卡上的所有ip平移到虚拟网卡上, 才能实现共享网络.
由于知识匮乏, 不知道如何继续集成使桥接的配置更灵活. 每次开机后都要把几个命令反复的粘贴来实现桥接.
1. ifconfig eth0 0;
2. ip addr add ip地址/子网 dev virbr0
3. route add default gw 网关地址 dev virbr0
4. brctl addif virbr0 eth0
几天下来之后我就感觉到比较烦躁了, 于是又有了下面这段代码, 来减少我对桥接的阴影.
[root@localhost ~]# vim bridgeWay.py # -.- coding:utf-8 -.- __author__ = 'root' import re import os import sys import getopt from xml.sax import parse from xml.sax.handler import ContentHandler # 获取XML文件中的Bridge网卡名称 class getHandler(ContentHandler): def __init__(self): self.bridge = [] def startElement(self, name, attrs): if name == "bridge": self.bridge.append(attrs["name"]) # 输出帮助信息 def printHelp(): print "INTRODUCTION" print "-"*60 print "Syntax(1): python %s -i ethX [-h]" % sys.argv[0] print "Syntax(2): python %s --interface ethX [--help]" % sys.argv[0] print "-i or --interface: network interface which to grant bridge." print "-"*60 # 处理网卡配置,提取出一组或多组ip信息. def handleNI(interface): with open("/etc/sysconfig/network-scripts/ifcfg-%s" % interface, "r") as netCar: ipAddress = {} result = [] splitVar = [] extrNum = [] # 获取出多组ip信息(IP地址, 子网掩码, 网关) for i in netCar.readlines(): # 拆分文本内容. eachPara = i.replace("\n", "").split("=") # 如果是注释掉的内容则不处理. if "#" in eachPara[0]: continue # 提取ip信息(ipaddr、preffix、netmask、gateway). if re.findall(r"IPADDR|PREFIX|NETMASK|GATEWAY", eachPara[0]): ipAddress[eachPara[0]] = eachPara[1] for i in ipAddress.keys(): # 拆分变量名称(ipaddr2 --> ['ipaddr', '2']) splitVar.append([re.split(r"[0-9]+", i)[0], re.split(r"[a-zA-Z]+", i)[1]]) # 提取变量数字(ipaddr2, ipaddr3 --> ['2', '3']) extrNum.append(re.split(r"[a-zA-Z]+", i)[1]) # 提取并组合正确的ip组(即每组对应一个ip、preffix、netmask、gateway) for i in list(set(extrNum).intersection(set(extrNum))): temp = {} for j in splitVar: if i == j[1]: temp[j[0]] = ipAddress[''.join(j)] result.append(temp) return result def rebuildBridge(netInterface, bridgeName, ipList): result = [] # 绑定网卡为桥接模式 os.popen("brctl addif %s %s >> /dev/null 2>&1" % (bridgeName, netInterface)) for i in ipList: # 清除原网卡上所设定的ip地址 os.popen("ip addr del %s/%s dev %s >> /dev/null 2>&1" % (i["IPADDR"], i["PREFIX"], netInterface)) # 在桥接口上添加ip地址 os.popen("ip addr add %s/%s dev %s >> /dev/null 2>&1" % (i["IPADDR"], i["PREFIX"], bridgeName)) # 只要ip列表中包含有网关, 则会启用该网关. if i.has_key("GATEWAY"): os.popen("route del default gw %s dev %s >> /dev/null 2>&1" % (i["GATEWAY"], netInterface)) os.popen("route add default gw %s dev %s >> /dev/null 2>&1" % (i["GATEWAY"], bridgeName)) # 若网关设置好了之后无法被ping通, 则会将该条默认网关清除掉. getPing = os.popen("ping -c 1 %s >> /dev/null 2>&1; echo $?" % i["GATEWAY"]).read().replace("\n", "") # linux中的操作, 正确返回0, 错误返回非0. if int(getPing) != 0: result.append(("error", i["GATEWAY"])) os.popen("route del default gw %s dev %s >> /dev/null 2>&1" % (i["GATEWAY"], bridgeName)) else: result.append(("correct", i["GATEWAY"])) for i in result: if "correct" in i[0]: print "网关可以正常使用: ", i[1] # 检查输入参数是否正确 def checkArguments(*args): options, args = getopt.getopt(sys.argv[1:], shortopts="hi:", longopts=["help", "interface="]) for name, value in options: if name in ("-h", "--help"): printHelp() sys.exit(1) elif name in ("-i", "--interface"): return value else: printHelp() sys.exit(1) if __name__ == "__main__": if len(sys.argv) > 1: # 定义kvm读取网卡(virbrX)的配置信息. filePath = "/etc/libvirt/qemu/networks/default.xml" # 检查参数是否正确. interface = checkArguments(sys.argv[1:]) # 获取ip信息 ipList = handleNI(interface) # 获取桥接网卡名称(Bridge Name). handleXML = getHandler() parse(filePath, handleXML) bridgeName = handleXML.bridge[0] # 创建桥接. rebuildBridge(interface, bridgeName, ipList) else: printHelp()
以后我要用虚拟机的时候,运行一下这个脚本, 就会帮助我解决网络的问题.
[root@localhost ~]# python bridgeWay.py -i eth0