2017年5月14日 星期日

手工精簡版 qemu-kvm 虛擬區域網路

qemu/kvm 是蠻底層的 linux 虛擬化工具, 只適合用於單一虛擬機的場合。 它固定配 10.0.2.15 的 IP 給虛擬機, 這個 IP 僅供虛擬機自嗨用, 從 host 並不能用這個 IP 連到虛擬機; 。 如果要管理一整群虛擬機, 各自要有 ip、 彼此要能互連, 理論上應該改用 virsh 跟 virt-manager 比較好。 不過這兩者的相依套件蠻多的。 對於喜歡騎腳踏車勝過騎機車/開車的人來說, 其實 「含有多部 kvm 虛擬機的區域網路環境」 還是可以用 qemu/kvm 指令徒手建立出來。

假設從 route -n 查出 host 對外的網卡叫做 enp3s0, 而對外的 gateway 是 192.168.0.1。 本文的目標是要建立一個內部區域網路 192.168.29.0/24, 讓 kvm 虛擬機都連到這個內部網路, 再透過 NAT 上網。 測試環境是 lubuntu 16.04。

一、 建立 bridge

請先安裝 bridge-utils 套件, 否則等一下會出現 Cannot find device "br29" 之類的錯誤。 在 host 的 /etc/network/interfaces 最後面加上這一段:

auto br29
iface br29 inet static
    address 192.168.29.254
    netmask 255.255.255.0
    bridge_ports none
    bridge_stp off
    bridge_fd 0
    post-up echo 1 > /proc/sys/net/ipv4/ip_forward
    post-up iptables -t nat -A POSTROUTING -s '192.168.29.0/24' -o enp3s0 -j MASQUERADE
    post-down iptables -t nat -D POSTROUTING -s '192.168.29.0/24' -o enp3s0 -j MASQUERADE

注意: 請把 enp3s0 改成你的真實網卡名稱。 修改之前, 先用 ip link showip route showbrctl show 三個指令查看並儲存目前網路設定。 修改完之後, systemctl restart ifup@br29service networking restart 或重開機, 然後再次用上述三個指令查看, 應該每句都會看到多出一列 br29。

二、 /etc/qemu-ifup 跟 /etc/qemu-ifdown

把系統原有的 /etc/qemu-if* 改名或備份。 改用以下簡單的兩句完全取代 /etc/qemu-ifup:

#! /bin/sh
echo "setting up tap device $1..." # 這一句僅為幫助除錯。 成功後可刪掉。
ip link set "$1" up
ip link set "$1" master br29

又用以下一句取代 /etc/qemu-ifdown:

#! /bin/sh
ip link set "$1" down

並且 chmod a+x /etc/qemu-if* 開放執行權限。 每當 kvm 指令啟動虛擬機時, 會觸發 /etc/qemu-ifup 設定虛擬機的網卡; 虛擬機關機時, 會觸發 /etc/qemu-ifdown。

三、 在 br29 上面啟動 dhcp 服務

  1. 安裝 dnsmasq 套件。
  2. 編輯 /etc/dnsmasq.conf, 分別在各自適當的地方 (每一句範例註解的位置) 加上這兩句:
    interface=br29
    ...
    dhcp-range=br29,192.168.29.31,192.168.29.99,4h
    
  3. 重新啟動 dnsmasq: systemctl restart dnsmasq

如果 dnsmasq 無法啟動, 出現 「address already in use」之類的錯誤, 有可能是因為跟 network-manager 套件衝突。 請移除 dnsmasq-base (會同時移除掉 network manager)、 重裝 dnsmasq、 再重裝 network-manager 。 詳見 這個問答

四、 啟動 finnix 虛擬機

