1. 程式人生 > 其它 >雲端計算與虛擬化入門通識

雲端計算與虛擬化入門通識

經常有朋友問我,你是做什麼的呢?

我回答說,雲端計算。

不回答還好,一回答,他們更加疑惑了。聽著挺高大上,挺牛b的,就是不知道是什麼。在大多數Pythonista的認知裡,學會了Python,不從事爬蟲,就是做Web開發,不然就是資料分析/挖掘,人工智慧的。

想一想,這也是合理的,大部分培訓班為你讓你交學費,一般都會把你的職業路線給規劃好,什麼Web開發,什麼爬蟲工程師,什麼資料分析師等等,卻沒人告訴你,學會了Python,也可以去做一名雲端計算工程師(準確地說應該是OpenStack工程師,因為雲端計算涉及的範圍更廣,需要的技術棧更多,而不單單是一門程式語言)。

為了讓你多瞭解一些雲端計算的內容,我想著寫這麼一篇文章,介紹一下我從事的領域,同時也對雲端計算和虛擬化這塊入門級知識做一個梳理,如果剛好你也想進入這個領域,這份入門通識指南,應該挺適合你的。

1. 雲端計算是什麼?

維基百科上定義的雲端計算(英語:cloud computing),是一種基於網際網路的計算方式,通過這種方式,共享的軟硬體資源和資訊可以按需求提供給計算機各種終端和其他裝置。

枯燥的定義,聽起來還是不太好理解,我嘗試用自己的語言來解釋下。

計算,即計算資源,包括我們熟悉的 CPU,記憶體,磁碟,頻寬等。

雲,就是將這些零散實體資源變成一個巨大無比的資源池子,有了這個池子,做為個人使用者,你不再需要自己你買一個電腦放在家裡,做為小型公司,你不需要自己整一個機房,花很多的人力和裝置成本去運營這些基礎設施。一旦你需要,你就向池子擁有者申請即可。這極大的提高了資源的利用率,以及分配的靈活性。

還有人說,雲就像是天上的雲一樣,聚焦的水汽多了就會下雨,落到地面的雨水又會蒸發到天上,繼續等待下一次下雨。雲端計算裡的雲,正如大自然裡的雲一樣,可以實現資源的迴圈利用。你在公有云提供商那裡,購買了一年的雲主機,一年後資源被回收,可以再分配給其他人使用。

雲端計算的模型,是以服務為導向的。根據服務層次的不同,可以分為三類:

  1. IaaS(Infrastructure as a Service):基礎設施即服務,簡單點說就是提供基礎設施,你在阿里雲,AWS上購買的雲主機就屬於這類。
  2. PaaS(Platform as a Service):平臺即服務,簡單點說就是提供一個平臺,典型的應用有,GAE(Google App Engine),直接給你提供一個應用程式的執行環境。
  3. SaaS(Software as a Service):軟體即服務,這個你再熟悉不過了,你手機上的APP都是屬於這類。

以上三種模型,面向的群體各不相同,從上到下,使用者的自主權越來越小,需關注的細節也越來越少。

另外根據部署方式的不同,可以將雲端計算分為三類:公有云、私有云和混合雲。

私有云由專供一個企業或組織使用的雲端計算資源構成。私有云可在物理上位於組織的現場資料中心,也可由第三方服務提供商託管。而混合雲,就是二者皆有。

網上很流行的一種比喻:男人找個女友或老婆是自建私有云,單身約p或者到娛樂場所消費是公有云服務,按需使用並可彈性擴容,已婚男人找二奶小蜜則屬於混合雲。

這種解釋方式雖然比較俗,但卻挺恰當,便於小白理解。

2. 虛擬化是什麼?

雲端計算,是為了提高資源的利用率,分配的靈活性而提出的一種解決方案。

而這個解決方案的底層,需要有技術支撐,目前主要是虛擬化技術和容器技術。

這次主要講的是虛擬化。

你是不是又要蒙圈了,什麼是虛擬化?

它是一種可以將計算機的實體資源(CPU,記憶體,儲存,網路等)進行抽象轉化,並提供分割,重新組合,以達到最大化利用資源的一種技術。

