この記事では、レスキューや持ち運び環境などの目的で、VentoyをインストールしたUSBメモリに共存させる形で他のLinuxを入れるときの雑多な注意点などを紹介します。
それにあたって、UEFI(セキュアブート有/無)、Legacy BIOSという新旧の環境に対応できるようにしてみたかったので、まずはこの2つの特徴を簡単に説明してから、細かい注意点について書きます。
Legacy BIOS
Legacy BIOSは2010年代くらいまでの古い方式です。以下のような特徴があります。
- ディスク形式がGPTではなく古いMBR(msdos)方式である必要がある
- 起動プロセスとしては、ディスク先頭のMBR領域にあるコードが最初に呼ばれる。MBR直後の空き領域(MBR gapやpost-MBR gapなどとも呼ばれる)やパーティションの先頭であるPBRが補助的に使われる場合も
- (そもそも古いマシンが多いので、今回の記事ではメモリなども少なめの環境を想定)
UEFI
UEFIは新しい方式で、ファームウェア(UEFI BIOS)側でやってくれることが結構多いので全体に見通しは良くなりますが、セキュアブートが厄介です。詳しくはWindows・Linuxにおけるセキュアブートと関連ツール(shim・MOK)、およびセキュアブートやTPMの効果について - turgenev’s blogを参照。
- FAT形式のEFIシステムパーティションにあるEFIバイナリが呼ばれることで起動が開始する
- ディスク形式はMBRでもGPTでもよい
- セキュアブートが有効(ここではWindows機として販売されているもののみ想定する)な場合:
USBの構成の概要
これらの環境に対応するため、例えば以下のような構成にすることにします。
- パーティション形式はMBRディスクとして、Ventoyをインストール
- 主にLegacy BIOS向けに32bitの軽量なLinuxをインストールする。この記事ではantiXを想定
- 主にUEFI BIOS向けに64bitの中量級くらいのLinuxをインストールする。ただし、MOKが動作しない機種でも使うことを考え、ブートローダー・カーネルに署名が付いているものにしたい。Debian系・RHEL系・openSUSEなどが候補になる。個人的には、普段だったらLinux Mintにするところだが、RHEL系を使ってみたかったのでCentOS Streamを入れてみることにした。
- Legacy BIOS・UEFIどちらにおいても、Linux側のGRUBが最初に出るようにして、そこから必要に応じてVentoyも起動できるようにする。
パーティション構成
まずVentoyを入れるので、先頭2つは基本パーティション(=拡張パーティションではない)にする必要があります(ちゃんと調べてないですが、多分)。で、2つ目がEFIシステムパーティション(VTOYEFI)になるのですが、Ventoyはこれを32MBちょうどしか取ってくれずそのうち28MBくらいを使ってしまうので、他のLinuxを入れるためのEFIシステムパーティションとしては使い物になりません。
そこで、先頭のパーティション(Ventoy用のisoとかを置くところ)を100-200MBくらいのEFIシステムパーティション(フォーマットはFAT32)にして、2つ目はbootやespなどのフラグは付けないこととします。これでもVentoyは問題なく動きます。
この2つ以外はLinuxを普通に入れるのに使うだけなので全部論理パーティションにしてしまってもいいですし、あと1個基本パーティションを作れるのでそこを何か別の用途に使っておくのもいいでしょう。
ちなみにUSBメモリのサイズはなんでもいいですがLinuxを2つ入れるので最低でも32GBくらいはあると気持ちに余裕があるのではないでしょうか。
Ventoyのインストール
ディスクの後ろを空けてVentoyをインストールするのは公式にサポートされているので詳しくは書きません。無理やりな感じでインストールしたい場合はVentoyを使用中のUSBメモリに無理やりインストールする方法 - turgenev’s blogも読んでみてください。
VirtualBox経由でインストール
これは具体的な手順というわけではないのですがこの後書く内容に共通して言えることなので先に書いてしまいます。
一般にUSBメモリというのはランダムアクセスが遅く、特に悪い製品(KIOXIAとか)だと0.1MB/sを切るようなあり得ないランダム書き込み速度しか出ないものもあります。一方でシーケンシャル(連続)アクセスはそこそこ速いです。が、当然いまどきのSSDとかよりはだいぶ遅いです。
LinuxをUSBに直接インストールするとなると、パッケージの展開のみならず、一時ダウンロード先としてもUSBメモリが使われる可能性があり、無駄に読み書き時間がかかります。
一方で、Virtualboxの仮想ハードディスクに一旦インストールしてからパーティションごとUSBメモリにコピーすると、USBが使われるのがそのコピー操作(アクセスとしてはシーケンシャルになるはず)だけになるので、まあまあな速度が出ます。VDIをimgファイルとかに変換してddで焼いてもいいですし、面倒ならVirtualboxのUSBパススルーを使ってもいいです(GPartedでGUI操作も可能)(多少のオーバーヘッドはあります)。自分の環境では実測シーケンシャル書き込み15MB/sくらいのUSBでVirtualboxのパススルーだと6MB/sくらい出ました(ランダム書き込みは実測1MB/s)。
Virtualboxへのインストール自体はSSD上の仮想ディスクファイルを使っていればかなり速いです。小さめのディストリビューションなら1分とかで終わるような感じです。
あと、USBに焼く前に試しに動かせるとか、余計なパッケージを消しておくことができるとか、インストール時にまっさらなディスクから始められるので間違って既存のLinuxに上書きインストールしてしまうリスクが無いといった副次的なメリットもあります。
というわけで、結構おすすめの手法。
パーティションのコピーをしたらデバイス番号とかが変わってしまうのでは?と思うかもしれませんが、最近はUUIDで見てくれているので意外と大丈夫なことも多いです。
ちなみにVirtualboxのUSBパススルーだと、UEFIの場合はUSBからブートできますがLegacy BIOSモードだと無理っぽいです。
Linux側のGRUBを最初に起動する(UEFIの場合)
多分技術的にはメインといえる、VentoyではないLinux側のGRUBを最優先で起動する設定についてです。
といってもUEFIの場合は簡単です。
基本的にUSBメモリをUEFI BIOSメニューで選んで起動した場合は、EFIシステムパーティションにある\EFI\BOOT\BOOTX64.EFI(x86_64の場合)が呼び出される決まりになっています。
なので、Ventoy本来のEFIパーティション(VTOYEFI)の\EFI\BOOT\BOOTX64.EFIにはVentoy用のEFIバイナリ(ちなみにVentoyも基本的にはGRUBがベースになっています)が配置されています。
しかし今回はすでにVTOYEFIからboot, espラベルを外して最初のパーティションに付け替えています。なのでそっちの\EFI\BOOT\BOOTX64.EFIにLinux(CentOS Stream)側のGRUB(shim)をインストールすればOKです。
grub-installに--removableオプションをつけると、リムーバブルディスク想定になり、\EFI\BOOT\BOOTX64.EFIにインストールしてくれます。ブート順の変更も行わなくなります。
さらに、このGRUBにVentoyを呼び出すメニューを追加します。内容としては、VTOYEFIにあるBOOTX64.EFIを起動するmenuentryを追加するだけです。
GRUBにカスタムのメニューを追加する際は、Ubuntu系でもRHEL系でも、/etc/grub.d以下のファイルを使います。自分の場合は、41_customというファイルがこんな感じでした。
#!/usr/bin/sh
cat <<EOF
if [ -f \${config_directory}/custom.cfg ]; then
source \${config_directory}/custom.cfg
elif [ -z "\${config_directory}" -a -f \$prefix/custom.cfg ]; then
source \$prefix/custom.cfg
fi
EOF
このファイルの実行結果が最終的なgrubの設定ファイル(/boot/grub以下)に書き出されていきます。
そこで、EOFの手前に以下のような内容を追加します。
if [ "\$grub_platform" = "efi" ]; then
menuentry "Ventoy" {
search --no-floppy --set=root --fs-uuid XXXX-YYYY
chainloader /EFI/BOOT/BOOTX64.EFI
}
fi
UEFIブートの場合のみ、UUIDで検索したVTOYEFIパーティションのBOOTX64.EFIを起動するメニューを追加します。UUIDのところはblkidやGPartedなどで調べます。
シェルスクリプトとして評価されるため、\$grub_platformと$をエスケープしていることに注意してください。
書き終わったらgrub2-mkconfig(あるいはUbuntu系ならupdate-grub)で設定を更新しましょう。
- 追記訂正: 上記の41_customを見ればわかりますが、/boot/grub(つまりgrub.cfgがあるところ)にcustom.cfgを置いておけばその内容がgrub2-mkconfigなどしなくても直接grubに反映されます。また40_customというファイルもあり、こちらは
#!/bin/sh
exec tail -n +3 $0
で始まっていてエスケープを気にせずメニュー内容を直接書けます(grub2-mkconfigなどは必要)。前述の41_customの使い方は明らかにベストではないのでやめましょう。スクリプト内容は\$を$に戻す以外はそのままです。
ちなみにrootというのはGRUBにおいての特殊な変数名のようなもので、特に何も指定がなければこのrootからファイルパスをたどります。別の言い方をすれば、chainloader /EFI/BOOT/BOOTX64.EFI は chainloader ($root)/EFI/BOOT/BOOTX64.EFI と同じ意味になります。多分。
CentOS Streamのmenuentryの内側でrootが設定されない問題
また、自分が試したCentOS Streamのgrub2-mkconfigでは、CentOS Streamのmenuentryの内側にrootを設定するコード(典型的にはsearchでUUIDを探すもの)が含まれておらず、外側で正しくroot変数が設定されていることを仮定して(たとえば($root)/boot/vmlinuz-6.8.0-....のように)カーネルを呼び出すものになっていました。このため、
if [ "\$grub_platform" = "efi" ]; then
search --no-floppy --set=root --fs-uuid XXXX-YYYY
menuentry "Ventoy" {
chainloader /EFI/BOOT/BOOTX64.EFI
}
fi
このようにroot変数の設定をVentoyのmenuentryの外側に書いてしまうと、CentOSのmenuentryの内側が評価されるタイミング(メニューを選んだ後)ではrootの値が異なっており起動できなくなってしまいます。
また、rootの設定を行う別のmenuentryを起動したもののエラーなどでGRUBに戻ってきてしまった場合にも同様の問題が発生します。
(少なくとも自分が使っている最近の)Linux Mintではmenuentryの内側でrootを探してくれるのでこのような問題は起こりません。
Linux側のGRUBを最初に起動する(Legacy BIOSの場合)
Legacy BIOSの場合は少し面倒です。なぜなら、Ventoyを使う以上はMBRの内容は書き換えられない(前述の過去記事参照)ので、USBからの起動時に最初にVentoyが呼び出されるということ自体は絶対に変えられないからです。
しかし、Ventoyではデフォルトの起動メニューを指定することはできます。これを使ってLinux側のGRUBを即座に呼び出してしまえば良さそうです。
そうすると、こんどはLinux側のGRUBからVentoyを呼び出したときにもまたすぐにLinux側に切り替わってしまうという問題が発生します。
そこで、環境変数(grubenv)を使用して、条件によって起動しかたを変えることにします。
また、MBRはVentoyが使っているのでLinux側のGRUBはPBRにインストールすることになります。
では具体的な設定方法に移ります。
Ventoyはgrubベースですが、Ventoyのメインのメニュー(isoとかを勝手に検索して追加してくれる)は大幅なカスタマイズがなされていて、こちら側に手を出すことはできません。
そのかわり、メインのものとは別にカスタムメニューを設定することができて、メイン画面でF6を押すとそれを呼び出すことができます。これを利用します。
カスタムメニューは、1番目のパーティションの/ventoy/ventoy_grub.cfgというファイルで設定します。ちょっと長いんですが、以下のように書きます。
search --no-floppy --set=env_partition --fs-uuid XXXX-YYYY
echo $env_partition
load_env -f ($env_partition)/ventoy/grubenv
menuentry "Halt" {
halt
}
if [ "$grub_platform" = "efi" ]; then
menuentry 'Default' --class=vtoyret VTOY_RET {
echo 'Return ...'
}
menuentry 'UEFI Setup' {
fwsetup
}
elif [ "${request_ventoy_boot}" = "1" ]; then
set request_ventoy_boot=0
save_env -f ($env_partition)/ventoy/grubenv request_ventoy_boot
menuentry 'Default' --class=vtoyret VTOY_RET {
echo 'Return ...'
}
else
menuentry "Default" {
search --no-floppy --set=root --fs-uuid xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
chainloader +1
boot
}
fi
haltのメニューは気分で追加してみただけです。
この「Default」という名前のメニューが重要です。request_ventoy_bootという変数が1のとき(またはUEFIモードのとき)は、「Default」メニューは、Ventoyのメインメニューに戻るだけのものになります。つまり最初からメインメニューが表示されているように見えます。
しかし、(Legacy BIOSモードかつ)request_ventoy_bootが0(1以外)のときは、Linux側のGRUBを呼び出すメニューになります。該当のパーティションをUUIDで検索してchainloader +1とすることでPBRからの起動になります。
環境変数は/ventoy/grubenvというファイルで設定しています。これはただのテキストファイルではあるのですが、一応専用の書式があるので、grub-editenvといったコマンドで生成させる必要があります。場所はどこでも構いません。
そして、Ventoyのデフォルトのメニューは1番目のパーティションの/ventoy/ventoy.jsonというファイルで設定します。ここに以下のように書きます。
{
"control":[
{"VTOY_DEFAULT_IMAGE":"F6>Default"}
]
}
このF6というのは特殊な識別子で、F6キーを押したときのメニュー、つまりカスタムgrubメニューを指します。これにより、先ほどの「一瞬でLinux側のGRUBに遷移するが、request_ventoy_bootが1のときだけメイン画面を表示する」というメニューがデフォルトに設定されます。
さらに、Linux側のGRUBでもUEFIの場合と同様にVentoyを呼び出すmenuentryを追加しますが、ここでrequest_ventoy_bootを1にするようにします。以下のように/etc/grub.d/41_customの最後の方("EOF"の手前)に追記します。
if [ "\$grub_platform" = "pc" ]; then
search --no-floppy --set=env_partition --fs-uuid XXXX-YYYY
menuentry "Ventoy" {
set request_ventoy_boot=1
save_env -f (\$env_partition)/ventoy/grubenv request_ventoy_boot
regexp --set=root '^(hd[0-9]+),' \$env_partition
chainloader +1
}
fi
- これも先ほどと同様、40_customか/boot/grub/custom.cfgを使うことを推奨します。
同じgrubenvファイルを使うのでパーティションのUUIDもさっきと同じです。
regexpを使って、env_partition変数(たとえばhd0,msdos1などと設定される)からディスク名だけ(たとえばhd0など)を取り出してrootに設定することで、chainloaderでUSBメモリのMBRをロードさせています。
CentOS Streamでのセキュアブート対応の問題
CentOS Stream自体は基本的にセキュアブートに対応しているはずなのですが、grub2-installコマンドを使うと
This utility should not be used for EFI platforms because it does not support UEFI Secure Boot
みたいなよくわからんエラーが出ます。Fedora 35 をBIOS/MBRからGPT/UEFIの起動に切り替えた際のメモ #Linux - Qiitaこのへんに書いてある通りdnf reinstall shim-* grub2-efi-*などとするのが正しいっぽい?あるいは最初のインストールのときのファイルが残っているならそれを手動でコピーしたり名前を変更したりするのでも問題ありません。
Ventoyでセキュアブートを迂回するにあたっての注意
VentoyはMOKによってセキュアブートを迂回しますが、Ventoyから別のshimを呼び出してそこのGRUBメニューから未署名カーネルを起動しようとしたりすれば弾かれることになります。このへん詳しくは最初に貼った過去記事を読んでください。
PBRへのGRUBのインストールに関する注意
この記事のLegacy BIOS向け設定のためにはGRUBをPBRに入れることが必要ですが、これは若干問題点があります。
GRUB/Tips and tricks - ArchWikiに書いてある通り、PBRに入れた場合は、GRUBの本体(core.img)の場所がblocklist(パーティションにおけるデータの位置のようなもの)を使って指定されます。しかしデータの位置はファイルの移動・削除などによって予測できないタイミングで変わってしまう可能性があり、そうするとGRUBが起動しなくなります。従って--forceを指定しないとPBRにはインストールできません。
位置の変動を防ぎたい場合、数MB程度のGRUB専用のパーティションを設けるという方法はアリかもしれません。
MBRの場合はcore.imgにあたる内容をMBR gapに書くことができるので大丈夫みたいです。
カーネルが新しめのディストリビューションを選ぶ
セキュアブート有効・MOK非対応という前提だと、カーネルはディストリビューション側が公式にビルドしたものしか使えません。
レスキュー用なので新技術を試したいといった需要は少ないと思いますが、カーネルのバージョンが古いと新しめのハードウェアを認識できない場合があります。
従って、レスキュー用としては、署名付きのカーネルのリリースが早いディストリビューション(全然詳しくないですが、Fedoraが多分最速で、UbuntuのHWEもまあまあ、openSUSE Tumbleweedとかも速い?)を1つ入れておくという選択肢はありだと思います。
またこれはディストリビューションによらない制約ですが、MOKが動かない場合は、ライセンスの問題でカーネルに含められない一部のモジュール(NVIDIA・Broadcom・VMware・VirtualBox関連など)は動作しなくなります。