從 VirtualBox 換到 virt-manager

為了可以使用 KVM,把桌機 Ubuntu (Xubuntu) 上的 VM 都從 VirtualBox 換到 virt-manager 了...

不得不說 VirtualBox 包的很好,很多事情就不用自己繞半天... 在 virt-manager 上面有蠻多東西得自己設定繞開,把 2024 年會遇到的問題整理下來。

首先是權限的部分,裝完 virt-manager 後馬上打開會遇到 virt-manager 說連不到 libvirtd 的問題:「virt-manager can't connect to libvirt」,而最簡單的解法就是重開機,原因是安裝過程中在 /etc/group 增加了 libvirt 的權限,現有的 session 因為權限不夠無法連上 libvirtd。

接下來就是操作介面上的順暢度問題了,預設「Automatically detect from the installation media / source」是勾起來的,但你丟 Windows 的 ISO 進去不一定會偵測到是 Windows 的 ISO,需要把勾勾拿掉,然後自己輸入 win 後才會出現可以選的選項,而不是直接選單選擇... 這邊的 UX 在第一次用的時候還蠻卡的。

另外裡面設定也是有問題的,選擇 Windows XP 會發現網路的設定居然還是用 e1000,導致 Windows XP 抓不到網路卡,需要另外再改成 rtl8139 (不過速度只有 100Mbps)。

最後在 Network selection 的部分,NAT 算是最常用的,不過如果要自己架設 lab 的話 (像是我弄了三台 Ubuntu VM 測各種服務),直覺會設定成 Bridge device,但這邊的 Bridge device 是需要先自己設定好 bridge interface 後再讓 virt-manager 設定掛進去。

所以比較「簡單」的方式 (當時以為比較簡單) 是選擇 Macvtap,然後選擇要用的介面,這樣設定後主機的確可以透過指定的介面連到 Internet 上,但就像設定 Macvtap 時出現的警告,guest 與 host 本機之間是無法溝通的:「In most configuration, macvtap does not work for host to guest network communication.」。

解決的方法還是自己搞 bridge interface,這邊由於 Ubuntu 現在網路都是透過 Netplan 在管理,我是透過「[Wishlist] Support macvlan/macvtap interfaces」這邊提供的 workaround 來解決。

以前是直接在 enps0f0 上面設定 IP address,現在是在 networkd 跑起來就先建立 macvlan0,然後在上面設定 IP address。然後 virt-manager 就可以用 macvtap 到 macvlan0 了,實際測試 guest 與 host 之間也通了...

折騰了一會算是搬過來了,這樣總算是可以在桌機上面跑 android emulator 了,先前硬關掉 KVM 跑了兩次,速度實在是受不了,就跑去 Mac 上開發了,現在這樣好多了...

Ubuntu 上 PPPoE 自動重撥的設定

tl;dr:在設定檔裡面除了 persist 外,還要加上 maxfail 0

中華 HiNet 家用方案有提供固一動七的 IPv4 address 可以用,我自己因為玩 DevOps/SRE 的項目,有個固定 IPv4 address 弄一台便當盒小主機跑個 Ubuntu 系統當 jump server (跳板機) 總是對於防火牆的設定比較友善。

家用方案的固定 IP 在網站上申請完以後,透過 PPPoE 撥號指定另外一組 username 拿到。

我遇到的問題時大多數斷線後會自己重連,但偶而就是不會,這次難得在土城家裡的主機發生,看 log 發現是 pppd 自己 exit 了:(時間是 UTC,大約是 2024/02/22 的早上三點多)