虛擬機器使用過吧?

當你只有一個電腦裝了windows系統,而你也想體驗一下linux系統,如果不想折騰去裝個雙系統,最簡單的方法就是用 VMWare 或者 VirtualBox 在你的電腦裡用linux的映象建立個虛擬機器。

你有沒有想過,這虛擬機器是如何創建出來,怎麼這麼神奇,一臺電腦上竟然可以同時執行著兩個作業系統。

其實你後建立的這個虛擬機器只是原物理機上的一個程序而已。只不過它從外觀上、使用上看起來和你原來宿主機上的系統沒有什麼區別。這個虛擬機器裡有自己的記憶體,cpu,磁碟,網絡卡,這些都依賴虛擬化技術才得以實現的。

在虛擬機器內部,如果要使用物理機上裝置,除了虛擬化技術讓其可以間接地使用物理裝置,也可以使用裝置的直通讓虛擬機器直接使用物理裝置,這種直通技術,不需要經過VMM(虛擬機器監控器,後面會介紹),所以效能會比虛擬化好。常見的有GPU直通。還有直通與虛擬化的結合,如SR-IOV,即單根IO虛擬化(Single-root I/O virtualization),將一個物理網絡卡(PF)虛擬化成多個虛擬網絡卡(VF),再將虛擬網絡卡直給掛給虛擬機器使用。

3. VMM 是什麼?

VMM,通常叫做 Hypervisor(下面我們也將以Hypervisor指代VMM),中文名:虛擬機器監控器,英文全稱:Virtual Machine Monitor。

Hypervisor 是為了實現虛擬化而引入的一個介於虛擬機器作業系統和物理資源的軟體層。

需要注意的是,Hypervisor並不是一款具體的軟體,而是一類軟體的統稱。

當虛擬機器要對物理資源進行操作時,Hypervisor將對其指令進行擷取並且重定向,讓虛擬機器無感知地像物理作業系統一樣使用物理資源。

常見的Hypervisor,有

  • KVM
  • Xen
  • Hyper-V
  • VMWare

4. 虛擬化技術

4.1 KVM

KVM(Kernel-based Virtual Machine),意思是基於核心的虛擬機器。

KVM是整合到Linux核心的Hypervisor,是X86架構且硬體支援虛擬化技術(Intel VT或AMD-V)的Linux的全虛擬化解決方案。它是Linux的一個很小的模組,利用Linux做大量的事,如任務排程、記憶體管理與硬體裝置互動等。

4.2 Xen

Xen是第一類執行在裸機上的虛擬化管理程式。它支援全虛擬化和半虛擬化,Xen支援hypervisor和虛擬機器互相通訊,而且提供在所有Linux版本上的免費產品,包括Red Hat Enterprise Linux和SUSE Linux Enterprise Server。Xen最重要的優勢在於半虛擬化,此外未經修改的作業系統也可以直接在xen上執行(如Windows),能讓虛擬機器有效執行而不需要模擬,因此虛擬機器能感知到hypervisor,而不需要模擬虛擬硬體,從而能實現高效能。

4.3 QEMU

QEMU是一套由Fabrice Bellard所編寫的模擬處理器的自由軟體。Qemu,其中關鍵字emu,全稱emulator,模擬器,所以單純使用qemu是採用的完全虛擬化的模式。

那QEMU有什麼用?它和KVM是什麼關係呢?

準確來說,KVM是Linux kernel的一個模組。可以用命令modprobe去載入KVM模組。載入了模組後,才能進一步通過其他工具建立虛擬機器。

但僅有KVM模組是 遠遠不夠的,KVM是最底層的hypervisor,它僅用來模擬CPU的執行,缺少了對network和周邊I/O的支援,所以我們是沒法直接用它的。

而QEMU-KVM就是一個完整的模擬器,它是基於KVM構建的,提供了完整的網路和I/O支援。

