我是山姆鍋

在 「我的 K8S DevOps 實驗環境 - 基礎篇」 提到: Vagrant+Libvirt 也是值得考慮的桌面等級虛擬化方案。理論上,在同樣硬體規格下,KVM 虛擬機的效能會比 VirtualBox 來得高。所以,對於已經有 Linux 環境的人,使用這個組合應該比較有吸引力。

撰寫本文時,山姆鍋手邊並沒有可用的 Linux 系統機器,只能使用 VMWare Fusion 的巢式虛擬化 (nested virtualization) 技術來作為 KVM 宿主機。由於目的是讓 spk-cluster-lab 可以有多一個虛擬方案可以選擇,Vagrant+VirtualBox 以及 Vagrant+Libvirt 效能比較其實並非本文關注重點。

Vagrant+Libvirt 仍有些不足的地方,詳見內文。

前題假設

要進行本文描述的操作,需要符合下列條件的環境:

  1. 支援硬體虛擬化 (for KVM) 的虛擬或實體機
  2. 執行 Ubuntu 18.04 x86_64 系統
  3. 足夠給虛擬機使用的記憶體、CPU 以及磁碟空間(依據要執行的虛擬機規格與數量而定)。

山姆鍋手邊沒有 Linux 的實體機,所以使用 VMWare Fusion 虛擬機以及 Ubuntu 18.04 Desktop 版本來作為測試環境。

檢查 CPU 是否支援硬體虛擬化

執行 egrep -c '(svm|vmx)' /proc/cpuinfo 指令,如果回傳 0 則表示主機的 CPU 不支援硬體虛擬化,也就是無法使用 KVM。

1
2
[email protected]:~/spk-cluster-lab$ egrep -c '(svm|vmx)' /proc/cpuinfo
4

安裝 KVM 支援

確認主機有支援硬體虛擬化後,進行 KVM 相關套件安裝:

1
2
sudo apt-get update
sudo apt-get install -y qemu qemu-kvm libvirt-bin bridge-utils virt-manager

提醒:需要登出再登入,或者重新開機,不然現有帳戶會沒有存取 libvirtd 的權限。

安裝 Vagrant

在「Vagrant+VirtualBox 跨平台虛擬環境」有提供說明,在此為了方便參考重列指令:

需要最新或者特定版本,可以使用下列指令安裝:

1
2
3
wget https://releases.hashicorp.com/vagrant/2.2.9/vagrant_2.2.9_x86_64.deb

sudo dpkg -i vagrant_2.2.9_x86_64.deb

這裡使用 Vagrant 2.2.9, 因為 spk-cluster-lab 需要使用 Vagrant 2.2 以上的版本。

Vagrant 發行套件列表可由此位址 https://releases.hashicorp.com/vagrant/ 取得。

安裝 Vagrant 插件

除了 Vagrant 本身,需要 vagrant-libvirt 來支援 KVM 作為虛擬機,以及其他輔助套件。下面是安裝完後的插件列表:

1
2
3
4
5
[email protected]:~/spk-cluster-lab$ vagrant plugin list
sahara (0.0.17, global)
vagrant-env (0.0.3, global)
vagrant-libvirt (0.1.2, global)
vagrant-mutate (1.2.0, global)

下面各節說明套件的用途與安裝。

安裝 Vagrant-libvirt 插件

Vagrant-libvirt 插件作為 Vagrant 的 Provider,透過 libvirtd 來管理 KVM 虛擬環境。可以透過以下指令安裝:

1
vagrant plugin install vagrant-libvirt

執行 vagrant up 指令需要額外指定 provider 如下:

1
vagrant up --provider=libvirt

或者在執行前設定 VAGRANT_DEFAULT_PROVIDER 環境變數:

1
export VAGRANT_DEFAULT_PROVIDER=libvirt

提醒:vagrant-libvirt 預設使用 NFS 來作為虛擬機與宿主機共享目錄機制,需要宿主機帳戶具備 sudo 權限,且在啟動過程可能會被要求輸入密碼。

Vagrant-libvirt 在 Vagrantfile 檔案有相當多的可設定參數,進一步資訊可參考下列連結:

vagrant-libvirt
Vagrant provider for libvirt.

安裝 Vagrant-mutate 插件

Vagrant-mutate 插件可以轉換虛擬機映像檔為適合 KVM 的格式。

1
2
3
4
5
6
[email protected]:~/spk-cluster-lab$ vagrant plugin install vagrant-mutate
Installing the 'vagrant-mutate' plugin. This can take a few minutes...
Building native extensions. This could take a while...
Building native extensions. This could take a while...
Fetching vagrant-mutate-1.2.0.gem
Installed the plugin 'vagrant-mutate (1.2.0)'!

以下示範如何將一個 VirtualBox 的虛擬機映像檔轉成 libvirt 相容的格式。
首先使用 vagrant box add 下載要轉換的虛擬機映像檔:

1
vagrant box add --provider virtualbox --box-version 202003.31.0 bento/ubuntu-18.04

上面範例下載 VirtualBox 的 bento/ubuntu-18.04 映像檔,--box-version 參數可以指定映像檔版本。下載完成後,使用 vagrant mutate 指令轉換:

1
vagrant mutate bento/ubuntu-18.04 libvirt

使用 vagrant box list 列出本地映像檔確認產出所要的映像檔格式:

1
2
3
4
[email protected]:~/spk-cluster-lab$ vagrant box list
bento/ubuntu-18.04 (libvirt, 202003.31.0)
bento/ubuntu-18.04 (virtualbox, 202003.31.0)
generic/ubuntu1804 (libvirt, 3.0.10)

其中, bento/ubuntu-18.04 (libvirt, 202003.31.0) 就是轉換後的映像檔。

vagrant-mutate
Convert vagrant boxes to work with different providers

安裝 Sahara 插件

與 VirtualBox provider 不同,Vagrant-libvirt 並沒有內建支援 snapshot 功能,但此功能在實驗環境中用來快速恢復實驗前的環境狀態可以節省不少時間。

使用下列指令安裝 Sahara 插件:

1
vagrant plugin install sahara

Sahara 插件可以作為 vagrant snapshot 指令的有限替代方案,Sahara 支援一個沙盒 (sandbox) 模式,一旦進入沙盒模式,過程中對虛擬機所做的更動,使用者可以選擇是要提交 (commit) 或者回滾 (rollback)。提交會讓修改變成永久性,回滾則可以將狀態回到上一個提交的狀態。


在山姆鍋的安裝環境中,執行 vagrant sandbox 指令會出現下列錯誤 (如果您沒遇到則可跳過):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[email protected]:~/spk-cluster-lab$ vagrant sandbox on
Traceback (most recent call last):
13: from /opt/vagrant/embedded/gems/2.2.9/gems/vagrant-2.2.9/bin/vagrant:205:in `<main>'
12: from /opt/vagrant/embedded/gems/2.2.9/gems/vagrant-2.2.9/lib/vagrant/environment.rb:290:in `cli'
11: from /opt/vagrant/embedded/gems/2.2.9/gems/vagrant-2.2.9/lib/vagrant/cli.rb:67:in `execute'
10: from /home/sampot/.vagrant.d/gems/2.6.6/gems/sahara-0.0.17/lib/sahara/command/root.rb:52:in `execute'
9: from /home/sampot/.vagrant.d/gems/2.6.6/gems/sahara-0.0.17/lib/sahara/command/on.rb:19:in `execute'
8: from /opt/vagrant/embedded/gems/2.2.9/gems/vagrant-2.2.9/lib/vagrant/plugin/v2/command.rb:232:in `with_target_vms'
7: from /opt/vagrant/embedded/gems/2.2.9/gems/vagrant-2.2.9/lib/vagrant/plugin/v2/command.rb:232:in `each'
6: from /opt/vagrant/embedded/gems/2.2.9/gems/vagrant-2.2.9/lib/vagrant/plugin/v2/command.rb:238:in `block in with_target_vms'
5: from /home/sampot/.vagrant.d/gems/2.6.6/gems/sahara-0.0.17/lib/sahara/command/on.rb:21:in `block in execute'
4: from /home/sampot/.vagrant.d/gems/2.6.6/gems/sahara-0.0.17/lib/sahara/session/factory.rb:12:in `create'
3: from /home/sampot/.vagrant.d/gems/2.6.6/gems/sahara-0.0.17/lib/sahara/session/factory.rb:12:in `require_relative'
2: from /home/sampot/.vagrant.d/gems/2.6.6/gems/sahara-0.0.17/lib/sahara/session/libvirt.rb:1:in `<top (required)>'
1: from /opt/vagrant/embedded/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require'
/opt/vagrant/embedded/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require': cannot load such file -- fog (LoadError)

稍微估狗一下在這個 issue 有提到一個暫時解法

修改 ~/.vagrant.d/gems/2.6.6/gems/sahara-0.0.17/lib/sahara/session/libvirt.rb 檔案,將 require "fog" 改成 require "fog/libvirt"

如因版本變動,上述檔案路徑需要根據您的環境自行修改。


使用下列指令進入沙盒模式:

1
vagrant sandbox on

進入沙盒模式後,可以使用 vagrant ssh 登入虛擬機進行各種操作。

如果要提交修改結果,使用下列指令:

1
vagrant sandbox commit

或者使用下列指令回到上次提交的狀態:

1
vagrant sandbox rollback

最後要離開沙盒模式:

1
vagrant sandbox off

相對 vagrant snapshot 指令,Sahara 只有一個沙盒狀態的模式是比較受限的。但大部分的實驗環境都是從一個基準環境 (baseline) 開始,實驗完畢後就恢復到原先狀態。所以,Sahara 應該還算是實用的工具。

Sahara
a plugin for vagrant that allows you manage a sandbox state

安裝 Vagrant-env 插件

Vagrant-env 插件讓 .env 檔案內定義的環境變數可以從 Vagrantfile 中存取。

1
vagrant plugin install vagrant-env

此插件是為了支援 spk-cluster-lab 的需要,一般情況並不會用到。

Vagrant-env
Vagrant plugin to load environment variables from .env into ENV

小結

如果需要跨桌面系統 (Windows, Linux, OS X) 平台提供統一的虛擬環境, Vagrant+VirtualBox 是比較推薦的方案,例如 spk-cluster-lab 作為教學與練習使用的實驗環境。 對於希望有比較好的執行效能或者實際環境已經有使用 KVM,Vagrant+Libvirt 會是比較有吸引了的選擇。