Feb 21 19:09:15 kennel pppd[716]: No response to 4 echo-requests                                                      
Feb 21 19:09:15 kennel pppd[716]: Serial link appears to be disconnected.                                             
Feb 21 19:09:15 kennel pppd[716]: Connect time 7434.5 minutes.                                                        
Feb 21 19:09:15 kennel pppd[716]: Sent 1240056869 bytes, received 1018762497 bytes.                                   
Feb 21 19:09:21 kennel pppd[716]: Connection terminated.                                                              
Feb 21 19:09:21 kennel pppd[716]: Connect time 7434.5 minutes.                                                        
Feb 21 19:09:21 kennel pppd[716]: Sent 1240056869 bytes, received 1018762497 bytes.                                   
Feb 21 19:09:21 kennel pppd[716]: Modem hangup                                                                        
Feb 21 19:10:27 kennel pppd[716]: Timeout waiting for PADO packets                                                    
Feb 21 19:10:27 kennel pppd[716]: Unable to complete PPPoE Discovery                                                  
Feb 21 19:11:32 kennel pppd[716]: Timeout waiting for PADO packets                                                    
Feb 21 19:11:32 kennel pppd[716]: Unable to complete PPPoE Discovery                                                  
Feb 21 19:12:37 kennel pppd[716]: Timeout waiting for PADO packets                                                    
Feb 21 19:12:37 kennel pppd[716]: Unable to complete PPPoE Discovery                                                  
Feb 21 19:13:42 kennel pppd[716]: Timeout waiting for PADO packets
Feb 21 19:13:42 kennel pppd[716]: Unable to complete PPPoE Discovery
Feb 21 19:14:47 kennel pppd[716]: Timeout waiting for PADO packets
Feb 21 19:14:47 kennel pppd[716]: Unable to complete PPPoE Discovery
Feb 21 19:15:52 kennel pppd[716]: Timeout waiting for PADO packets
Feb 21 19:15:52 kennel pppd[716]: Unable to complete PPPoE Discovery
Feb 21 19:16:57 kennel pppd[716]: Timeout waiting for PADO packets
Feb 21 19:16:57 kennel pppd[716]: Unable to complete PPPoE Discovery
Feb 21 19:18:02 kennel pppd[716]: Timeout waiting for PADO packets
Feb 21 19:18:02 kennel pppd[716]: Unable to complete PPPoE Discovery
Feb 21 19:19:07 kennel pppd[716]: Timeout waiting for PADO packets
Feb 21 19:19:07 kennel pppd[716]: Unable to complete PPPoE Discovery
Feb 21 19:20:12 kennel pppd[716]: Timeout waiting for PADO packets
Feb 21 19:20:12 kennel pppd[716]: Unable to complete PPPoE Discovery
Feb 21 19:20:12 kennel pppd[716]: Exit.

這邊算了一下「Unable to complete PPPoE Discovery」出現了十次,這種數字看起來就蠻可疑的,回頭去 pppd 的說明找 10 可以看到這段:

Terminate after n consecutive failed connection attempts. A value of 0 means no limit. The default value is 10.

接著網路上翻,在「How do I set a PPPoE connection to redial?」這邊看到有人也提到了這點:除了 persist 以外,也要記得改 maxfail...

Ubuntu 的 Phased Update

Ubuntu 22.04 上面常常會遇到跑 apt upgrade 時系統跟你說有些 package 不打算升級:

$ sudo apt upgrade
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
Calculating upgrade... Done
The following packages have been kept back:
  python3-distupgrade ubuntu-release-upgrader-core ubuntu-release-upgrader-gtk
0 upgraded, 0 newly installed, 0 to remove and 3 not upgraded.

以往遇到這種情況,如果確定要裝就是開 dist-upgrade 下去,但會發現也還是不為所動:

$ sudo apt full-upgrade
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
Calculating upgrade... Done
The following packages have been kept back:
  python3-distupgrade ubuntu-release-upgrader-core ubuntu-release-upgrader-gtk
0 upgraded, 0 newly installed, 0 to remove and 3 not upgraded.

這個可能是遇到 PhasedUpdates,這個設計是在最後一關推出去的階段,一次不要更新 100% 的機器。

可以從 apt policy 看到現在的比率是 20%:(這是我已經升級上去的樣子)

