最近在看“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