2018年7月6日 星期五

在 ubuntu 18.04 底下為 kvm 打造的虛擬區域網路

[2020/9/3 改推薦採用 netplan 設定 bridge 搭配 virt-manager 會比本文簡單很多。]

Ubuntu 18.04 Bionic Beaver 的網路設定改用 netplan 取代舊的 /etc/network/interfaces 設定方式。 如果只是單純的固定 IP 或 DHCP, 據說設定很簡單。 可是我想採用類似 手工精簡版 的方式來幫未來的 qemu-kvm guests 設定獨立式或可橋接外界的虛擬區域網路。 暫時沒有力氣學 netplan, 所以就照著 這個問答 強制改成舊的設定方式比較簡單。 但若不小心, 有可能會在開機時無限等待 dhcp 服務。 以下是我的 lubuntu 18.04 最終網路設定, 及一些有助除錯的筆記。

一、 懷舊網路設定

首先安裝幾個套件: apt install ifupdown2 bridge-utils qemu-kvm。 再來把 /etc/network/interfaces 改成類似這樣:

# interfaces(5) file used by ifup(8) and ifdown(8)
auto lo
iface lo inet loopback

iface enp0s3 inet manual

auto brext
iface brext inet dhcp
        bridge_ports enp0s3
        bridge_stp off
        bridge_fd 0

auto br29
iface br29 inet static
    address 192.168.29.254
    netmask 255.255.255.0
    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 brext -j MASQUERADE
    post-down iptables -t nat -D POSTROUTING -s '192.168.29.0/24' -o brext -j MASQUERADE

其中的 brext (任意自取的名稱) 是對外的 bridge, 透過實體網卡 enp0s3 (在你的系統上, 名稱可能不一樣! 請用 ip link 查看並把幾處 enp0s3 都改掉) 向實體網路請求 dhcp; 而 br29 則是對內的區網名稱, 由 brext 幫它做 NAT。 等一下我們可以決定要讓所有的 qemu/kvm 虛擬機通通加入對外的 brext 或是通通加入對內的 br29。 (但不能混合。)

注意: 實體網卡 enp0s3 降級變成虛擬網卡 brext 的一個 port 之後, udpcast 龍貓公車 就失效了。

然後照著 askubuntu 的連結做:

ifdown --force -a ; ifup -a
systemctl stop networkd-dispatcher
systemctl disable networkd-dispatcher
systemctl mask networkd-dispatcher
apt-get purge nplan netplan.io

如此一來, 系統將不再採用新的 netplan, 而是採用熟悉的 /etc/network/interfaces 。 用 ip link showip route showbrctl show 三個指令查看, 應該都要看到 brext 才算成功。

二、 開機卡關?

可是! 如果設定錯誤 (例如沒有把 enp0s3 改成正確的網卡名稱) 那麼重新開機時有可能會卡在網路設定:

[ *** ] A start job is running for ifupdown2 networking initailization (??min ??s / no limit)

什麼?! 要等到地老天荒? 後來實際測試發現大約等五分鐘就會放棄了。 不過貴哥連五分鐘的耐性都沒有。 所以用 dpkg -L ifupdown2 | grep systemd 查出設定檔在 /lib/systemd/system/networking.service , 並且看了一下 手冊 問答 得知可以把裡面原來的一句 TimeoutStopSec=30s 改成 TimeoutSec=30s, 也就是不論啟動時或是終止服務時, 最多都等 30 秒。 (不知為什麼, 重開機時發現, 實際上會多等三四秒。)

我自己最常遇到的狀況, 就是實體網卡名稱錯誤。 開機進系統之後, 可以用 ip link 查看真實網卡名稱。 修改過 /etc/network/interfaces 之後, 再用 ifdown --force -a ; ifup -a 重新啟動網路。

其實, 如果在 (grub2 或 extlinux.conf 或 isolinux.cfg 的) 開機命令列上加上 net.ifnames=0 biosdevname=0 那麼網卡名稱就會固定為 eth0。 這對需要到處跑的開光碟或開機機隨身碟特別有用。 詳見 這篇

三、 qemu/kvm 虛擬機融入實體網路

想要使用 qemu/kvm, 標準的做法是採用 virsh 跟 virt-manager。 不過有了上述的網路設定, 就可以省略那兩個龐大的套件, 即使是徒手啟動 kvm 也能用區網。 首先把系統原有的 /etc/qemu-if* 改名或備份。 改用以下簡單的兩句完全取代 /etc/qemu-ifup:

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

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

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

