2013/01/26

libvirtのKVMゲストプロセスを認識しやすくする

libvirt を使って複数の KVM ゲストを管理していると、どのプロセスがリソースを多く使用しているのか top コマンドでは分かりづらいときがあります。リソースの使用状況を確認したい場合は virt-manager や virsh 、virt-top など専用のコマンドを使えばいいのですが、もう少しカジュアルに知りたいです。

はじめに (追記)

ここで話題にしている libvirt のバージョンは 0.8.3 です。

# virsh version
Compiled against library: libvir 0.8.3
Using library: libvir 0.8.3
Using API: QEMU 0.8.3
Running hypervisor: QEMU 0.12.5
@nakamuray さんに教えていただきましたが、libvirt 0.8.5 以降では /etc/libvirt/qemu.conf でプロセス名を指定するパラメータ set_process_name が使えるようです。どのように見えるかは後述します。

KVMプロセスのコマンドラインは多くて長い

top コマンドの出力ではこのように kvm という同じ名前のプロセスが見えます。

# top -b -n 1 -u libvirt-qemu | tail -n +7
  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
26745 libvirt-  20   0 1255m 1.0g 4420 S   16  6.5   2:30.66 kvm
26704 libvirt-  20   0 12.3g 677m 4404 S    2  4.2   0:47.46 kvm
26780 libvirt-  20   0  622m 272m 4392 S    2  1.7   0:24.72 kvm
-c オプションを付ければコマンドラインが表示できますが、kvm(qemu)プロセスを起動する際のオプションは非常に多くて長く、そこから -name を見つけるのも一苦労です。(だいたい同じ位置に現れますが)
# top -b -n 1 -u libvirt-qemu -c | tail -n +7
  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
26745 libvirt-  20   0 1255m 1.0g 4420 S   16  6.5   2:37.32 /usr/bin/kvm -S -M pc-0.12 -enable-kvm -m 1024 -smp 1,sockets=1,cores=1,threads=1 -name Windows8 -uuid c4e94fe7-5d2a-0d03-515b-f56d8fdf8449 -nodefaults -chardev socket,id=monitor,path=/var/lib/libvirt/qemu/Windows8.monitor,server,nowait -mon chardev=monitor
26704 libvirt-  20   0 12.3g 677m 4404 S    4  4.2   0:48.52 /usr/bin/kvm -S -M pc-0.12 -enable-kvm -m 12288 -smp 2,sockets=2,cores=1,threads=1 -name FreeBSD -uuid 2933345f-dd30-9f9b-c396-047654d44a64 -nodefaults -chardev socket,id=monitor,path=/var/lib/libvirt/qemu/FreeBSD.monitor,server,nowait -mon chardev=monitor,
26780 libvirt-  20   0  622m 272m 4392 S    2  1.7   0:25.03 /usr/bin/kvm -S -M pc-0.12 -enable-kvm -m 386 -smp 1,sockets=1,cores=1,threads=1 -name CentOS -uuid ef35e149-fb57-6e77-6730-07ad39214e58 -nodefaults -chardev socket,id=monitor,path=/var/lib/libvirt/qemu/CentOS.monitor,server,nowait -mon chardev=monitor,mode

KVM起動スクリプトを修正する

先日、virt-manager 上のコンソールでキーボードが正常に使用できない時の対策として libvirt が起動する KVM プロセス用のラッパースクリプトを作成しました。

kvm(qemu) の -name オプションでは ,process= でプロセス名も指定できるようですので、これを使用するようスクリプトを修正しました。
# kvm --help | grep -A1 -- -name
-name string1[,process=string2]    set the name of the guest
            string1 sets the window title and string2 the process name (on Linux)
  • -name 引数を先頭にする
  • プロセス名に仮想マシンの名前を表示する

このスクリプトを使用すると top コマンドの出力はこのようになり、前より分かりやすくなりました。

# top -b -n 1 -u libvirt-qemu | tail -n +7
  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
27500 libvirt-  20   0 1255m 1.0g 4420 S   51  6.5   0:51.56 kvm:Windows8
27538 libvirt-  20   0 12.3g 668m 4404 R    4  4.2   0:30.26 kvm:FreeBSD
27574 libvirt-  20   0  622m 304m 4392 S    2  1.9   0:19.15 kvm:CentOS

よく分からないところ

これで要望は満たせたのですが、このスクリプトに渡される引数($@)は実際には次のようになっています。