$ apt policy python3-distupgrade
python3-distupgrade:
  Installed: 1:22.04.18
  Candidate: 1:22.04.18
  Version table:
 *** 1:22.04.18 500 (phased 20%)
        500 http://tw.archive.ubuntu.com/ubuntu jammy-updates/main amd64 Packages
        500 http://tw.archive.ubuntu.com/ubuntu jammy-updates/main i386 Packages
        100 /var/lib/dpkg/status
     1:22.04.10 500
        500 http://tw.archive.ubuntu.com/ubuntu jammy/main amd64 Packages
        500 http://tw.archive.ubuntu.com/ubuntu jammy/main i386 Packages

而對於 LTS 的使用者,這個功能在 APT 的支援是從 Ubuntu 22.04 開始,以前只有桌面的 Update Manager 才有支援,所以不太會遇到:

Up to Focal (20.04), Update Manager is the only package manager that supports phased updates (reference). Any other update mechanism installs all updates regardless of the Phased-Update-Percentage.

(話說 wiki 頁上面可以看到有「User stories」這段,用 User story 的格式把這個功能的目的描述出來了)

所以一般人可以忽略掉,而對於有意願想要幫忙測試的人,也可以透過設定蓋過 Phased Updates 的比例設定...

查詢 Debian 與 Ubuntu 官方的 apt repository 的版本資訊

因為在寫「Python 3 的支援週期」這篇時需要查不同作業系統版本下的 python3-minimal 版本資訊,一開始是到 packages.ubuntu.com 上查,但上面只列出了目前還有支援的作業系統的套件。

所以就到 Ask Ubuntu 上面問:「How to search package information on unsupported Ubuntu distribution」。

看起來有兩個方法可以拉到歷史資料,一個是 devscripts 裡面的 rmadison,直接帶入要查的套件名稱就可以了:

$ rmadison python3-minimal

另外一個是到 https://ubuntu-archive-team.ubuntu.com/madison.cgi 這邊查,這個位置也是 rmadison 預設的 backend,資料應該是一樣的。

而加上 -u debian 可以改查 Debian 這邊的資訊,用 -h 可以看到還有那些 alias 可以用。

目前 Ubuntu 這邊可以查到最舊的版本是 trusty (14.04),如果要更舊的版本資訊,需要去 launchpad.net 上面翻,像是 https://launchpad.net/ubuntu/precise/+package/python3-minimal 這個。

玩了一下 OpenSnitch,Linux 下的 Application Firewall

這是在 Hacker News 上的討論「Brute-forcing a macOS user’s real name from a browser using mDNS (fingerprint.com)」這篇看到的,裡面一開始是提到 Mac 上面的 Little Snitch,可以針對特定應用程式設定防火牆規則,而在 Linux 上對應的解決方案則是 OpenSnitch,但一直沒有嘗試,所以就試著用看看...

套件分成兩個部分,一個是 OpenSnitch 的主程式,另外一個是 GUI 的部分。

而在 Ubuntu 22.04 上裝有點麻煩,因為 Ubuntu 22.04 上預設的 grpc package 似乎是有 bug,需要裝新版解決。

不過我在找 PPA 的時候發現有人包了輔助套件:「OpenSnitch - application firewall (Xenial & newer)」。

這個套件本身是沒有包 OpenSnitch 主程式與 GUI 套件的,他只是要「補充」官方套件安裝的問題,所以需要照他的說明安裝:(我把下面指令提到的 1.5.2 換成目前新版的 1.6.0 裝,目前看起來是會動的)

sudo add-apt-repository ppa:savoury1/opensnitch
sudo apt-get update && sudo apt-get upgrade
sudo dpkg -i opensnitch_1.5.2-1_amd64.deb
sudo dpkg -i python3-opensnitch-ui_1.5.2-1_all.deb
sudo apt-get -f install

這邊用 dpkg -i 裝,而不是用 apt install 的原因是故意讓他不裝 dependency,等到後面的 apt-get -f install 時再裝 PPA 裡面提供的 dependency。

裝好後把跑 opensnitch-gui 起來後就會陸陸續續收到系統內不同的應用程式嘗試的連線,像是官網提供的 screenshot 這樣 (會跳出像左邊這樣的視窗):

這樣可以控的比較細,不過剛開始用會需要花時間把系統內常態性的 request 先設定過一次,還蠻煩的 XD