假設你有 中文版 finnix 光碟 (或原始英文版也可以)。

  1. 啟動虛擬機: kvm -monitor stdio -cdrom finnix-ckhung16c.iso -device virtio-net,netdev=net0,mac=52:54:00:12:34:13 -netdev tap,id=net0,ifname=tap13 這裡的 mac= 跟 ifname= 可以任意取, 但不可以跟其他 kvm 虛擬機重複; 其他部分可以照抄。 啟動時應該要看到 /etc/qemu-ifup 那句 echo 所印出來的除錯訊息。
  2. 開機後, 用 ifconfig 查看 dnsmasq 分配給它的 ip、 用 route -n 查看 dnsmasq 幫忙設定好的 gateway、 用 lynx http://www.eff.org 測試瀏覽網頁。
  3. passwd 更改密碼。
  4. 編輯 /etc/ssh/sshd_config, 找到 PermitRootLogin, 把 without-password 或是 no 改成 yes。
  5. 重新啟動 ssh: service ssh restart

五、 啟動 SystemRescueCD

一定要開第二部虛擬機來測試一下才能完全確定有學會, 因為如果沒設定好, 兩部機器有可能會搶網卡之類的。 比較懶一點的話, 也可以兩部虛擬機都用同一張光碟來開機測試; 不過用不同的光碟會更有感覺。

因為 finnix 蠻久沒更新了, 所以最近我也常改用 SystemRescueCD。 測試步驟大致同 finnix, 只有幾個地方不太一樣:

  1. 它需要 256MB 的記憶體才能跑。 又, 啟動第二部虛擬機時, mac= 跟 ifname= 不能跟先前的重複。 所以完整的指令長這樣: kvm -monitor stdio -m 256 -cdrom systemrescuecd-x86-4.9.6.iso -device virtio-net,netdev=net0,mac=52:54:00:12:34:14 -netdev tap,id=net0,ifname=tap14
  2. 它好像沒裝 lynx 跟 w3m, 所以改用 wget http://www.eff.org 測試網路連線。

最後, 請從 finnix 視窗登入 SystemRescueCD, 又從 SystemRescueCD 視窗登入 finnix, 虛擬區網測試成功!

六、 除錯

如果虛擬機的網路不通, 請 (比方說, 由內向外) 依序檢查:

  1. dhcp 有成功嗎? route -n
  2. 可以 ping 得到虛擬網路的 gateway (br29) 嗎? ping 192.168.29.254
  3. 可以 ping 得到 host 的實體網卡的 IP 嗎?
  4. 可以 ping 得到 host 對外的實體 gateway 嗎?

如果可以 ping 得到 host 的實體網卡的 IP, 但卻出不去, 那就有可能是 iptables 沒設定好。 請下 iptables-save | grep MASQ 檢查 -- 也許對外網卡的名稱打錯了?

七、 補充說明

如果新開的虛擬機並不需要跟其他虛擬機互動, 一樣可以用簡單的 (不含 -device 跟 -netdev 那兩段的) kvm 指令啟動它。 原先預設的 User Networking (SLIRP) 還是有效。 (不要用 ping 測試! 直接用瀏覽器或 ssh 測試。)

上面的 (高效率的 para-virtualization 版驅動程式) -netdev virtio-net,... 只適用於 linux guests。 如果是 windows guests 的話, 則必須改成 -netdev e1000,...-netdev rtl8139,...

如果希望 dnsmasq (根據虛擬機的 mac address) 派送固定的 IP 給特定的虛擬機, 可以在 /etc/dnsmasq.conf 裡加上類似這句。 dhcp-host=52:54:00:12:34:13,192.168.29.13

寫這篇時, 搜尋到 qemu 的 wiki 2015 年的文章 2009 年的文章 等等幾篇。 不過想要把虛擬機群直接接到實體網卡對外網路時, 一直失敗。 反正就算成功了, 也會有 (1) 不適用於 wifi (2) 比較危險 (3) 需要動到真實網卡的設定 等等幾大缺點。 所以最後還是改參考我自己寫的、 解釋得很詳盡的、 已經快忘光的 「我的免費有線分享器」 那篇, 改用 NAT 間接上網比較簡單。

騎腳踏車就是比較辛苦, 不過也特別有感就感啊!

沒有留言:

張貼留言