說到了QEMU,其實它也是一個虛擬化軟體。作用是什麼呢,它相當於一個路由器,當Guest OS的核心想要操作物理硬體時,必須先經由Qemu轉發,將操作指令轉給真實的硬體。由於所有的指令都要從Qemu裡面過一手,因而效能比較差。

總結

  1. KVM 和 Xen 都是免費的。
  2. KVM 需要硬體支援(Intel VT或AMD-V),整合在核心中,而Xen可在所有的Linux上執行,可不需要硬體支援。

4.4 libvirt

要解釋libvirt是什麼,只要知道為什麼會需要libvirt就好了。

  • 虛擬化的底層可能是KVM,也可能是Xen,或者是其他市面上的Hypervisor,種類之繁多,如果沒有一個統一的介面來管理它們,就太亂了,移植性非常差。
  • Hypervisor ,以 qemu-kvm 為例,它的命令列虛擬機器管理工具引數眾多,難於使用。需要有一個工具將這些引數進行封裝。

這些都是在核心空間層做的事情,而我們使用者建立、銷燬虛擬機器都是在使用者空間層操作,這就尷尬了,我們沒有許可權。

這下該 libvirt 出場了,libvirt分為服務端各客戶端。

服務端是libvirtd,而你所熟悉的virt,virt-install,virt-manager,virt-viewer 等都是libvirt的客戶端。

目前,libvirt 已經成為使用最為廣泛的對各種虛擬機器進行管理的工具和應用程式介面(API),而且一些常用的虛擬機器管理工具(如virsh、virt-install、virt-manager等)和雲端計算框架平臺(如OpenStack、OpenNebula、Eucalyptus等)都在底層使用libvirt的應用程式介面。

5. 虛擬化分類

5.1 全虛擬化和半虛擬化

根據客戶機系統是否需要修改定製可以分為全虛擬化半虛擬化

1. 全虛擬化

全虛擬化(英語:Full virtualization),是需要依託於硬體虛擬化的。

在全虛擬化模式下,虛擬機器的所有操作(CPU,記憶體,網路等)都需要經過一個執行在物理機上的虛擬化軟體轉發給物理機核心。而這個虛擬化軟體,在windows上你常見且熟悉的有vmware,virtualbox。

允許未經修改的客作業系統(英語:Guest OS)隔離執行。在全虛擬化環境中,任何可以執行在裸機上的軟體(通常是作業系統)都可以未經修改地執行在虛擬機器中。

代表:VMWare(1998年),KVM

2. 半虛擬化

半虛擬化(英語:Paravirtualization)是另一種類似於全虛擬化的熱門技術。

半虛擬化對比全虛擬化,就是有一些可以直接操作物理核心空間,而不需要全部經過虛擬化軟體。這就大大提高了虛擬機器的效能。

它在HOST上使用Hpervisor(虛擬機器管理程式)提供便利的介面,使得Guest OS能夠呼叫介面訪問虛擬硬體。而域名拍賣平臺地圖條件是,Guest OS 內部需要部署安裝相應的驅動和軟體邏輯,需要對作業系統進行修改。

代表:Xen(2006)

  • Xen是一款虛擬化軟體,支援半虛擬化和完全虛擬化。它在不支援VT技術的cpu上也能使用,但是隻能以半虛擬化模式執行。
  • 半虛擬化的意思是需要修改被虛擬系統的核心,以實現系統能被完美的虛擬在Xen上面。完全虛擬化則是不需要修改系統核心則可以直接執行在Xen上面。
  • VMware是一款完全虛擬化軟體。完全虛擬的弱點是效率不如半虛擬化的高。半虛擬化系統性能可以接近在裸機上的效能。

5.2 1型虛擬化和2型虛擬化

根據虛擬化層是直接位於硬體之上還是位於作業系統之上,可以分為 Type 1 虛擬化和 Type 2 虛擬化。

Type 1:Xen,VMWare ESX

Type 2:KVM,WMWare Workstation

5.3 硬體虛擬化和軟體虛擬化

1. 軟體虛擬化

在硬體虛擬化出現之前,市場上都是使用的軟體虛擬化。

