Ubuntu Weekly Recipe

第595回リモートデスクトップのためのSPICEクライアントあれこれ

SPICEは仮想マシン上のディスプレイと通信するためのプロトコルです。SPICEプロトコルに対応したクライアントをいくつか紹介しましょう。

SPICEを有効化した仮想マシンを起動する

SPICEは仮想マシン上のディスプレイ・入力デバイスとローカルマシン上のクライアントの中を取り持つプロトコルです。グラフィックデバイスとしてQXLを指定した仮想マシンを立ち上げることで、仮想マシン内部のグラフィックドライバーであるQXLドライバーとSPICEサーバーが連携し、SPICEクライントがネットワーク越しにSPICEサーバーと通信することで、リモートの仮想マシンの画面をクライアント側で表示できます[1]⁠。VMWareのvSphereクライアントにある、リモートの画面を表示する仕組みだと考えれば良いでしょう。

SPICEでは単に画面のやりとりだけでなく、⁠Virtual Device Interface(VDI⁠⁠」として実デバイス・仮想デバイス自身もネットワーク越しに操作できるプロトコルを定義しています。これによりリモートの仮想マシン上のオーディオをクライアント側で再生・録音したり、クライアント側にあるUSBデバイスを仮想マシン上で認識することも可能になります。

まずはSPICEに対応したQEMUインスタンスを構築しましょう。といってもQEMUコマンドに渡すオプションを変えるだけで、基本的な手順は第592回「QEMUでGPUの3Dアクセラレーションを利用する」と同じです。もちろんSPICEなしで構築した上で、あとからSPICEを有効化してもかまいません。よって第592回で構築したイメージを流用する方法もあります。

リモート側にQEMUを動かすための諸々をインストールしておきます。

$ sudo apt install qemu-system-x86 qemu-utils
$ sudo adduser $USER kvm

CPUの仮想化支援機構を使いたいなら、kvmグループに所属しておく必要があります。環境やインストールしたパッケージによっては最初から所属しているかもしれません。もしQEMUコマンド実行時に「権限がない」旨のエラーが出るようなら、上記のように明示的に所属したあとに、ログインしなおしてください。

新規にイメージを構築するなら、空のイメージファイルを作っておきましょう。

$ qemu-img create -f qcow2 ubuntu.qcow2 20G

UEFI対応のイメージにしたいなら、第441回「QEMU/KVMでUEFIファームウェアを使う」を参考に、OVMFもインストールしておきます。

$ sudo apt install ovmf
$ cp /usr/share/OVMF/OVMF_VARS.fd vars.fd

Ubuntuをインストールするなら、次のように実行します。

$ qemu-system-x86_64 \
    -enable-kvm -M q35 -smp 2 -m 4G \
    -drive format=qcow2,file=ubuntu.qcow2,if=virtio \
    -net nic,model=virtio \
    -net user,hostfwd=tcp::2222-:22 \
    -machine vmport=off \
    -vga qxl \
    -spice port=5900,disable-ticketing \
    -boot once=d -no-reboot -cdrom ubuntu-19.10-desktop-amd64.iso

UEFIに対応させるなら次のように実行します。

$ qemu-system-x86_64 \
    -enable-kvm -M q35 -smp 2 -m 4G \
    -drive if=pflash,format=raw,readonly,file=/usr/share/OVMF/OVMF_CODE.fd \
    -drive if=pflash,format=raw,file=vars.fd \
    -drive format=qcow2,file=ubuntu.qcow2,if=virtio \
    -net nic,model=virtio \
    -net user,hostfwd=tcp::2222-:22 \
    -machine vmport=off \
    -vga qxl \
    -spice port=5900,disable-ticketing \
    -boot once=d -no-reboot -cdrom ubuntu-19.10-desktop-amd64.iso

第592回と異なるのは次の4点です。

  • -machine vmport=offが追加された
  • -vga virtioの代わりに-vga qxlになった
  • -display gtk,grab-on-hover=on,gl=onがなくなった
  • -spice port=5900,disable-ticketingが追加された

最初のvmport=offはVMWareのI/Oポートのエミュレーションを無効化しています。SPICE上のマウス処理と相性が悪いようです。

QXLはSPICE用のグラフィックデバイスです。これとSPICEを組み合わせることで、高速なリモートデスクトップ環境を構築できます。

今回はリモートデスクトップを前提としているため、ローカルの仮想マシンウィンドウを立ち上げる-displayオプションは使っていません。

最後の-spiceオプションが今回のポイントです。port=5900でその仮想マシンのSPICEサーバーへの接続ポートを設定します。つまり複数のマシンを立ち上げるなら、それぞれ異なる値にします。addr=オプションを使うことで、bind()するアドレスを指定できます。何も指定しないとANYになるので、そのマシン上のすべてのインターフェース経由でアクセスできることになります。

disable-ticketingはこのあと紹介するSPICEクライントが接続する際に、⁠認証を行わない」よう設定しています。つまり仮想マシンが動いているサーバーの5900番ポートに接続できる人なら誰でもその仮想マシンの画面にアクセスできるという状態です。単純にパスワード認証したいのであればdisable-ticketingの代わりにpassword=パスワードを指定してください。X.509やSASLによる認証もサポートしています。

アドレスや認証関連はWAN経由でSPICEを使いたい場合に、特に必要になってきます。また経路をTLSで暗号化する方法も存在します。これらのオプションについてはqemu-systemのマニュアルを参照してください。

仮想マシンが立ち上がったので、あとはこれから紹介するクライアントで接続するだけです。ここからは仮想マシンのホストのアドレスが「vmserver.local」である前提で説明します。ポート番号とセットで「vmserver.local:5900」「SPICEアドレス」と呼ぶことにします。適宜、各自のホスト名やIPアドレス、ポート番号などに読み替えてください。

シンプルなGTKベースのクライアント「spice-client-gtk」

もっともシンプルなクライアントが、SPICEプロトコルの公式が作成しており、SPICEプロトコルのテストアプリケーションでもあるspice-client-gtkです。次のようにインストールできます。

$ sudo apt install spice-client-gtk

デスクトップファイルなどは作成しないので、起動するには端末から次のように実行します。

$ spicy --uri='spice://vmserver.local:5900'

--urlにSPICEアドレスを指定します。もしくは引数なしで起動した上で、メニューの「File」「Connect」からアドレスを指定する方法もあります。

図1 無事にリモートの画面が表示された
画像

マウスがウィンドウから抜けられなくなったり、間違ってフルスクリーンモードにした場合は、右Shift-F12で元に戻ります。ESCキーでは戻らないので注意してください。

ちなみに同梱のspicy-screenshotを使うと、現在表示している内容のスクリーンショットを取得できます。ただし、メインウィンドウは切断されますので、テストや記事の執筆用途だと思いましょう。

公式推奨の「virt-viewer」

SPICEの公式が推奨しているのが、virt-managerとセットでインストールされることの多いvirt-viewerです。virt-managerで仮想マシンを作成した場合は、基本的にvirt-viewerでゲストのディスプレイにアクセスすることになります。もちろんvirt-managerがなくても単体でvirt-viewerを利用可能です。

$ sudo apt install virt-viewer

アプリケーション一覧から「リモートビューアー」を選択するか、端末から次のコマンドを実行しましょう。

$ remote-viewer spice://vmserver.local:5900
図2 実はspice-client-gtkのほうができることは多い
画像

ちなみに第572回で紹介しているGNOME BoxesもSPICEクライアントとして利用できるようです。ローカルでlibvirtも利用する予定があるのなら、GNOME Boxesもセットでインストールすると、ローカルとリモートの両方の仮想マシンのデスクトップをBoxes経由で参照できます。Boxesでリモートデスクトップを使いたい場合、⁠新規」「URLを入力する」を選択し、URLに「spice://vmserver.local:5900」を入力し「続行」ボタンを押してください。最後に仮想環境を作成するかどうかを問い合わせられますので「作成」ボタンを押すと、リモートの仮想マシンに自動的に接続します。

Ubuntuデスクトップに最初から入っている「Remmina」

UbuntuデスクトップではリモートデスクトップクライアントとしてRemminaが最初からインストールされています。RemminaにはSPICEプラグインが存在するものの、Ubuntuにはインストールされていません。公式リポジトリにパッケージは存在するので、それをインストールしておきましょう。

$ sudo apt install remmina-plugin-spice

Remminaは端末から起動するより、アプリケーション一覧から「Remmina」を検索して起動したほうが便利です。

図3 プロトコルを「SPICE」に変更してアドレスを入力する
画像
図4 デスクトップクライアントとしてはおそらくもっとも高機能
画像

マウスとキーボードのイベントがRemminaの先の仮想マシンに奪われてしまった場合、右Ctrlキーを2回入力してください。SPICE固有の操作は、サイドバーのボタンの説明を読むとだいたいわかるかと思います。

ちなみに上記はUbuntu 19.10とYaruテーマでのスクリーンショットです。Ubuntu 18.04 LTSだともう少し野暮ったくなります。

ウェブブラウザーからアクセス可能な「spice-html5」

ちょっと変わったところとしては、ウェブ版クライアントとしてspice-html5が存在します。

websockifyを利用すると、WebSocket通信を通常のソケット通信に変換できます。つまりSPICEサーバーとのソケット通信をwebsockifyに任せることで、ウェブブラウザーからSPICEサーバーへの通信が可能になるというわけです[2]⁠。

websockifyはspice-html5パッケージの推奨パッケージとして指定されているので、標準設定だと一緒にwebsockifyもインストールされます。

$ sudo apt install spice-html5

SPICE 0.14以前において、spice-html5の使い方には2種類存在します。

  • 任意のウェブサーバーとwebosockifyを組み合わせて動かす方法
  • webosckifyをウェブサーバーとしても動かす方法

今回はよりお手軽な後者のみを説明します。まずはwebsockifyを使ってWebSocketサーバーを立ち上げましょう。

$ websockify --web /usr/share/spice-html5/ 5959 vmserver.local:5900

--webオプションを指定することで、指定したディレクトリをベースにウェブサーバーとして起動します。別途ウェブサーバーが存在するなら--webは不要ですが、ウェブサーバーから/usr/share/spice-html5にアクセスできるようにしておく必要があります。

「5959」はWebSocketサーバーのポートで、最後にターゲットサーバーとしてSPICEアドレスを指定します。

あとはウェブサーバーを立ち上げたアドレスの5959番ポートにウェブブラウザーからアクセスするだけです。

$ xdg-open http://localhost:5959/spice.html

あとは「Host」「Port」にWebSocketサーバーが動いているアドレスと、webosockifyに指定したポート番号を設定して、⁠Start」ボタンを押してください。

図5 すべてウェブブラウザーだけで完結するのが便利
画像

spice-html5の便利な点は、⁠ローカルマシンにSPICEクライアントが不要」な点です。リモートデスクトップを動かす以上、リモートアクセス可能なサーバーが存在します。つまりリモートサーバー上でQEMUだけでなく、spice-html5もセットで動かしてしまえば、クライアント側はウェブブラウザーさえあれば良いということになります。

Android版の「aSPICE」

Android版のSPICEクライアントとしてはbVNCやaRDPと同じ開発者が作っているaSPICEが存在します。ソースコードはbVNCやaRDPと共通化できるものは共通化しているようなので、ほぼ同じように使えるはずです。

図6 小さなスマートフォンでも画面の拡大・縮小ができるのでそれなりに使える
画像

PCを動かせない環境でどうしてもリモートにあるデスクトップ環境にアクセスしなくてはならない際に便利かもしれません。

ただしマウスをサーバーモードで動かさないと、何かクリックするたびにエラーダイアログが表示されます。次項の内容を参考に、spice-vdagentを有効化してください。

spice-vdagentを利用して高機能化

spice-vdagentを利用すると、SPICEプロトコルを経由して次のような機能が使えます。

  • クリップボードの共有
  • クライアントウィンドウサイズに基づいた画面解像度の自動変更
  • マウスカーソルがクライアントウィンドウに奪われないモードの有効化

spice-vdagentを利用するためにはゲスト側にspice-vdagentパッケージをインストールする必要があります。ただしUbuntuデスクトップなら最初からインストールされているので、特に対応する必要はありません。

もうひとつ必要なのが、仮想マシン側の設定の変更です。SPICEクライアントとゲストOS上のspice-vdagentが通信できるよう、QEMUコマンドに追加のオプションが必要になるのです。そこで仮想マシンを次のコマンドで起動し直しましょう。

$ qemu-system-x86_64 \
    -enable-kvm -M q35 -smp 2 -m 4G \
    -drive format=qcow2,file=ubuntu-bios.qcow2,if=virtio \
    -net nic,model=virtio \
    -net user,hostfwd=tcp::2222-:22 \
    -machine vmport=off \
    -vga qxl \
    -spice port=5900,disable-ticketing \
    -device virtio-serial -chardev spicevmc,id=vdagent,debug=0,name=vdagent \
    -device virtserialport,chardev=vdagent,name=com.redhat.spice.0

追加されたのは最後の2行です。virtio-serialデバイスを作っています。ゲストOS上のspice-vdagentはこのデバイスを経由して、外のプログラム(たとえばSPICEクライアント)と通信するのです。さらにspicevmcデバイスに接続するキャラクターデバイスを「vdagent」という名前で作成しています。vdagentのキャラクターデバイスは、ゲストから見るプロパティ名として「com.redhat.spice.0」を持っています。これによりゲスト上のspice-vdagentは、このデバイスがspice-vdagent用であることがわかるようになっているのです。

図7 spice-client-gtkだとウィンドウ左下でspice-vdagentが使えるかどうかを判別できる
画像

spice-vdagentが有効化されたので、たとえば任意の文字列をローカルからリモートに、リモートからローカルにコピー&ペーストできるか試してみましょう。

さらにローカルのNautilusから、SPICEクライアント上にドラッグ&ドロップするとリモートのダウンロードディレクトリーにコピーされるようです。

たとえばRemminaならウィンドウ左にある設定アイコンの「Resize guest to match window size」を、spice-client-gtkならメニューの「Option」にある同様のメニューを選択しておくと、クライアントのウィンドウに合わせて画面解像度を変更してくれます。

USBのリダイレクト機能

最後にUSBのリダイレクト機能を紹介しましょう。QEMUで仮想マシンを起動する際に、USB用のチャンネルを作成すると、SPICEクライアント経由で「クライアントのホストマシンにつながっているUSBデバイス」「ゲストOS上に接続したように見せる」ことが可能になります。

仮想マシン起動時のオプションがさらに長くなります。

$ qemu-system-x86_64 \
    -enable-kvm -M q35 -smp 2 -m 4G \
    -drive format=qcow2,file=ubuntu-bios.qcow2,if=virtio \
    -net nic,model=virtio \
    -net user,hostfwd=tcp::2222-:22 \
    -machine vmport=off \
    -vga qxl \
    -spice port=5900,disable-ticketing \
    -device virtio-serial -chardev spicevmc,id=vdagent,debug=0,name=vdagent \
    -device virtserialport,chardev=vdagent,name=com.redhat.spice.0 \
    -device nec-usb-xhci,id=usb \
    -chardev spicevmc,name=usbredir,id=usbredirchardev1 \
    -device usb-redir,chardev=usbredirchardev1,id=usbredirdev1 \
    -chardev spicevmc,name=usbredir,id=usbredirchardev2 \
    -device usb-redir,chardev=usbredirchardev2,id=usbredirdev2 \
    -chardev spicevmc,name=usbredir,id=usbredirchardev3 \
    -device usb-redir,chardev=usbredirchardev3,id=usbredirdev3

ここまでくるとQEMUコマンドよりは、素直にvirt-managerを使うほうがはるかに簡単です。ただ、一度はQEMUで起動しておくと、virt-managerの設定の際にどんなオプションを渡すべきかの勘所がわかりやすくなります。

追加されたのは最後の7行です。2行目以降は、2行ごとにUSBデバイス用ポートとなります。今回は3ポート作っているので、3個のUSBデバイスを接続可能というわけです。

たとえばRemminaだと、左のカスタマイズアイコンから「Select USB devices for redirection」を選択すると、どのUSBデバイスをリモート仮想マシンにリダイレクトするかを選択できます。

図8 このときポートを1個しか作らなかったため「1 free channel」と表示されている
画像

選べるのは「ホストで使われていないUSBデバイス」です。たとえばUSBメモリーなどは接続したら自動的にマウントされてしまい「使用中」の状態になってしまうため、リダイレクションしたければあらかじめアンマウントしておいてください。

デバイスを選択して「閉じる」ボタンを押すと、リモートの仮想マシン側でそのUSBデバイスを認識してくれるはずです。

図9 ローカルマシンのウェブカメラをリモートで使った例
画像

ネットワーク越しにUSBデバイスを使う以上、帯域や遅延にシビアなUSBデバイスは使いづらいですが、それらに目をつぶれば大抵のUSBデバイスはなんとか使えます。

おすすめ記事

記事・ニュース一覧