-device pci-assign,?
top コマンドで見えるものとだいぶ違います。そして今回のスクリプトを通すと次のコマンドに置き換えられます。
exec /usr/bin/kvm -name -device pci-assign,?,process=kvm(-device pci-assign,?) -device pci-assign,? -device pci-assign,? -k en-us
これだけ見ると全くダメそうですが、最終的に実行されたプロセスのコマンドラインは次のようになっています。
# cat /proc/27500/cmdline | tr '\0' ' '; echo
/usr/bin/kvm -name Windows8,process=kvm:Windows8 -S -M pc-0.12 -enable-kvm -m 1024 -smp 1,sockets=1,cores=1,threads=1 -uuid c4e94fe7-5d2a-0d03-515b-f56d8fdf8449 -nodefaults -chardev socket,id=monitor,path=/var/lib/libvirt/qemu/Windows8.monitor,server,nowait -mon chardev=monitor,mode=readline -rtc base=localtime -boot dc -drive if=none,media=cdrom,id=drive-ide0-1-0,readonly=on,format=raw -device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0 -drive file=/var/lib/libvirt/images/Windows8.img,if=none,id=drive-virtio-disk0,boot=on,format=raw -device virtio-blk-pci,bus=pci.0,addr=0x6,drive=drive-virtio-disk0,id=virtio-disk0 -device virtio-net-pci,vlan=0,id=net0,mac=52:54:00:46:7a:e9,bus=pci.0,addr=0x7 -net tap,fd=39,vlan=0,name=hostnet0 -chardev pty,id=serial0 -device isa-serial,chardev=serial0 -usb -device usb-tablet,id=input0 -vnc 0.0.0.0:0 -vga std -device AC97,id=sound0,bus=pci.0,addr=0x4 -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x5 -k en-us
プロセスの生成と実行についての知識が乏しいのですが、おそらく libvirt がラッパースクリプトを通して生成したプロセスのコマンドラインをこの後の処理で置き換えて実行しているのだと思います。具体的にどのように行っているのかは、ソースを追う力量が無いので調べることはできませんでしたが、そのうち明らかにしたいなと思います。

libvirt 0.8.5 以降でset_process_nameを指定した場合(追記)

確認した環境は Debian GNU/Linux 7.0 (wheezy) の libvirt-bin 0.9.12-5 です。

root@wheezy:~# virsh version
Compiled against library: libvir 0.9.12
Using library: libvir 0.9.12
Using API: QEMU 0.9.12
Running hypervisor: QEMU 1.1.2
/etc/libvirt/qemu.conf の set_process_name の値はコメントアウトされているので外して有効にします。
# If enabled, libvirt will have QEMU set its process name to
# "qemu:VM_NAME", where VM_NAME is the name of the VM. The QEMU
# process will appear as "qemu:VM_NAME" in process listings and
# other system monitoring tools. By default, QEMU does not set
# its process title, so the complete QEMU command (emulator and
# its arguments) appear in process listings.
#
# set_process_name = 1
set_process_name = 1
COMMAND 列に表示される文字列は 15 文字のようなので仮想マシン名が長いと途中で切れてしまいますね。
root@wheezy:~# virsh list
 Id    Name                           State
----------------------------------------------------
 2     OracleLinux                    running
root@wheezy:~# top -b -n 1 -u libvirt-qemu | tail -n +7
  PID USER      PR  NI  VIRT  RES  SHR S  %CPU %MEM    TIME+  COMMAND
 9063 libvirt-  20   0 1286m 112m 6180 R  99.9  3.7   6:54.16 qemu:OracleLinu
root@wheezy:~# cat /proc/9063/cmdline | tr '\0' ' '; echo
/usr/bin/kvm -S -M pc-1.1 -enable-kvm -m 1024 -smp 1,sockets=1,cores=1,threads=1 -name OracleLinux,process=qemu:OracleLinux -uuid 90544e15-ce49-efd9-1cde-f0c3cfdb4d16 -nodefconfig -nodefaults -chardev socket,id=charmonitor,path=/var/lib/libvirt/qemu/OracleLinux.monitor,server,nowait -mon chardev=charmonitor,id=monitor,mode=control -rtc base=localtime -no-shutdown -device piix3-usb-uhci,id=usb,bus=pci.0,addr=0x1.0x2 -drive file=/var/lib/libvirt/images/NAS/OracleLinux.img,if=none,id=drive-virtio-disk0,format=raw -device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x5,drive=drive-virtio-disk0,id=virtio-disk0,bootindex=2 -drive if=none,id=drive-ide0-1-0,readonly=on,format=raw -device ide-cd,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0,bootindex=1 -netdev tap,fd=20,id=hostnet0 -device virtio-net-pci,netdev=hostnet0,id=net0,mac=52:54:00:00:c5:91,bus=pci.0,addr=0x3 -chardev pty,id=charserial0 -device isa-serial,chardev=charserial0,id=serial0 -device usb-tablet,id=input0 -vnc 127.0.0.1:0 -vga cirrus -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x6

おわりに

libvirt のような開発に勢いのあるソフトウェアはディストリビューションのパッケージだと欲しい機能が利用できない場合がありますが、今回は qemu にもともとある機能が libvirt 0.8.3 では呼び出せないのでラッパースクリプトで工夫したよということでした。手軽にカスタマイズできるシェルスクリプトっていいですよね。

0 件のコメント:

コメントを投稿