軟體虛擬化,就是通過軟體來實現虛擬化,原理是把從虛擬機器傳來的操作指令進行擷取翻譯,並傳遞給真實的物理硬體。

由於每條指令都需要經過“擷取” -> “翻譯” -> “轉發”,所以其虛擬化效能會差一點。

哪些屬於虛擬化軟體呢?

  • KVM:負責cpu和記憶體的虛擬化,但cpu必須支援硬體虛擬化。
  • QEMU:負責IO裝置(網絡卡、磁碟)的虛擬化

2. 硬體虛擬化

硬體虛擬化,是指計算機硬體本身提供能力讓客戶機指令獨立執行,而不需要Hypervisor 截獲重定向。直接從硬體層面開始支援虛擬化。由硬體支援並提供多個虛擬硬體裝置介面,這些裝置由虛擬機器核心驅動傳遞給虛擬機器使用。使用這種方式,虛擬機器能獲得和宿主機一樣的硬體功能,效能也和宿主機相近,同時原生作業系統本來就支援這項技術,因此無需對作業系統進行修改。

Intel 從2005年開始在 x86 cpu 上支援硬體虛擬化,大大推進了虛擬化的發展。

缺點就是,硬體要支援虛擬化功能,在以前這可能是缺點,但是現在隨著虛擬化技術的發展,越來越多的硬體都已經支援虛擬化,成本也越來越低,所以硬體輔助虛擬化是目前最流行,使用最廣泛的虛擬化技術。

KVM這種流行的虛擬化技術裡,既有軟體虛擬化,也有硬體虛擬化,軟體虛擬化要基於硬體的虛擬化,二者是相輔的關係,而不是互斥。

6. KVM工具

有了虛擬化,就有了虛擬機器,那如何對這些虛擬機器進行管理呢。

在 Linux 下有許多的工具可以使用:

  • Virsh:基於 libvirt 的 命令列工具 (CLI)
  • Virt-Manager:基於 libvirt 的 GUI 工具
  • virt-v2v:虛機格式遷移工具
  • virt-* 工具:包括 Virt-install (建立KVM虛機的命令列工具), Virt-viewer (連線到虛機螢幕的工具),Virt-clone(虛機克隆工具),virt-top 等
  • libguestfs-tools:一組 Linux 下的 C 語言的 API ,用來訪問/修改虛擬機器的磁碟映像檔案。

7. 建立虛擬機器

手工建立

虛擬機器的本質是宿主機上的一個程序,當你用OpenStack在介面,或者使用virsg 建立了一個虛擬機器時。你可以使用ps -ef|grep kvm看下這個虛擬機器的程序,是下面這樣子的。

引數多得讓人頭皮發麻。意思是,你可以使用這樣一串命令才能建立一臺虛擬機器。

$ /usr/libexec/qemu-kvm \
-name guest=instance-00000035, debug-threads=on \
-S -object secret,id=masterKey0,format=raw,file=/var/lib/libvirt/qemu/domain-216-instance-00000035/master-key.aes \
-machine pc-i440fx-rhel7.5.0,accel=kvm,usb=off,dump-guest-core=off \
-cpu host \
-m 16384 \
-realtime mlock=off \
-smp 2,maxcpus=32,sockets=2,cores=16,threads=1 \
-uuid 31d70882-194f-469b-855e-fcfa6736550d \
-smbios type=1,manufacturer=RDO,product=OpenStack Compute,version=0.0.1-1.el7.centos,serial=bc147bfe8a204d06a09f98387e46b890,uuid=31d70882-194f-469b-855e-fcfa6736550d,family=Virtual Machine \
-display none \
-no-user-config -nodefaults \
-chardev socket,id=charmonitor,path=/var/lib/libvirt/qemu/domain-216-instance-00000035/monitor.sock,server,nowait \
-mon chardev=charmonitor,id=monitor,mode=control \
-rtc base=utc,driftfix=slew \
-global kvm-pit.lost_tick_policy=delay \
-no-hpet -no-shutdown -boot strict=on \