並且 chmod a+x /etc/qemu-if* 開放執行權限。 每當 kvm 指令啟動虛擬機時, 會觸發 /etc/qemu-ifup 把虛擬機的網卡加入 brext, 也就是跟 host 融入外部網路。 如果外部網路本來就有提供 dhcp, 那麼 guest 也一樣會自動取得 IP。 虛擬機關機時, 會觸發 /etc/qemu-ifdown, 把虛擬機的網卡刪掉。

啟動虛擬機時, 必須用 -netdev tap,... 的方式指定網卡, /etc/qemu-ifup 裡面的設定才有用。 詳見 我的免費有線分享器: qemu/kvm 虛擬區網。 簡單地說, 可以把這段加入 ~/.bashrc 裡面:

mykvm() {
  vmid=$1
  shift
  kvm -monitor stdio -vga std -cpu host -device usb-ehci -device usb-mouse -device virtio-net,netdev=net0,mac=52:54:00:12:34:$vmid -netdev tap,id=net0,ifname=tap$vmid "$@"
}

以上設定當中的 -netdev virtio-net,... 指定採用 (效率效高的) para-virtualization 版驅動程式, 但這只適用於 linux guests。 如果是 windows guests 的話, 則必須改成 -netdev e1000,...-netdev rtl8139,...。 登出再登入, 現在可以這樣啟動虛擬機: mykvm 3c -m 2048 -cdrom /some/path/grml64-small-g18B.iso 這裡的 3c 可以想成是一個任選的、 每部虛擬機玀有不重複的 id, 必須是一個二位數十六進位數字, 會變成網卡 mac address 的一部分; -cdrom 後面當然可以是任意的 iso 檔。 這裡推薦的是 我自製的 grml linux。 如果虛擬機的網路不通, 請參考 這篇 除錯。

四、 qemu/kvm 虛擬機躲在隔絕的內網

如果不希望虛擬機融入外網, 而是要躲在與世隔絕的內網, 只透過 NAT 上網, 那就要這樣做:

  1. 把 /etc/qemu-ifup 裡面的 brext 改成 br29
  2. 手動建立 br29: brctl addbr br29
  3. 手動啟動 br29: ifup br29

好像是因為 br29 原本不包含任何 ports, 所以用 ifup -a 啟動所有網路狀置時, 會忽略它? 總之, 最後要用 ifconfig 檢查一下, 確認有看到 br29 以及它的 IP 位址。

如果懶得幫每部虛擬機手動設定固定 IP, 就必須自己在內網裡提供 DHCP。 我的 lubuntu 18.04 裡面已經把 pxe 網路開機伺服器 大致設定好。 只需要在 /etc/dnsmasq.conf 裡面設定這兩句:

interface=br29
...
dhcp-range=br29,192.168.29.31,192.168.29.99,4h

然後重新啟動 dnsmasq 即可: systemctl restart dnsmasq 如果 dnsmasq 無法啟動, 出現 「address already in use」之類的錯誤, 可以用 netstat -tupln | grep :53fuser 53/tcplsof -i :53 查看是誰佔用了 port 53。 (詳見 這篇) 以我而言, 發現是 systemd-resolved.service 佔用了 port 53, 所以把它停掉、 再次啟動 dnsmasq 就 ok 了。

五、 變成 live cd 之後的額外動作

如果你用 debian live 機制 把這個系統打包成開機光碟, 不知為什麼 /etc/network/interfaces 會被蓋掉。 用這張光碟開機之後, 還必須把 squashfs 裡面原始的版本抓出來、 把網卡名稱改正確、 重新啟動網路服務:

sqpath=$(df | grep -Po '\S*\.squashfs')
ip link  # 查看網卡名稱, 假設看到 eth99
sed "s/enp0s3/eth99/g' $sqpath/etc/network/interfaces > /etc/network/interfaces
systemctl restart networking

不需要用 virsh 跟 virt-manager 也能自建 kvm 虛擬機區網, 感覺好像在自己組裝腳踏車, 很有成就感啊!

沒有留言:

張貼留言

因為垃圾留言太多,現在改為審核後才發佈,請耐心等候一兩天。