QEMUでVMを起動する
目標
用意されたディスクイメージでQEMUのVMを実際に起動し、シリアルログ・モニターソケット・hostfwdのリッスンソケットの3つで、生きていることを証明します。
なぜ重要なのか
実務ではlibvirtやクラウドコンソールを使いますが、問題が起きると、結局はその下のQEMUのコマンドラインを読む必要があります。-netdev(ホスト側のバックエンド)と-device(ゲストが見るNIC)がなぜ分かれているのか、format=をなぜ明示するのか、hostfwdのリッスンソケットがゲストの起動と無関係にすぐ開く理由は何なのか。こうしたことは、コマンドラインを自分で書いてみて初めて身につきます。
このラボは、仮想マシンの中で動き、その中でさらに仮想マシンを起動します。ネステッド仮想化が有効になっているので、/dev/kvmがあり、QEMUがハードウェアアクセラレーションをそのまま使います。\n\n以前はPodの中で動いていて/dev/kvmがなく、QEMUが命令を1つずつ変換するTCGソフトウェアエミュレーションだけで動いていました。ゲストがログインプロンプトまで来るのに数分かかったため、ラボは「ファームウェアが起動したか」までしか見られませんでした。\n\nアクセラレーターは、あるものを選んで使ってください。-accel kvmと-accel tcgでは、数十倍の差が出ます。実務でも順序は同じです。まず/dev/kvmがあるかを見て、あればそれを使います。採点ツールも、このマシンに何があるかを見て、それに合わせて判定します。
ステップ
/root/vmbootディレクトリを作成し、/opt/vm/の下に用意されたディスクイメージのqemu-img infoの出力を/root/vmboot/base-info.txtに保存してください。- そのイメージをバッキングにするオーバーレイ
/root/vmboot/vm.qcow2を作成してください。元は変わってはいけません。 /root/vmboot/run.shを作成してください。次の要素がすべて入っている必要があります。qemu-system-x86_64-accel tcg-m 512-smp 1-drive file=/root/vmboot/vm.qcow2,if=virtio,format=qcow2-netdev user,id=n0,hostfwd=tcp::12222-:22-device virtio-net-pci,netdev=n0-nographic-serial file:/root/vmboot/console.log-monitor unix:/root/vmboot/mon.sock,server,nowait
- 使用可能なアクセラレーターの一覧と
/dev/kvmの有無を、/root/vmboot/accel.txtに次の2行で書いてください。ACCELS=<쉼표로 구분한 가속기 목록>/DEVKVM=<yes|no>(プレースホルダーは、カンマで区切ったアクセラレーターの一覧です) run.shをバックグラウンドで実行して20秒以上待ったあと、/root/vmboot/console.logにファームウェアのメッセージが残っているかを確認してください。ログにSeaBIOSまたはBootingという文字列がある必要があります。- モニターソケットに
info statusを送り、応答を/root/vmboot/monitor.txtに保存してください。応答にrunningまたはpausedが見える必要があります。 12222ポートがリッスン中かを確認して、/root/vmboot/hostfwd.txtに保存してください。プロセスがqemuと見える必要があります。/root/vmboot/report.txtを次の5行で作成してください。ACCEL=tcg/MEM=512/VCPU=1/FWD_PORT=12222/DISK_IF=virtio
参考
qemu-system-x86_64 -accel helpで、アクセラレーターの一覧を見ます。- バックグラウンド実行は、
nohup bash /root/vmboot/run.sh >/root/vmboot/qemu.out 2>&1 &の形で行います。 - モニターへの問い合わせは
printf 'info status\n' | nc -U /root/vmboot/mon.sockです。応答が来なければ、-q 1で終了までの時間を与えてください。 - よくある間違い1:
run.shの中でQEMUをバックグラウンドに送ると、採点時に引数のパースが難しくなります。スクリプトはフォアグラウンドで実行するように書き、バックグラウンドにする処理は、実行するときに行ってください。 - よくある間違い2: オーバーレイなしで元を直接使うと、もう一度ラボをやるときに、状態が汚れます。
用意されたイメージの確認
/root/vmbootディレクトリを作成し、/opt/vm/の下に用意されたディスクイメージのqemu-img infoの出力を/root/vmboot/base-info.txtに保存してください。
/opt/vmの下に、用意されたイメージがあります。フォーマットと仮想サイズを先に確認してください。
オーバーレイで元を守る
そのイメージをバッキングにするオーバーレイ/root/vmboot/vm.qcow2を作成してください。元は変わってはいけません。
元をバッキングにするオーバーレイを作れば、元は変わりません。バッキングのフォーマットを明示するのを忘れないでください。
実行スクリプトの作成
/root/vmboot/run.shを作成してください。次の要素がすべて入っている必要があります。
qemu-system-x86_64-accel tcg-m 512-smp 1-drive file=/root/vmboot/vm.qcow2,if=virtio,format=qcow2-netdev user,id=n0,hostfwd=tcp::12222-:22-device virtio-net-pci,netdev=n0-nographic-serial file:/root/vmboot/console.log-monitor unix:/root/vmboot/mon.sock,server,nowait
必要なフラグが決まっています。1つでも抜けると、採点で引っかかります。バックグラウンド実行は、スクリプトの外で行ってください。
アクセラレーターの確認
使用可能なアクセラレーターの一覧と/dev/kvmの有無を、/root/vmboot/accel.txtに次の2行で書いてください。
ACCELS=<쉼표로 구분한 가속기 목록> / DEVKVM=<yes|no>(プレースホルダーは、カンマで区切ったアクセラレーターの一覧です)
qemu-system-x86_64には、使えるアクセラレーターを列挙するヘルプがあります。/dev/kvmの有無も一緒に記録してください。
実際に起動してコンソールログを残す
run.shをバックグラウンドで実行して20秒以上待ったあと、/root/vmboot/console.logにファームウェアのメッセージが残っているかを確認してください。ログにSeaBIOSまたはBootingという文字列がある必要があります。
シリアル出力をファイルに送るオプションがあります。ファームウェアのメッセージは起動直後に出るので、長く待つ必要はありません。
モニターソケットに問い合わせる
モニターソケットにinfo statusを送り、応答を/root/vmboot/monitor.txtに保存してください。応答にrunningまたはpausedが見える必要があります。
モニターをUNIXソケットで開き、ncの-Uでつなぎます。コマンドを標準入力に流し込めばよいです。
ポートフォワーディングの確認
12222ポートがリッスン中かを確認して、/root/vmboot/hostfwd.txtに保存してください。プロセスがqemuと見える必要があります。
hostfwdのリッスンソケットは、QEMUが起動した直後に開きます。ゲストの起動とは無関係です。
VM実行レポート
/root/vmboot/report.txtを次の5行で作成してください。
ACCEL=tcg / MEM=512 / VCPU=1 / FWD_PORT=12222 / DISK_IF=virtio
前のステップで確認した値を集めてください。アクセラレーターとフォワーディングのポートは、実際の値である必要があります。