-device piix3-usb-uhci,id=usb,bus=pci.0,addr=0x1.0x2 -drive file=/dev/hdd-volumes/31d70882-194f-469b-855e-fcfa6736550d_disk,format=raw,if=none,id=drive-virtio-disk0,cache=none,aio=native -device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x4,drive=drive-virtio-disk0,id=virtio-disk0,bootindex=1 -drive file=/var/lib/nova/instances/31d70882-194f-469b-855e-fcfa6736550d/disk.config,format=raw,if=none,id=drive-ide0-0-0,readonly=on,cache=writeback \
-device ide-cd,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0 \
-netdev tap,fds=28:35,id=hostnet0,vhost=on,vhostfds=36:37 \
-device virtio-net-pci,mq=on,vectors=6,netdev=hostnet0,id=net0,mac=fa:16:3e:69:63:18,bus=pci.0,addr=0x3 -chardev pty,id=charserial0 -device isa-serial,chardev=charserial0,id=serial0 -device qxl-vga,id=video0,ram_size=67108864,vram_size=67108864,vram64_size_mb=0,vgamem_mb=16,max_outputs=1,bus=pci.0,addr=0x2 \
-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x5 -msg timestamp=on

virsh 建立

前面我們看到,建立一臺虛擬機器需要諸多的引數。

如果一個一個去指定,非常不易於管理及複用。

如果可以在建立時,指定一個配置檔案,這個配置檔案裡包含上述所有的引數,不就大大簡化了虛擬機器建立過程。

這時候就出現了virsh這個基於 libvirt 的 命令列工具 (CLI)。通過它我們可以指定一個 xml 配置檔案來很輕鬆的建立一臺虛擬機器。

virsh define vm.xml
virsh start guest_vm

其中xml的內容如下