XFCE (Xubuntu) 下的手動 lock + screensaver + DPMS 組合

桌機換成 Xubuntu 22.04 後會遇到手動鎖定螢幕時,螢幕不會進入省電模式,遇到的情況有點像是「DPMS Suspend on Screen Lock」這邊提到的情境。

這類問題如果用 search engine 一時間沒有找到解法的話,最好的方法都是直接去讀 source code,然後就發現透過 Ctrl+Alt+L 觸發的 /usr/bin/xflock4 其實是個 shell script,從 code 讀可以發現裡面只負責 lock 的部分,本來就跟 DPMS 無關。

我在下面提供的方案就是自己處理螢幕的部分,也就是自己先跑 DPMS 指令,然後再回頭呼叫 /usr/bin/xflock4

#!/bin/sh
/usr/bin/xset dpms force off
exec /usr/bin/xflock4

Ctrl+Alt+L 的觸發程式掛上來,這樣就會正常處理了...

用 aptitude 找出合適的降版組合

在跟 Nvidia 提供的各種驅動程式以及套件奮戰,結果遇到經典的 apt 每次都講的不明不白的老問題,像是依照「NVIDIA Deep Learning TensorRT Documentation」這篇的說明,你需要指定需要的版本安裝對應的套件,像是我這邊就是要裝 CUDA 11 的版本,但系統就跟你說不能裝:

sudo apt install tensorrt=8.5.3.1-1+cuda11.8
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
Some packages could not be installed. This may mean that you have requested an impossible situation or if you are using the unstable distribution that some required packages have not yet been created or been moved out of Incoming.
The following information may help to resolve the situation:

The following packages have unmet dependencies:
 tensorrt : Depends: libnvinfer8 (= 8.5.3-1+cuda11.8) but 8.6.1.6-1+cuda12.0 is to be installed
            Depends: libnvinfer-plugin8 (= 8.5.3-1+cuda11.8) but 8.6.1.6-1+cuda12.0 is to be installed
            Depends: libnvparsers8 (= 8.5.3-1+cuda11.8) but 8.6.1.6-1+cuda12.0 is to be installed
            Depends: libnvonnxparsers8 (= 8.5.3-1+cuda11.8) but 8.6.1.6-1+cuda12.0 is to be installed
            Depends: libnvinfer-bin (= 8.5.3-1+cuda11.8) but 8.6.1.6-1+cuda12.0 is to be installed
            Depends: libnvinfer-dev (= 8.5.3-1+cuda11.8) but 8.6.1.6-1+cuda12.0 is to be installed
            Depends: libnvinfer-plugin-dev (= 8.5.3-1+cuda11.8) but 8.6.1.6-1+cuda12.0 is to be installed
            Depends: libnvparsers-dev (= 8.5.3-1+cuda11.8) but 8.6.1.6-1+cuda12.0 is to be installed
            Depends: libnvonnxparsers-dev (= 8.5.3-1+cuda11.8) but 8.6.1.6-1+cuda12.0 is to be installed
            Depends: libnvinfer-samples (= 8.5.3-1+cuda11.8) but 8.6.1.6-1+cuda12.0 is to be installed
E: Unable to correct problems, you have held broken packages.

以前比較簡單的套件可以用 apt-cache showpkg 慢慢看組合自己解,但這種巨大套件實在沒辦法。

在「How do I resolve `The following packages have unmet dependencies`」這邊則是有提到這個問題,下面有給個一般性的通解:用 aptitude 提供降版的組合,每一套組合你都可以選 n 讓他提供另外一套組合,直到你覺得這套組合 OK 了再選擇 y 讓他裝起來。

然後裝完以後記得用 apt-mark hold 把主套件的版本固定住,避免 upgrade 的時候又被搞中爛掉出事。

OpenSSH 與 Dropbear 對 Ed25519 的支援

查了一下這兩個 server 端的軟體支援 Ed25519 的時間點。

OpenSSH 是在 2014/01/30 的 6.5 就支援了:

* ssh(1), sshd(8): Add support for Ed25519 as a public key type. Ed25519 is a elliptic curve signature scheme that offers better security than ECDSA and DSA and good performance. It may be used for both user and host keys.

算是相當久以前就支援了。對應到第一個支援的 Debian 版本是 Jessie 使用的 OpenSSH 6.7:「sshd(8) — openssh-server — Debian jessie — Debian Manpages」;第一個支援的 Ubuntu (LTS) 版本是 Trusty (14.04) 用的 OpenSSH 6.6:「openssh source package in Trusty」。

Dropbear 這邊就晚不少,在 2020/06/15 的 2020.79 版本才支援:

- Support ed25519 hostkeys and authorized_keys, many thanks to Vladislav Grishenko. This also replaces curve25519 with a TweetNaCl implementation that reduces code size.

所以對應到第一個支援的 Debian 版本是 Bullseye 的 2020.81:「Debian -- Details of package dropbear in bullseye」;第一個支援 Ubuntu (LTS) 的版本是 Jammy (22.04) 的 2020.81:「Ubuntu – Details of package dropbear in jammy」。

這樣看起來如果就是想要用 Ed25519 的話,變成 server 端的軟體得配合:預設裝的 sshd 應該都是 OpenSSH,如果想要換 Dropbear 的話要看 distribution 內給的版本夠不夠新,或是透過 PPA 之類的方法裝新版。

但大多數採用 BusyBox 的機器應該沒有採用新版 Dropbear (像是 AP 刷機),這邊還是得使用其他 key format,如果要避開 NIST 有介入的格式,就還是得用 ssh-rsa 了。

在 PPA 裡面只安裝特定軟體的方式

Ubuntu 20.04 的 rsync 內建只有 3.1.3 (參考「Ubuntu – Package Search Results -- rsync」這邊),但 --mkpath 這個參數需要 3.2.3+ 才能跑:「How can I configure rsync to create target directory on remote server?」,所以就要找 PPA 看看有沒有人有包新版的可以用。

在「Utilities - various (Xenial & newer)」這邊可以看到 Rob Savoury 有包,但發現這包有一堆軟體,我不想要裝這麼多,所以就用 Pinning 限制。

apt-cache policy 可以看到 o= 的值,然後就可以在 /etc/apt/preferences.d/savoury1-utilities 裡設定 rsync 的 Pin-Priority1001,而其他的都掛到 -1

Package: *
Pin: release o=LP-PPA-savoury1-utilities
Pin-Priority: -1

Package: rsync
Pin: release o=LP-PPA-savoury1-utilities
Pin-Priority: 1001

但跑 apt upgrade 沒看到可以升級,而直接 apt install rsync 的時候可以看到是因為 libxxhash0 跟不上新版而產生錯誤訊息:

The following packages have unmet dependencies:
 rsync : Depends: libxxhash0 (>= 0.8.0) but 0.7.3-1 is to be installed
E: Unable to correct problems, you have held broken packages.

所以一起加進去變成:

Package: *
Pin: release o=LP-PPA-savoury1-utilities
Pin-Priority: -1

Package: libxxhash0 rsync
Pin: release o=LP-PPA-savoury1-utilities
Pin-Priority: 1001

然後就可以 apt upgrade 升級上去了。

用 reprepro 建立 APT repository

在「用 fpm 這個工具包 .deb 安裝」這篇題到了 fpm,另外在同一篇文章裡面 (「Using Cloudflare R2 as an apt/yum repository」這篇) 也有提到要怎麼生出一個有簽名過的 APT repository,裡面就提到了 reprepro 這個工具。

Debian Wiki 上面的「SetupWithReprepro」就有一步一步告訴你設定的方式,另外 Wikimedia 的技術 wiki 上也有提到常用的操作:「Reprepro」。

然後可以丟到很多不同的地方,最常見的 apache 或是 nginx 外,S3 或是其他可以吐 HTTP/HTTPS 的 object storage 服務都可以。

也是先記錄起來,等要用的時候可以回來 blog 上翻到...