プログラミング
Vagrantからの卒業: DebianにおけるKVMとVirshを使ったVM
Ditching Vagrant: VMs with KVM and Virsh on Debian (benjamintoll.com)
要約
筆者は、長年利用してきた仮想マシン管理ツールVagrantから、DebianネイティブのKVMとlibvirt/virshへの移行を決断しました。Vagrantが自身のワークフローにとって過剰なソフトウェアであると感じたためです。記事では、KVM、libvirt、virshの概要と連携方法を解説し、Debianのアップグレード後に発生したシリアル出力の問題を解決するために、virt-installを用いたプリシードによるVM作成方法を紹介しています。
全文翻訳
Vagrantからの卒業
2026年6月29日
さようなら、古い友よ。私たちは2010年から共に旅をしてきたが、あなたはVirtualBox、そして後にlibvirtとKVMで、私の仮想マシンのニーズを忠実に満たしてくれた。しかし、すべて良いものには終わりがある、と言うように、その時が来た。何が起こったのか?何が変わったのか?
はじめに
KVMとlibvirtとvirsh
まずいぞ
プリシード
ネットワーク接続
マウント
SSHエージェントフォワーディング
要約
参考文献
はじめに
ここで何をしているのか?なぜ別れを選ぶのか?正直に言って、Vagrantは私のような個人にはあまりにも多くのソフトウェアだと感じている。この短い人生で学習を続け、ますます多くのことに触れるにつれて、以前はそれほど知らなかった頃の自分の選択を問い直し、再評価している。私は常に過去のプロジェクトや決定を見直しており、それがうまくいってきた。この場合、自分のワークフローが複雑になりすぎていることに気づいた。2010年にVagrantを使い始めたとき、VMのライフサイクルを管理してくれるだけで満足していた。Vagrantボックスはクールで時間を節約してくれたし、その後Ansibleを使い始めると、Vagrantの組み込みAnsibleサポートでマシンをプロビジョニングするようになった。しかし、Linuxについてますます学ぶにつれて、なぜVagrantではなくKVMを使わないのだろうかと思い始めた。結局、バージョン2.6.20以降、Linuxカーネルにマージされており、仮想マシンを作成・管理するために必要なツールはすでに持っているのだ。Linuxがネイティブにできることを、なぜ別のソフトウェアレイヤー、別の抽象化が必要なのだろうか?私は自分が弱虫だと感じ始めた。私は自分が臭い小さなクソ野郎だと感じ始めた。最悪なことに、自分が怠惰であることを悟った。だから、数年前に半ばの措置としてVirtualBoxプロバイダーからlibvirtプロバイダーに切り替え、その後も生活を続けた。結局、もっと重要なことがあった。例えば、当時の雇用主とその顧客のために、できる限り一生懸命働くことだ。なぜなら、それが重要で、最も重要なことで、あまりにも重要だったので、アジャイルとスクラムマスターのせいで、平日に直す時間がなかった急ごしらえのインフラを修正するために、連続して夜中の3時に起きなければならなかったからだ。そして、それは顧客に価値を提供しなかった。とにかく、この恥ずべき行動を数年続けた後、ついにKVMとlibvirtを掘り下げて正しく行うための時間を確保した。そう、子供たちよ、私はVagrantをアンインストールし、妻は再び私を愛し始めた。では、何をしたのか?さあ、火の周りに集まって、一緒に学ぼう。
KVMとlibvirtとvirsh
KVMは、カーネル仮想化モジュールを介して、Linuxカーネルがハイパーバイザーとして機能し、仮想マシン(VM)を作成・実行できるようにする。仮想化を通じて、ハードウェアはソフトウェアでエミュレートされるため、VMを作成することは、ホストオペレーティングシステム内に完全なオペレーティングシステムを持つようなものだ。クールじゃないか?その通りだ!カーネルモジュールはおそらく有効になっている。確認するには:
$ lsmod | ag kvm
kvm_intel 380928 0
kvm 1146880 1 kvm_intel
irqbypass 16384 1 kvm
または:
$ ls /dev/kvm
/dev/kvm
一方、libvirtは、KVMやXen、LXC、QEMUなどの他の仮想化プラットフォームを管理するライブラリとネットワークデーモン(「デーモン」と発音する)である。VMの作成、起動、停止、一時停止、削除など、ストレージやネットワーク管理といった他のことも可能にする。libvirtの素晴らしい点は、サポートするさまざまなプラットフォームと対話する際に、統一された共通のライブラリを提供してくれることだ。そのため、他のものを利用したり、異なるハイパーバイザーのために異なるコマンドや操作を学んだりする必要がない。つまり、仮想化バックエンドを切り替えても、同じコマンドでlibvirtを使い続けることができる。インストールするには:
$ sudo apt-get install libvirt-daemon-system
virshは、libvirtのコマンドラインフロントエンドである(libvirtはvirt-managerのような他のフロントエンドもサポートしているが、それはGUIであり、CLIツールがあるときにGUIを使う人はいないと誰もが知っている)。libvirtデーモンと対話するための優れた抽象化レイヤーを提供し、libvirtデーモンはKVMと対話する。インストールするには:
$ sudo apt-get install libvirt-clients virtinst
これにより、virt-installもインストールされる。
仮想マシン(ドメイン)に関する情報を取得するための便利なvirshコマンドをいくつか紹介する:
domblkinfo
domblkstat
domid
domiflist
domifstat
dominfo
dommemstat
domname
domstate
domuuid
ホストやノードに関する情報を取得するには:
capabilities
hostname
nodeinfo
そして、便利な管理コマンド:
connect
destroy
dumpxml
edit
list
reboot
shutdown
start
undefine
ここにリストするにはあまりにも多くのコマンドがある。virshのドキュメントを参照してほしい。ここでも、概念モデルはユーザー -> virsh -> libvirt -> KVM である。これらのトピックのそれぞれについて、さらに理解すべきことはたくさんあるが、これで始められるはずだ。このトピックに関連する素晴らしい記事をいくつか紹介する:
仮想マシンについて
名前空間の共有解除について、パート1
名前空間の共有解除について、パート2
Linuxコンテナネットワーキングについて
まずいぞ
私はlibvirtとKVMを使って仮想マシンを楽しく作成していた。何の心配もなかった。ところが突然、私の世界は完全に崩壊した。bookwormからtrixieにアップグレードしたところ、VMを起動してもシリアル出力が得られなくなったのだ。VMとホスト間のシリアルポート経由の通信を有効にするために、virt-installコマンド(後述)で通常通りカーネルブートパラメータを渡していたが、それがVMに実際にパラメータを書き込んでいない(つまり、ブートローダー設定に)ように見えたのだ。grub(または使用している他のブートローダー)に実際に書き込まれたパラメータを確認するには、仮想マシンにログインしてgrub設定を開く:
/etc/default/grub
重要な行は次のようになるはずだ:
GRUB_CMDLINE_LINUX_DEFAULT="quiet"
GRUB_CMDLINE_LINUX="console=ttyS0,115200"
何かを変更した場合は、次のコマンドを実行する:
$ sudo grub-mkconfig -o /boot/grub/grub.cfg
$ sudo reboot
考えてみた結果、この問題には別の方法でアプローチすることにした。デバッグに(おそらく長時間)費やす代わりに、インストールコマンドに設定ファイルを渡して、プリシード仮想マシンとして知られるものを作成することにした。これは全体的により良い解決策だ。なぜなら、ビルドを決定論的でバージョン管理可能にし(ビルドマシンからアクセス可能な場所に置く)、ファイルで指定した値が仮想マシンに書き込まれることを確実にできるからだ。さらに、すべてのマシンに共通して持つべきソフトウェアをプリインストールでき、後でcloud-initのようなものを使用して、VM作成ライフサイクルにフックして、各マシン固有の追加ソフトウェアを追加できる。いいね!それでは、それを見てみよう。
プリシード
では、プリシードとは何か?前の発言から推測されたかもしれないが、プリシードは、ローカライゼーション、ユーザー名とパスワード、インストールパッケージなど、インストール中に尋ねられる質問にあらかじめ決められた回答を提供することで、仮想マシンの作成を自動化する方法だ。おなじみの手順、つまり何千回も実行したことのあるものだ。プリシードという言葉は主にDebianビルドの文脈で使われているのを見たことがあるが、他のオペレーティングシステムにも同様の方法がある。Debian trixieは、独自のベースとして使用できる例のプリコンフィギュレーションファイルを提供している。Automating the installation using preseeding という素晴らしい記事で、さらに詳しい情報を得ることができる。これは非常に推奨される読み物だ。
これはすべて素晴らしいように聞こえ、あなたはきっと驚嘆し、今すぐ始めたいと思っているだろう。そこで、前述の小さな友であるvirt-installが登場する:
$ virt-install \
--connect qemu:///system \
--name kilgore-trout \
--memory 8192 \
--extra-args="preseed/file=/preseed.cfg console=ttyS0,115200n8" \
--initrd-inject ./preseed.cfg \
--install debian13 \
--disk size=40 \
--filesystem type=mount,source=/home/btoll/libvirt/kilgore-trout/mnt,target=shared,accessmode=mapped,driver.type=path,driver.wrpolicy=immediate \
--network net