<domain type='kvm' id='200'>
  <name>guest_vm</name>
  <memory unit='KiB'>12582912</memory>
  <currentMemory unit='KiB'>12582912</currentMemory>
  <vcpu placement='static'>6</vcpu>
  <numatune>
    <memory mode='strict' nodeset='0-1'/>
    <memnode cellid='0' mode='strict' nodeset='0'/>
    <memnode cellid='1' mode='strict' nodeset='1'/>
  </numatune>
  <resource>
    <partition>/machine</partition>
  </resource>
  <os>
    <type arch='x86_64' machine='pc-i440fx-rhel7.0.0'>hvm</type>
    <boot dev='hd'/>
    <boot dev='cdrom'/>
  </os>
  <features>
    <acpi/>
    <apic/>
  </features>
  <clock offset='utc'>
    <timer name='rtc' tickpolicy='catchup'/>
    <timer name='pit' tickpolicy='delay'/>
    <timer name='hpet' present='no'/>
  </clock>
  <on_poweroff>destroy</on_poweroff>
  <on_reboot>restart</on_reboot>
  <on_crash>restart</on_crash>
  <pm>
    <suspend-to-mem enabled='no'/>
    <suspend-to-disk enabled='no'/>
  </pm>
  <devices>
    <emulator>/usr/libexec/qemu-kvm</emulator>
    <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2'/>
      <source file='/path/to/test.qcow2'/>
      <backingStore/>
      <target dev='hda' bus='virtio'/>
      <alias name='virtio-disk0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/>
    </disk>
    <controller type='pci' index='0' model='pci-root'>
      <aliasname='pci.0'/>
    </controller>
    <controllertype='ide'index='0'>
      <aliasname='ide'/>
      <addresstype='pci'domain='0x0000'bus='0x00'slot='0x01'function='0x1'/>
    </controller>
    <controllertype='virtio-serial'index='0'>
      <aliasname='virtio-serial0'/>
      <addresstype='pci'domain='0x0000'bus='0x00'slot='0x05'function='0x0'/>
    </controller>
    <controllertype='usb'index='0'model='piix3-uhci'>
      <aliasname='usb'/>
      <addresstype='pci'domain='0x0000'bus='0x00'slot='0x01'function='0x2'/>
    </controller>
    <interfacetype='bridge'>
      <macaddress='52:54:00:d2:81:b0'/>
      <sourcebridge='br0-ovs'/>
      <virtualporttype='openvswitch'>
        <parametersinterfaceid='abc10709-ebff-4d0f-8761-4b7fdaba0dc0'/>
      </virtualport>
      <targetdev='vnet0'/>
      <modeltype='virtio'/>
      <aliasname='net0'/>
      <addresstype='pci'domain='0x0000'bus='0x00'slot='0x03'function='0x0'/>
    </interface>
    <interfacetype='bridge'>
      <macaddress='52:54:00:5e:91:38'/>
      <sourcebridge='br0-ovs'/>
      <virtualporttype='openvswitch'>
        <parametersinterfaceid='cceb5703-185a-4f6f-b2ce-a7e273e52bdc'/>
      </virtualport>
      <bandwidth>
        <inboundaverage='50000'/>
        <outboundaverage='50000'/>
      </bandwidth>
      <targetdev='vnet1'/>
      <modeltype='virtio'/>
      <aliasname='net1'/>
      <addresstype='pci'domain='0x0000'bus='0x00'slot='0x06'function='0x0'/>
    </interface>
    <interfacetype='bridge'>
      <macaddress='52:54:00:b2:77:07'/>
      <sourcebridge='br0-ovs'/>
      <virtualporttype='openvswitch'>
        <parametersinterfaceid='674716ab-243d-4137-bc01-aa2c33cca21a'/>
      </virtualport>
      <targetdev='vnet6'/>
      <modeltype='virtio'/>
      <aliasname='net2'/>
      <addresstype='pci'domain='0x0000'bus='0x00'slot='0x09'function='0x0'/>
    </interface>
    <consoletype='pty'tty='/dev/pts/4'>
      <sourcepath='/dev/pts/4'/>
      <targettype='virtio'port='0'/>
      <aliasname='console0'/>
    </console>
    <inputtype='mouse'bus='ps2'>
      <aliasname='input0'/>
    </input>
    <inputtype='keyboard'bus='ps2'>
      <aliasname='input1'/>
    </input>
    <soundmodel='ich6'>
      <aliasname='sound0'/>
      <addresstype='pci'domain='0x0000'bus='0x00'slot='0x04'function='0x0'/>
    </sound>
    <video>
      <modeltype='qxl'ram='65536'vram='65536'vgamem='16384'heads='1'primary='yes'/>
      <aliasname='video0'/>
      <addresstype='pci'domain='0x0000'bus='0x00'slot='0x02'function='0x0'/>
    </video>
    <memballoonmodel='virtio'>
      <aliasname='balloon0'/>
      <addresstype='pci'domain='0x0000'bus='0x00'slot='0x07'function='0x0'/>
    </memballoon>
  </devices>
  <seclabeltype='dynamic'model='dac'relabel='yes'>
    <label>+0:+0</label>
    <imagelabel>+0:+0</imagelabel>
  </seclabel>
</domain>

OpenStack

使用 virsh 來指定xml進行建立雖然能對虛擬機器進行生命週期的管理,但是無法對成百上千臺的機器進行集中式的管理。

這時候,OpenStack 這個開源的雲端計算管理平臺就出現了。

有了OpenStack,你可以使用 Horizon提供的介面進行虛擬機器的管理

也可以使用nova 的 cli 命令進行建立。

nova boot <vm_name> \
--flavor <flavor_id> \
--nic net-id=<net_id>,v4-fixed-ip=<ip> \
--image <image_id/name> \
--config-drive True

說了半天,線於引出了OpenStack,我的工作基本60%的時間都是圍繞著它轉,OpenStack 是一個開源框架,是使用Python語言開發的最大的專案,具說有數百萬行的程式碼量,是動態語言的一個優秀典範。

關於 OpenStck,你可能不太明白它是做什麼的。這裡引用我昨天看到的另一篇文章的一個說明:它有點像一個商店,負責管理所有的商品(計算資源、儲存資源、網路資源等),賣給使用者,但是它本身不製造商品(不具備虛擬化能力),它的商品來自KVM(當然也可以用Xen等其他Hypervisor)。